+ /* Set U and G to nonzero length strings corresponding to user and
+ group specifiers or to NULL. If U is not NULL, it is a newly
+ allocated string. */
+
+ u = NULL;
+ if (separator == NULL)
+ {
+ if (*spec)
+ u = xstrdup (spec);
+ }
+ else
+ {
+ size_t ulen = separator - spec;
+ if (ulen != 0)
+ {
+ u = xmemdup (spec, ulen + 1);
+ u[ulen] = '\0';
+ }
+ }
+
+ g = (separator == NULL || *(separator + 1) == '\0'
+ ? NULL
+ : separator + 1);
+
+#ifdef __DJGPP__
+ /* Pretend that we are the user U whose group is G. This makes
+ pwd and grp functions "know" about the UID and GID of these. */
+ if (u && !is_number (u))
+ setenv ("USER", u, 1);
+ if (g && !is_number (g))
+ setenv ("GROUP", g, 1);
+#endif
+
+ if (u != NULL)
+ {
+ /* If it starts with "+", skip the look-up. */
+ pwd = (*u == '+' ? NULL : getpwnam (u));
+ if (pwd == NULL)
+ {
+ bool use_login_group = (separator != NULL && g == NULL);
+ if (use_login_group)
+ {
+ /* If there is no group,
+ then there may not be a trailing ":", either. */
+ error_msg = E_bad_spec;
+ }
+ else
+ {
+ unsigned long int tmp;
+ if (xstrtoul (u, NULL, 10, &tmp, "") == LONGINT_OK
+ && tmp <= MAXUID && (uid_t) tmp != (uid_t) -1)
+ unum = tmp;
+ else
+ error_msg = E_invalid_user;
+ }
+ }
+ else
+ {
+ unum = pwd->pw_uid;
+ if (g == NULL && separator != NULL)
+ {
+ /* A separator was given, but a group was not specified,
+ so get the login group. */
+ char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ gnum = pwd->pw_gid;
+ grp = getgrgid (gnum);
+ gname = xstrdup (grp ? grp->gr_name : umaxtostr (gnum, buf));
+ endgrent ();
+ }
+ }
+ endpwent ();
+ }
+
+ if (g != NULL && error_msg == NULL)
+ {
+ /* Explicit group. */
+ /* If it starts with "+", skip the look-up. */
+ grp = (*g == '+' ? NULL : getgrnam (g));
+ if (grp == NULL)
+ {
+ unsigned long int tmp;
+ if (xstrtoul (g, NULL, 10, &tmp, "") == LONGINT_OK
+ && tmp <= MAXGID && (gid_t) tmp != (gid_t) -1)
+ gnum = tmp;
+ else
+ error_msg = E_invalid_group;
+ }
+ else
+ gnum = grp->gr_gid;
+ endgrent (); /* Save a file descriptor. */
+ gname = xstrdup (g);
+ }
+
+ if (error_msg == NULL)
+ {
+ *uid = unum;
+ if (gid)
+ *gid = gnum;
+ if (username)
+ {
+ *username = u;
+ u = NULL;
+ }
+ if (groupname)
+ {
+ *groupname = gname;
+ gname = NULL;
+ }
+ }
+
+ free (u);
+ free (gname);
+ return _(error_msg);
+}
+
+/* Extract from SPEC, which has the form "[user][:.][group]",