obstack.m4 (gl_PREREQ_OBSTACK): Require
[gnulib.git] / lib / userspec.c
index 9def456..6bf4089 100644 (file)
@@ -1,5 +1,6 @@
 /* userspec.c -- Parse a user and group string.
-   Copyright (C) 1989-1992, 1997, 1998, 2000, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1989-1992, 1997-1998, 2000, 2002-2004 Free Software
+   Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 # include <config.h>
 #endif
 
-#ifdef __GNUC__
-# define alloca __builtin_alloca
-#else
-# if HAVE_ALLOCA_H
-#  include <alloca.h>
-# else
-#  ifdef _AIX
- #  pragma alloca
-#  else
-char *alloca ();
-#  endif
-# endif
-#endif
+/* Specification.  */
+#include "userspec.h"
+
+#include <alloca.h>
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <sys/types.h>
 #include <pwd.h>
@@ -44,27 +37,16 @@ char *alloca ();
 # include <sys/param.h>
 #endif
 
-#if HAVE_LIMITS_H
-# include <limits.h>
-#endif
-
-#if HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-# ifndef strchr
-#  define strchr index
-# endif
-#endif
-
-#if STDC_HEADERS
-# include <stdlib.h>
-#endif
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
 
 #if HAVE_UNISTD_H
 # include <unistd.h>
 #endif
 
+#include "inttostr.h"
+#include "strdup.h"
 #include "xalloc.h"
 #include "xstrtol.h"
 
@@ -86,10 +68,6 @@ struct group *getgrgid ();
 # define endpwent() ((void) 0)
 #endif
 
-#ifndef CHAR_BIT
-# define CHAR_BIT 8
-#endif
-
 /* The extra casts work around common compiler bugs.  */
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
 /* The outer cast is needed to work around a bug in Cray C 5.0.3.0.
@@ -120,9 +98,9 @@ struct group *getgrgid ();
 #define V_STRDUP(dest, src)                                            \
   do                                                                   \
     {                                                                  \
-      int _len = strlen ((src));                                       \
-      (dest) = (char *) alloca (_len + 1);                             \
-      strcpy (dest, src);                                              \
+      size_t size = strlen (src) + 1;                                  \
+      (dest) = (char *) alloca (size);                                 \
+      memcpy (dest, src, size);                                                \
     }                                                                  \
   while (0)
 
@@ -133,23 +111,25 @@ struct group *getgrgid ();
    POSIX says that only '0' through '9' are digits.  Prefer ISDIGIT to
    ISDIGIT_LOCALE unless it's important to use the locale's definition
    of `digit' even when the host does not conform to POSIX.  */
-#define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
+#define ISDIGIT(c) ((unsigned int) (c) - '0' <= 9)
 
-#ifndef strdup
-char *strdup ();
-#endif
+#ifdef __DJGPP__
 
-/* Return nonzero if STR represents an unsigned decimal integer,
-   otherwise return 0. */
+/* Return true if STR represents an unsigned decimal integer.  */
 
-static int
+static bool
 is_number (const char *str)
 {
-  for (; *str; str++)
-    if (!ISDIGIT (*str))
-      return 0;
-  return 1;
+  do
+    {
+      if (!ISDIGIT (*str))
+       return false;
+    }
+  while (*++str);
+
+  return true;
 }
+#endif
 
 /* Extract from NAME, which has the form "[user][:.][group]",
    a USERNAME, UID U, GROUPNAME, and GID G.
@@ -184,7 +164,6 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
   struct group *grp;
   char *g, *u, *separator;
   char *groupname;
-  int maybe_retry = 0;
   char *dot = NULL;
 
   error_msg = NULL;
@@ -203,11 +182,8 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
       /* If there's no colon but there is a `.', then first look up the
         whole spec, in case it's an OWNER name that includes a dot.
         If that fails, then we'll try again, but interpreting the `.'
-        as a separator.  */
-      /* FIXME: accepting `.' as the separator is contrary to POSIX.
-        someday we should drop support for this.  */
-      if (dot)
-       maybe_retry = 1;
+        as a separator.  This is a compatible extension to POSIX, since
+        the POSIX-required behavior is always tried first.  */
     }
 
  retry:
@@ -241,23 +217,16 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
       pwd = getpwnam (u);
       if (pwd == NULL)
        {
-
-         if (!is_number (u))
-           error_msg = E_invalid_user;
+         bool use_login_group = (separator != NULL && g == NULL);
+         if (use_login_group)
+           error_msg = E_bad_spec;
          else
            {
-             int use_login_group;
-             use_login_group = (separator != NULL && g == NULL);
-             if (use_login_group)
-               error_msg = E_bad_spec;
-             else
-               {
-                 unsigned long int tmp_long;
-                 if (xstrtoul (u, NULL, 0, &tmp_long, NULL) != LONGINT_OK
-                     || tmp_long > MAXUID)
-                   return _(E_invalid_user);
-                 *uid = tmp_long;
-               }
+             unsigned long int tmp_long;
+             if (! (xstrtoul (u, NULL, 10, &tmp_long, "") == LONGINT_OK
+                    && tmp_long <= MAXUID))
+               return _(E_invalid_user);
+             *uid = tmp_long;
            }
        }
       else
@@ -271,12 +240,9 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
              grp = getgrgid (pwd->pw_gid);
              if (grp == NULL)
                {
-                 /* This is enough room to hold the unsigned decimal
-                    representation of any 32-bit quantity and the trailing
-                    zero byte.  */
-                 char uint_buf[21];
-                 sprintf (uint_buf, "%u", (unsigned) (pwd->pw_gid));
-                 V_STRDUP (groupname, uint_buf);
+                 char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+                 char const *num = umaxtostr (pwd->pw_gid, buf);
+                 V_STRDUP (groupname, num);
                }
              else
                {
@@ -294,16 +260,11 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
       grp = getgrnam (g);
       if (grp == NULL)
        {
-         if (!is_number (g))
-           error_msg = E_invalid_group;
-         else
-           {
-             unsigned long int tmp_long;
-             if (xstrtoul (g, NULL, 0, &tmp_long, NULL) != LONGINT_OK
-                 || tmp_long > MAXGID)
-               return _(E_invalid_group);
-             *gid = tmp_long;
-           }
+         unsigned long int tmp_long;
+         if (! (xstrtoul (g, NULL, 10, &tmp_long, "") == LONGINT_OK
+                && tmp_long <= MAXGID))
+           return _(E_invalid_group);
+         *gid = tmp_long;
        }
       else
        *gid = grp->gr_gid;
@@ -316,31 +277,16 @@ parse_user_spec (const char *spec_arg, uid_t *uid, gid_t *gid,
   if (error_msg == NULL)
     {
       if (u != NULL)
-       {
-         *username_arg = strdup (u);
-         if (*username_arg == NULL)
-           error_msg = xalloc_msg_memory_exhausted;
-       }
+       *username_arg = xstrdup (u);
 
-      if (groupname != NULL && error_msg == NULL)
-       {
-         *groupname_arg = strdup (groupname);
-         if (*groupname_arg == NULL)
-           {
-             if (*username_arg != NULL)
-               {
-                 free (*username_arg);
-                 *username_arg = NULL;
-               }
-             error_msg = xalloc_msg_memory_exhausted;
-           }
-       }
+      if (groupname != NULL)
+       *groupname_arg = xstrdup (groupname);
     }
 
-  if (error_msg && maybe_retry)
+  if (error_msg && dot)
     {
-      maybe_retry = 0;
       separator = dot;
+      dot = NULL;
       error_msg = NULL;
       goto retry;
     }
@@ -368,10 +314,10 @@ main (int argc, char **argv)
       tmp = strdup (argv[i]);
       e = parse_user_spec (tmp, &uid, &gid, &username, &groupname);
       free (tmp);
-      printf ("%s: %u %u %s %s %s\n",
+      printf ("%s: %lu %lu %s %s %s\n",
              argv[i],
-             (unsigned int) uid,
-             (unsigned int) gid,
+             (unsigned long int) uid,
+             (unsigned long int) gid,
              NULL_CHECK (username),
              NULL_CHECK (groupname),
              NULL_CHECK (e));