Several cleanups from Manuel Novoa III.
authorEric Andersen <andersen@codepoet.org>
Wed, 14 Feb 2001 07:15:30 +0000 (07:15 -0000)
committerEric Andersen <andersen@codepoet.org>
Wed, 14 Feb 2001 07:15:30 +0000 (07:15 -0000)
get_kernel_revision --  size reduction
        NOTE: may want to combine with get_kernel_version in insmod???

parse_mode -- size reduction, multiple settings with "," now work correctly,
        sticky-bit setting now implemented

process_escape_sequence -- size reduction, octal code to big for char bug fixed

format -- size reduction, val > LONG_MAX and hr = 1 printing bug fixed (was %ld),

busybox.h
include/busybox.h
utility.c

index 2fc0cc7..101e659 100644 (file)
--- a/busybox.h
+++ b/busybox.h
@@ -232,7 +232,7 @@ extern int sysinfo (struct sysinfo* info);
 #endif
 
 #ifdef BB_FEATURE_HUMAN_READABLE
-char *format(unsigned long val, unsigned long hr);
+const char *format(unsigned long val, unsigned long hr);
 #define KILOBYTE 1024
 #define MEGABYTE (KILOBYTE*1024)
 #define GIGABYTE (MEGABYTE*1024)
index 2fc0cc7..101e659 100644 (file)
@@ -232,7 +232,7 @@ extern int sysinfo (struct sysinfo* info);
 #endif
 
 #ifdef BB_FEATURE_HUMAN_READABLE
-char *format(unsigned long val, unsigned long hr);
+const char *format(unsigned long val, unsigned long hr);
 #define KILOBYTE 1024
 #define MEGABYTE (KILOBYTE*1024)
 #define GIGABYTE (MEGABYTE*1024)
index 9f0bca9..f3c184e 100644 (file)
--- a/utility.c
+++ b/utility.c
@@ -51,6 +51,7 @@
 #include <unistd.h>
 #include <ctype.h>
 #include <stdlib.h>
+#include <limits.h>
 #include <sys/ioctl.h>
 #include <sys/utsname.h>               /* for uname(2) */
 
@@ -77,7 +78,7 @@ const char mtab_file[] = "/proc/mounts";
 
 extern void usage(const char *usage)
 {
-       fprintf(stderr, "%s\n\nUsage: %s\n", full_version, usage);
+       fprintf(stderr, "%s\n\nUsage: %s\n\n", full_version, usage);
        exit(EXIT_FAILURE);
 }
 
@@ -145,16 +146,21 @@ extern void perror_msg_and_die(const char *s, ...)
 extern int get_kernel_revision(void)
 {
        struct utsname name;
-       int major = 0, minor = 0, patch = 0;
+       char *s;
+       int i, r;
 
        if (uname(&name) == -1) {
                perror_msg("cannot get system information");
                return (0);
        }
-       major = atoi(strtok(name.release, "."));
-       minor = atoi(strtok(NULL, "."));
-       patch = atoi(strtok(NULL, "."));
-       return major * 65536 + minor * 256 + patch;
+
+       s = name.release;
+       r = 0;
+       for (i=0 ; i<3 ; i++) {
+               r = r * 256 + atoi(strtok(s, "."));
+               s = NULL;
+       }
+       return r;
 }
 #endif                                                 /* BB_INIT */
 
@@ -749,102 +755,100 @@ extern int create_path(const char *name, int mode)
  || defined (BB_MKFIFO) || defined (BB_MKNOD) || defined (BB_AR)
 /* [ugoa]{+|-|=}[rwxst] */
 
-
-
 extern int parse_mode(const char *s, mode_t * theMode)
 {
-       mode_t andMode =
+       static const mode_t group_set[] = { 
+               S_ISUID | S_IRWXU,              /* u */
+               S_ISGID | S_IRWXG,              /* g */
+               S_IRWXO,                                /* o */
+               S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO /* a */
+       };
+
+       static const mode_t mode_set[] = {
+               S_IRUSR | S_IRGRP | S_IROTH, /* r */
+               S_IWUSR | S_IWGRP | S_IWOTH, /* w */
+               S_IXUSR | S_IXGRP | S_IXOTH, /* x */
+               S_ISUID | S_ISGID,              /* s */
+               S_ISVTX                                 /* t */
+       };
+
+       static const char group_string[] = "ugoa";
+       static const char mode_string[] = "rwxst";
+
+       const char *p;
 
+       mode_t andMode =
                S_ISVTX | S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
        mode_t orMode = 0;
-       mode_t mode = 0;
-       mode_t groups = 0;
+       mode_t mode;
+       mode_t groups;
        char type;
        char c;
 
-       if (s==NULL)
+       if (s==NULL) {
                return (FALSE);
+       }
 
        do {
-               for (;;) {
-                       switch (c = *s++) {
-                       case '\0':
-                               return -1;
-                       case 'u':
-                               groups |= S_ISUID | S_IRWXU;
-                               continue;
-                       case 'g':
-                               groups |= S_ISGID | S_IRWXG;
-                               continue;
-                       case 'o':
-                               groups |= S_IRWXO;
-                               continue;
-                       case 'a':
-                               groups |= S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
-                               continue;
-                       case '+':
+               mode = 0;
+               groups = 0;
+       NEXT_GROUP:
+               if ((c = *s++) == '\0') {
+                       return -1;
+               }
+               for (p=group_string ; *p ; p++) {
+                       if (*p == c) {
+                               groups |= group_set[(int)(p-group_string)];
+                               goto NEXT_GROUP;
+                       }
+               }
+               switch (c) {
                        case '=':
+                       case '+':
                        case '-':
                                type = c;
-                               if (groups == 0)        /* The default is "all" */
-                                       groups |=
-                                               S_ISUID | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO;
+                               if (groups == 0) { /* The default is "all" */
+                                       groups |= S_ISUID | S_ISGID | S_ISVTX
+                                                       | S_IRWXU | S_IRWXG | S_IRWXO;
+                               }
                                break;
                        default:
-                               if (isdigit(c) && c >= '0' && c <= '7' &&
-                                       mode == 0 && groups == 0) {
+                               if ((c < '0') || (c > '7') || (mode | groups)) {
+                                       return (FALSE);
+                               } else {
                                        *theMode = strtol(--s, NULL, 8);
                                        return (TRUE);
-                               } else
-                                       return (FALSE);
-                       }
-                       break;
+                               }
                }
 
-               while ((c = *s++) != '\0') {
-                       switch (c) {
-                       case ',':
-                               break;
-                       case 'r':
-                               mode |= S_IRUSR | S_IRGRP | S_IROTH;
-                               continue;
-                       case 'w':
-                               mode |= S_IWUSR | S_IWGRP | S_IWOTH;
-                               continue;
-                       case 'x':
-                               mode |= S_IXUSR | S_IXGRP | S_IXOTH;
-                               continue;
-                       case 's':
-                               mode |= S_IXGRP | S_ISUID | S_ISGID;
-                               continue;
-                       case 't':
-                               mode |= 0;
-                               continue;
-                       default:
-                               *theMode &= andMode;
-                               *theMode |= orMode;
-                               return (TRUE);
+       NEXT_MODE:
+               if (((c = *s++) != '\0') && (c != ',')) {
+                       for (p=mode_string ; *p ; p++) {
+                               if (*p == c) {
+                                       mode |= mode_set[(int)(p-mode_string)];
+                                       goto NEXT_MODE;
+                               }
                        }
-                       break;
+                       break;                          /* We're done so break out of loop.*/
                }
                switch (type) {
-               case '=':
-                       andMode &= ~(groups);
-                       /* fall through */
-               case '+':
-                       orMode |= mode & groups;
-                       break;
-               case '-':
-                       andMode &= ~(mode & groups);
-                       orMode &= andMode;
-                       break;
+                       case '=':
+                               andMode &= ~(groups); /* Now fall through. */
+                       case '+':
+                               orMode |= mode & groups;
+                               break;
+                       case '-':
+                               andMode &= ~(mode & groups);
+                               orMode &= ~(mode & groups);
+                               break;
                }
        } while (c == ',');
+
        *theMode &= andMode;
        *theMode |= orMode;
-       return (TRUE);
-}
 
+       return TRUE;
+}
 
 #endif
 /* BB_CHMOD_CHOWN_CHGRP || BB_MKDIR || BB_MKFIFO || BB_MKNOD */
@@ -1575,48 +1579,43 @@ extern int print_file_by_name(char *filename)
 #if defined BB_ECHO || defined BB_SH || defined BB_TR
 char process_escape_sequence(char **ptr)
 {
-       char c;
-
-       switch (c = *(*ptr)++) {
-       case 'a':
-               c = '\a';
-               break;
-       case 'b':
-               c = '\b';
-               break;
-       case 'f':
-               c = '\f';
-               break;
-       case 'n':
-               c = '\n';
-               break;
-       case 'r':
-               c = '\r';
-               break;
-       case 't':
-               c = '\t';
-               break;
-       case 'v':
-               c = '\v';
-               break;
-       case '\\':
-               c = '\\';
-               break;
-       case '0': case '1': case '2': case '3':
-       case '4': case '5': case '6': case '7':
-               c -= '0';
-               if ('0' <= **ptr && **ptr <= '7') {
-                       c = c * 8 + (*(*ptr)++ - '0');
-                       if ('0' <= **ptr && **ptr <= '7')
-                               c = c * 8 + (*(*ptr)++ - '0');
-               }
-               break;
-       default:
-               (*ptr)--;
-               c = '\\';
-               break;
-       }
-       return c;
+       static const char charmap[] = {
+                  'a',  'b',  'f',  'n',  'r',  't',  'v',  '\\', 0,
+              '\a', '\b', '\f', '\n', '\r', '\t', '\v', '\\', '\\' };
+
+       const char *p;
+          char *q;
+       int num_digits;
+       unsigned int n;
+
+       n = 0;
+          q = *ptr;
+
+       for ( num_digits = 0 ; num_digits < 3 ; ++num_digits) {
+              if ((*q < '0') || (*q > '7')) { /* not a digit? */
+                      break;
+              }
+              n = n * 8 + (*q++ - '0');
+       }
+
+       if (num_digits == 0) {  /* mnemonic escape sequence? */
+                  for (p=charmap ; *p ; p++) {
+                          if (*p == *q) {
+                                  q++;
+                                  break;
+                          }
+                  }
+                  n = *(p+(sizeof(charmap)/2));
+          }
+
+          /* doesn't hurt to fall through to here from mnemonic case */
+          if (n > UCHAR_MAX) { /* is octal code too big for a char? */
+                  n /= 8;                      /* adjust value and */
+                  --q;                         /* back up one char */
+          }
+
+          *ptr = q;
+          return (char) n;
 }
 #endif
 
@@ -1737,23 +1736,45 @@ ssize_t safe_read(int fd, void *buf, size_t count)
 #endif
 
 #ifdef BB_FEATURE_HUMAN_READABLE
-char *format(unsigned long val, unsigned long hr)
+const char *format(unsigned long val, unsigned long hr)
 {
-       static char str[10] = "\0";
-
-       if(val == 0)
-               return("0");
-       if(hr)
-               snprintf(str, 9, "%ld", val/hr);
-       else if(val >= GIGABYTE)
-               snprintf(str, 9, "%.1LfG", ((long double)(val)/GIGABYTE));
-       else if(val >= MEGABYTE)
-               snprintf(str, 9, "%.1LfM", ((long double)(val)/MEGABYTE));
-       else if(val >= KILOBYTE)
-               snprintf(str, 9, "%.1Lfk", ((long double)(val)/KILOBYTE));
-       else
-               snprintf(str, 9, "%ld", (val));
-       return(str);
+       static const char strings[] = { '0', 0, 'k', 0, 'M', 0, 'G', 0 };
+       static const char fmt[] = "%lu";
+       static const char fmt_u[] = "%lu.%lu%s";
+
+       static char str[10];
+
+       unsigned long frac __attribute__ ((unused));    /* 'may be uninitialized' warning is ok */
+       const char *u;
+       const char *f;
+
+#if 1
+       if(val == 0) {                          /* This may be omitted to reduce size */
+               return strings;                 /* at the cost of speed. */
+       }
+#endif
+
+       u = strings;
+       f = fmt;
+       if (hr) {
+               val /= hr;
+       } else {
+               while ((val >= KILOBYTE) && (*u != 'G')) {
+                       f = fmt_u;
+                       u += 2;
+                       frac = (((val % KILOBYTE) * 10) + (KILOBYTE/2)) / KILOBYTE;
+                       val /= KILOBYTE;
+                       if (frac >= 10) {       /* We need to round up here. */
+                               ++val;
+                               frac = 0;
+                       }
+               }
+       }
+
+       /* If f==fmt then 'frac' and 'u' are ignored and need not be set. */
+       snprintf(str, sizeof(str), f, val, frac, u);
+
+       return str;
 }
 #endif