#define _POSIX_C_SOURCE 200112L #include #include #include #include #include #include #include "zpm.h" /* * a generic printf style format string parser * takes a character pointer, returns pointer to next non * parsed character, next token, optionally * does a callback, fills in a format struct */ #if 0 char *fmt; struct format f; while (*fmt) { fmt = parse_format_str(fmt, &f); if (!f.found) break; /* done */ if (!f.flags) { /* literal/noformat */ putchar(f.found); /* or whatever */ continue; } switch (f.found) { case 'a': /* handle %a */ break; default: /* handle unknown formatting character */ break; } } #endif struct format_string { int found; /* the 'd' in '%d' */ unsigned flags; /* 1 = found, 0 = none found */ }; char *format_string_parse(char *s, struct format_string *f) { f->found = 0; f->flags = 0; if (!*s) return s; /* done */ /* literal non-format specifier */ if (*s != '%') { f->found = *s++; return s; } s++; f->flags = 1; f->found = *s++; return s; } void stat_one(char *fmt, char *timefmt, char *filename, struct stat *buf) { struct tm *tm; char timestr[1024]; struct format_string f; struct passwd *pw; struct group *gr; while (*fmt) { fmt = format_string_parse(fmt, &f); if (!f.found) break; /* done */ if (!f.flags) { /* literal/noformat */ putchar(f.found); /* or whatever */ continue; } switch (f.found) { case 'y': /* handle mtime */ tm = gmtime(&buf->st_mtime); strftime(timestr, 1023, timefmt, tm); timestr[1023] = 0; printf("%s", timestr); break; case 's': printf("%jd", (intmax_t)buf->st_size); break; case 'a': /* octal mode */ printf("%o", (int)buf->st_mode & 07777); break; case 't': if (S_ISBLK(buf->st_mode)) { printf("block"); } else if (S_ISCHR(buf->st_mode)) { printf("character"); } else if (S_ISDIR(buf->st_mode)) { printf("directory"); } else if (S_ISFIFO(buf->st_mode)) { printf("fifo"); } else if (S_ISREG(buf->st_mode)) { printf("regular"); } else if (S_ISLNK(buf->st_mode)) { printf("symlink"); } else if (S_ISSOCK(buf->st_mode)) { printf("socket"); } else { printf("unknown"); } break; case 'u': /* handle uid */ printf("%0d", buf->st_uid); break; case 'U': /* handle username */ pw = getpwuid(buf->st_uid); if (!pw) exit(1); printf("%s", pw->pw_name); break; case 'g': /* handle gid */ printf("%0d", buf->st_gid); break; case 'G': /* handle groupname */ gr = getgrgid(buf->st_gid); if (!gr) exit(1); printf("%s", gr->gr_name); break; case 'n': printf("%s", filename); break; case '%': putchar('%'); break; default: /* handle unknown formatting character */ printf("%c", f.found); break; } } putchar('\n'); } int main(int ac, char *av[]) { char *fmt = "%y"; /* default stat is mtime */ char *timefmt = "%s"; /* default time fmt is unix ts */ int errflg = 0; int c; int uselstat = 0; while ((c = getopt(ac, av, "lf:t:")) != -1) { switch(c) { case 'f': fmt = optarg; break; case 't': timefmt = optarg; break; case ':': /* -f or -t without operand */ fprintf(stderr, "Option -%c requires an operand\n", optopt); errflg++; break; case 'l': uselstat = 1; break; case '?': fprintf(stderr, "Unrecognized option: '-%c'\n", optopt); errflg++; } } if (errflg) { fprintf(stderr, "zpm-stat [-f ] [-t ]\n"); exit(2); } for ( ; optind < ac; optind++) { struct stat buf; if (uselstat) { lstat(av[optind], &buf); } else { stat(av[optind], &buf); } stat_one(fmt, timefmt, av[optind], &buf); } return 0; }