changeset 916:b92cb3cc9696

Stat cleanup. lib: rename format_mode() to mode_to_string() (echoing string_to_mode), make it take a normal char * argument. stat: collapse big switch/case statements that only have one line each into if/else staircase (much fewer lines of code). Remove return type (other stat implementations print ? for unknown escapes, so do that here). Inline do_stat() and do_statfs(). Set default string in normal local variable "format". Remove unnecessary struct d. Restructure stat logic to "if (flagf && !statfs()) else if (!flagf && !stat()) else perror_msg();" Teach %N to add -> symlink. Judicious use of putchar() instead of xputc to let FILE * do its job collating output.
author Rob Landley <rob@landley.net>
date Sun, 02 Jun 2013 00:24:24 -0500
parents 463a7b796e61
children b2697351ce6d
files lib/lib.c lib/lib.h toys/pending/stat.c toys/posix/ls.c
diffstat 4 files changed, 91 insertions(+), 181 deletions(-) [+]
line wrap: on
line diff
--- a/lib/lib.c	Sat Jun 01 22:36:48 2013 -0500
+++ b/lib/lib.c	Sun Jun 02 00:24:24 2013 -0500
@@ -1205,13 +1205,13 @@
   error_exit("bad mode '%s'", modestr);
 }
 
-// Format a mode for ls and stat
-void format_mode(char (*buf)[11], mode_t mode)
+// Format access mode into a drwxrwxrwx string
+void mode_to_string(mode_t mode, char *buf)
 {
   char c, d;
   int i, bit;
 
-  (*buf)[10]=0;
+  buf[10]=0;
   for (i=0; i<9; i++) {
     bit = mode & (1<<i);
     c = i%3;
@@ -1219,7 +1219,7 @@
       c = "tss"[d];
       if (!bit) c &= ~0x20;
     } else c = bit ? "xwr"[c] : '-';
-    (*buf)[9-i] = c;
+    buf[9-i] = c;
   }
 
   if (S_ISDIR(mode)) c = 'd';
@@ -1229,7 +1229,7 @@
   else if (S_ISFIFO(mode)) c = 'p';
   else if (S_ISSOCK(mode)) c = 's';
   else c = '-';
-  **buf = c;
+  *buf = c;
 }
 
 char* make_human_readable(unsigned long long size, unsigned long unit)
--- a/lib/lib.h	Sat Jun 01 22:36:48 2013 -0500
+++ b/lib/lib.h	Sun Jun 02 00:24:24 2013 -0500
@@ -180,7 +180,7 @@
 char *num_to_sig(int sig);
 
 mode_t string_to_mode(char *mode_str, mode_t base);
-void format_mode(char (*buf)[11], mode_t mode);
+void mode_to_string(mode_t mode, char *buf);
 
 // password helper functions
 int read_password(char * buff, int buflen, char* mesg);
--- a/toys/pending/stat.c	Sat Jun 01 22:36:48 2013 -0500
+++ b/toys/pending/stat.c	Sun Jun 02 00:24:24 2013 -0500
@@ -44,7 +44,7 @@
   } stat;
   struct passwd *user_name;
   struct group *group_name;
-  char *ftname, access_str[11];
+  char *ftname;
 )
 
 
@@ -59,198 +59,108 @@
   xprintf("%s.%09d", toybuf, ts->tv_nsec);
 }
 
-static int print_stat(char type)
+static void print_stat(char type)
 {
   struct stat *stat = (struct stat *)&TT.stat;
 
-  switch (type) {
-    case 'a':
-      xprintf("%04lo", stat->st_mode & ~S_IFMT);
-      break;
-    case 'A':
-      xprintf("%s", TT.access_str);
-      break;
+  if (type == 'a') xprintf("%04lo", stat->st_mode & ~S_IFMT);
+  else if (type == 'A') {
+    char str[11];
 
-    case 'b':
-      xprintf("%llu", stat->st_blocks);
-      break;
-
-    case 'B':
-      xprintf("%lu", stat->st_blksize);
-      break;
-    case 'd':
-      xprintf("%ldd", stat->st_dev);
-      break;
-    case 'D':
-      xprintf("%llxh", stat->st_dev);
-      break;
-    case 'f':
-      xprintf("%lx", stat->st_mode);
-      break;
-    case 'F':
-      xprintf("%s", TT.ftname);
-      break;
-    case 'g':
-      xprintf("%lu", stat->st_gid);
-      break;
-    case 'G':
-      xprintf("%8s", TT.user_name->pw_name);
-      break;
-    case 'h':
-      xprintf("%lu", stat->st_nlink);
-      break;
-    case 'i':
-      xprintf("%llu", stat->st_ino);
-      break;
-    case 'N':
-      xprintf("`%s'", *toys.optargs);
-      break;
-    case 'o':
-      xprintf("%lu", stat->st_blksize);
-      break;
-    case 's':
-      xprintf("%llu", stat->st_size);
-      break;
-    case 'u':
-      xprintf("%lu", stat->st_uid);
-      break;
-    case 'U':
-      xprintf("%8s", TT.user_name->pw_name);
-      break;
-
-    case 'x':
-      date_stat_format((void *)&stat->st_atime);
-      break;
-    case 'X':
-      xprintf("%llu", (long long)stat->st_atime);
-      break;
-    case 'y':
-      date_stat_format((void *)&stat->st_mtime);
-      break;
-    case 'Y':
-      xprintf("%llu", (long long)stat->st_mtime);
-      break;
-    case 'z':
-      date_stat_format((void *)&stat->st_ctime);
-      break;
-    case 'Z':
-      xprintf("%llu", (long long)stat->st_ctime);
-      break;
-
-    default:
-      return 1;
-  }
-  return 0;
+    mode_to_string(stat->st_mode, str);
+    xprintf("%s", str);
+  } else if (type == 'b') xprintf("%llu", stat->st_blocks);
+  else if (type == 'B') xprintf("%lu", stat->st_blksize);
+  else if (type == 'd') xprintf("%ldd", stat->st_dev);
+  else if (type == 'D') xprintf("%llxh", stat->st_dev);
+  else if (type == 'f') xprintf("%lx", stat->st_mode);
+  else if (type == 'F') xprintf("%s", TT.ftname);
+  else if (type == 'g') xprintf("%lu", stat->st_gid);
+  else if (type == 'G') xprintf("%8s", TT.user_name->pw_name);
+  else if (type == 'h') xprintf("%lu", stat->st_nlink);
+  else if (type == 'i') xprintf("%llu", stat->st_ino);
+  else if (type == 'N') {
+    xprintf("`%s'", *toys.optargs);
+    if (S_ISLNK(stat->st_mode))
+      if (0<readlink(*toys.optargs, toybuf, sizeof(toybuf)))
+        xprintf(" -> `%s'", toybuf);
+  } else if (type == 'o') xprintf("%lu", stat->st_blksize);
+  else if (type == 's') xprintf("%llu", stat->st_size);
+  else if (type == 'u') xprintf("%lu", stat->st_uid);
+  else if (type == 'U') xprintf("%8s", TT.user_name->pw_name);
+  else if (type == 'x') date_stat_format((void *)&stat->st_atime);
+  else if (type == 'X') xprintf("%llu", (long long)stat->st_atime);
+  else if (type == 'y') date_stat_format((void *)&stat->st_mtime);
+  else if (type == 'Y') xprintf("%llu", (long long)stat->st_mtime);
+  else if (type == 'z') date_stat_format((void *)&stat->st_ctime);
+  else if (type == 'Z') xprintf("%llu", (long long)stat->st_ctime);
+  else xprintf("?");
 }
 
-static int print_statfs(char type) {
+static void print_statfs(char type) {
   struct statfs *statfs = (struct statfs *)&TT.stat;
 
-  switch (type) {
-    case 'a':
-      xprintf("%lu", statfs->f_bavail);
-      break;
-    case 'b':
-      xprintf("%lu", statfs->f_blocks);
-      break;
-    case 'c':
-      xprintf("%lu", statfs->f_files);
-      break;
-    case 'd':
-      xprintf("%lu", statfs->f_ffree);
-      break;
-    case 'f':
-      xprintf("%lu", statfs->f_bfree);
-      break;
-    case 'i':
-      xprintf("%x%x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
-      break;
-    case 'l':
-      xprintf("%ld", statfs->f_namelen);
-      break;
-    case 's':
-      xprintf("%d", statfs->f_frsize);
-      break;
-    case 'S':
-      xprintf("%d", statfs->f_bsize);
-      break;
-    case 't':
-      xprintf("%lx", statfs->f_type);
-      break;
-    default:
-      return 1;
-  }
-  return 0;
-}
-
-static int do_stat(char *path)
-{
-  struct stat *statf = (struct stat*)&TT.stat;
-  char *types = "character device\0directory\0block device\0" \
-               "regular file\0symbolic link\0socket\0FIFO (named pipe)";
-  int i, filetype;
-
-  if (stat(path, statf) < 0) return 1;
-
-  filetype = statf->st_mode & S_IFMT;
-  TT.ftname = types;
-  for (i = 1; filetype != (i*8192) && i < 7; i++)
-    TT.ftname += strlen(TT.ftname)+1;
-  if (!statf->st_size && filetype == S_IFREG)
-    TT.ftname = "regular empty file";
-
-  // check user and group name
-  TT.user_name = getpwuid(statf->st_uid);
-  TT.group_name = getgrgid(statf->st_gid);
-  // function to get access in human readable format
-  format_mode(&TT.access_str, statf->st_mode);
-
-  return 0;
-}
-
-static int do_statfs(char *path)
-{
-  return statfs(path, (void *)&TT.stat) < 0;
+  if (type == 'a') xprintf("%lu", statfs->f_bavail);
+  else if (type == 'b') xprintf("%lu", statfs->f_blocks);
+  else if (type == 'c') xprintf("%lu", statfs->f_files);
+  else if (type == 'd') xprintf("%lu", statfs->f_ffree);
+  else if (type == 'f') xprintf("%lu", statfs->f_bfree);
+  else if (type == 'l') xprintf("%ld", statfs->f_namelen);
+  else if (type == 't') xprintf("%lx", statfs->f_type);
+  else if (type == 'i')
+    xprintf("%x%x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
+  else if (type == 's') xprintf("%d", statfs->f_frsize);
+  else if (type == 'S') xprintf("%d", statfs->f_bsize);
+  else xprintf("?");
 }
 
 void stat_main(void)
 {
-  struct {
-    char *fmt;
-    int (*do_it)(char*);
-    int (*print_it)(char);
-  } d, ds[2] = {
-    {"  File: %N\n"
-     "  Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n"
-     "Device: %D\t Inode: %i\t Links: %h\n"
-     "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n"
-     "Access: %x\nModify: %y\nChange: %z",
-     do_stat, print_stat},
-    {"  File: \"%n\"\n"
-     "    ID: %i Namelen: %l    Type: %t\n"
-     "Block Size: %s    Fundamental block size: %S\n"
-     "Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
-     "Inodes: Total: %c\tFree: %d",
-     do_statfs, print_statfs}
-  };
+  int flagf = toys.optflags & FLAG_f;
+  char *format = flagf
+    ? "  File: \"%n\"\n    ID: %i Namelen: %l    Type: %t\n"
+      "Block Size: %s    Fundamental block size: %S\n"
+      "Blocks: Total: %b\tFree: %f\tAvailable: %a\n"
+      "Inodes: Total: %c\tFree: %d"
+    : "  File: %N\n  Size: %s\t Blocks: %b\t IO Blocks: %B\t%F\n"
+      "Device: %D\t Inode: %i\t Links: %h\n"
+      "Access: (%a/%A)\tUid: (%u/%U)\tGid: (%g/%G)\n"
+      "Access: %x\nModify: %y\nChange: %z";
 
-  d = ds[toys.optflags & FLAG_f];
-  if (toys.optflags & FLAG_c) d.fmt = TT.fmt;
+  if (toys.optflags & FLAG_c) format = TT.fmt;
 
   for (; *toys.optargs; toys.optargs++) {
-    char *format = d.fmt;
-    if (d.do_it(*toys.optargs)) {
+    char *f;
+
+    if (flagf && !statfs(*toys.optargs, (void *)&TT.stat));
+    else if (!flagf && !lstat(*toys.optargs, (void *)&TT.stat)) {
+      struct stat *stat = (struct stat*)&TT.stat;
+      char *types = "character device\0directory\0block device\0" \
+                   "regular file\0symbolic link\0socket\0FIFO (named pipe)";
+      int i, filetype;
+
+      filetype = stat->st_mode & S_IFMT;
+      TT.ftname = types;
+      for (i = 1; filetype != (i*8192) && i < 7; i++)
+        TT.ftname += strlen(TT.ftname)+1;
+      if (!stat->st_size && filetype == S_IFREG)
+        TT.ftname = "regular empty file";
+
+      // check user and group name
+      TT.user_name = getpwuid(stat->st_uid);
+      TT.group_name = getgrgid(stat->st_gid);
+    } else {
       perror_msg("'%s'", *toys.optargs);
       continue;
     }
-    for (; *format; format++) {
-      if (*format != '%') {
-        xputc(*format);
-        continue;
+
+    for (f = format; *f; f++) {
+      if (*f != '%') putchar(*f);
+      else {
+        if (*++f == 'n') xprintf("%s", *toys.optargs);
+        else if (flagf) print_statfs(*f);
+        else print_stat(*f);
       }
-      format++;
-      if (*format == 'n') xprintf("%s", *toys.optargs);
-      else if (d.print_it(*format)) xputc(*format);
     }
     xputc('\n');
   }
--- a/toys/posix/ls.c	Sat Jun 01 22:36:48 2013 -0500
+++ b/toys/posix/ls.c	Sun Jun 02 00:24:24 2013 -0500
@@ -337,7 +337,7 @@
       struct tm *tm;
       char perm[11], thyme[64], *usr, *upad, *grp, *grpad;
 
-      format_mode(&perm, mode);
+      mode_to_string(mode, perm);
 
       tm = localtime(&(st->st_mtime));
       strftime(thyme, sizeof(thyme), "%F %H:%M", tm);