diff options
author | Rob Landley <rob@landley.net> | 2012-11-13 17:14:08 -0600 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2012-11-13 17:14:08 -0600 |
commit | 7aa651a6a4496d848f86de9b1e6b3a003256a01f (patch) | |
tree | 6995fb4b7cc2e90a6706b0239ebaf95d9dbab530 /toys/posix | |
parent | 571b0706cce45716126776d0ad0f6ac65f4586e3 (diff) | |
download | toybox-7aa651a6a4496d848f86de9b1e6b3a003256a01f.tar.gz |
Reindent to two spaces per level. Remove vi: directives that haven't worked right in years (ubuntu broke its' vim implementation). Remove trailing spaces. Add/remove blank lines. Re-wordwrap in places. Update documentation with new coding style.
The actual code should be the same afterward, this is just cosmetic refactoring.
Diffstat (limited to 'toys/posix')
45 files changed, 3533 insertions, 3582 deletions
diff --git a/toys/posix/basename.c b/toys/posix/basename.c index 9f228b41..75f3baa4 100644 --- a/toys/posix/basename.c +++ b/toys/posix/basename.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * basename.c - Return non-directory portion of a pathname +/* basename.c - Return non-directory portion of a pathname * * Copyright 2012 Tryn Mirell <tryn@mirell.org> * @@ -10,36 +8,36 @@ USE_BASENAME(NEWTOY(basename, "<1>2", TOYFLAG_USR|TOYFLAG_BIN)) config BASENAME - bool "basename" - default y - help - usage: basename string [suffix] + bool "basename" + default y + help + usage: basename string [suffix] - Return non-directory portion of a pathname removing suffix + Return non-directory portion of a pathname removing suffix */ #include "toys.h" void basename_main(void) { - char *arg = toys.optargs[0], *suffix = toys.optargs[1], *base; - - while ((base = strrchr(arg, '/'))) { - if (base == arg) break; - if (!base[1]) *base = 0; - else { - base++; - break; - } + char *arg = toys.optargs[0], *suffix = toys.optargs[1], *base; + + while ((base = strrchr(arg, '/'))) { + if (base == arg) break; + if (!base[1]) *base = 0; + else { + base++; + break; } + } - if (!base) base = arg; - - // chop off the suffix if provided - if (suffix) { - arg = base + strlen(base) - strlen(suffix); - if (arg > base && !strcmp(arg, suffix)) *arg = 0; - } - - puts(base); + if (!base) base = arg; + + // chop off the suffix if provided + if (suffix) { + arg = base + strlen(base) - strlen(suffix); + if (arg > base && !strcmp(arg, suffix)) *arg = 0; + } + + puts(base); } diff --git a/toys/posix/cal.c b/toys/posix/cal.c index 1c018e2f..e4301a64 100644 --- a/toys/posix/cal.c +++ b/toys/posix/cal.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * cal.c - show calendar. +/* cal.c - show calendar. * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,14 +7,14 @@ USE_CAL(NEWTOY(cal, ">2", TOYFLAG_USR|TOYFLAG_BIN)) config CAL - bool "cal" - default y - help - usage: cal [[month] year] - Print a calendar. - - With one argument, prints all months of the specified year. - With two arguments, prints calendar for month and year. + bool "cal" + default y + help + usage: cal [[month] year] + Print a calendar. + + With one argument, prints all months of the specified year. + With two arguments, prints calendar for month and year. */ #include "toys.h" @@ -26,51 +24,51 @@ config CAL static char *calstrings(char *buf, struct tm *tm) { - char temp[21]; - int wday, mday, start, len, line; - - // header - len = strftime(temp, 21, "%B %Y", tm); - len += (20-len)/2; - buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, ""); - buf++; - buf += sprintf(buf, "Su Mo Tu We Th Fr Sa "); - buf++; - - // What day of the week does this month start on? - if (tm->tm_mday>1) - start = (36+tm->tm_wday-tm->tm_mday)%7; - else start = tm->tm_wday; - - // What day does this month end on? Alas, libc doesn't tell us... - len = 31; - if (tm->tm_mon == 1) { - int year = tm->tm_year; - len = 28; - if (!(year & 3) && !((year&100) && !(year&400))) len++; - } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30; - - for (mday=line=0;line<6;line++) { - for (wday=0; wday<7; wday++) { - char *pat = " "; - if (!mday ? wday==start : mday<len) { - pat = "%2d "; - mday++; - } - buf += sprintf(buf, pat, mday); - } - buf++; - } - - return buf; + char temp[21]; + int wday, mday, start, len, line; + + // header + len = strftime(temp, 21, "%B %Y", tm); + len += (20-len)/2; + buf += sprintf(buf, "%*s%*s ", len, temp, 20-len, ""); + buf++; + buf += sprintf(buf, "Su Mo Tu We Th Fr Sa "); + buf++; + + // What day of the week does this month start on? + if (tm->tm_mday>1) + start = (36+tm->tm_wday-tm->tm_mday)%7; + else start = tm->tm_wday; + + // What day does this month end on? Alas, libc doesn't tell us... + len = 31; + if (tm->tm_mon == 1) { + int year = tm->tm_year; + len = 28; + if (!(year & 3) && !((year&100) && !(year&400))) len++; + } else if ((tm->tm_mon+(tm->tm_mon>6 ? 1 : 0)) & 1) len = 30; + + for (mday=line=0;line<6;line++) { + for (wday=0; wday<7; wday++) { + char *pat = " "; + if (!mday ? wday==start : mday<len) { + pat = "%2d "; + mday++; + } + buf += sprintf(buf, pat, mday); + } + buf++; + } + + return buf; } void xcheckrange(long val, long low, long high) { - char *err = "%ld %s than %ld"; + char *err = "%ld %s than %ld"; - if (val < low) error_exit(err, val, "less", low); - if (val > high) error_exit(err, val, "greater", high); + if (val < low) error_exit(err, val, "less", low); + if (val > high) error_exit(err, val, "greater", high); } // Worst case scenario toybuf usage: sizeof(struct tm) plus 21 bytes/line @@ -78,57 +76,57 @@ void xcheckrange(long val, long low, long high) void cal_main(void) { - struct tm *tm; - char *buf = toybuf; - - if (toys.optc) { - // Conveniently starts zeroed - tm = (struct tm *)toybuf; - buf += sizeof(struct tm); - - // Last argument is year, one before that (if any) is month. - xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999); - tm->tm_year -= 1900; - tm->tm_mday = 1; - tm->tm_hour = 12; // noon to avoid timezone weirdness - if (toys.optc) { - xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12); - tm->tm_mon--; - - // Print 12 months of the year - - } else { - char *bufs[12]; - int i, j, k; - - for (i=0; i<12; i++) { - tm->tm_mon=i; - mktime(tm); - buf = calstrings(bufs[i]=buf, tm); - } - - // 4 rows, 6 lines each, 3 columns - for (i=0; i<4; i++) { - for (j=0; j<8; j++) { - for(k=0; k<3; k++) { - char **b = bufs+(k+i*3); - *b += printf("%s ", *b); - } - puts(""); - } - } - return; - } - - // What day of the week does that start on? - mktime(tm); - - } else { - time_t now; - time(&now); - tm = localtime(&now); - } - - calstrings(buf, tm); - while (*buf) buf += printf("%s\n", buf); + struct tm *tm; + char *buf = toybuf; + + if (toys.optc) { + // Conveniently starts zeroed + tm = (struct tm *)toybuf; + buf += sizeof(struct tm); + + // Last argument is year, one before that (if any) is month. + xcheckrange(tm->tm_year = atol(toys.optargs[--toys.optc]),1,9999); + tm->tm_year -= 1900; + tm->tm_mday = 1; + tm->tm_hour = 12; // noon to avoid timezone weirdness + if (toys.optc) { + xcheckrange(tm->tm_mon = atol(toys.optargs[--toys.optc]),1,12); + tm->tm_mon--; + + // Print 12 months of the year + + } else { + char *bufs[12]; + int i, j, k; + + for (i=0; i<12; i++) { + tm->tm_mon=i; + mktime(tm); + buf = calstrings(bufs[i]=buf, tm); + } + + // 4 rows, 6 lines each, 3 columns + for (i=0; i<4; i++) { + for (j=0; j<8; j++) { + for(k=0; k<3; k++) { + char **b = bufs+(k+i*3); + *b += printf("%s ", *b); + } + puts(""); + } + } + return; + } + + // What day of the week does that start on? + mktime(tm); + + } else { + time_t now; + time(&now); + tm = localtime(&now); + } + + calstrings(buf, tm); + while (*buf) buf += printf("%s\n", buf); } diff --git a/toys/posix/cat.c b/toys/posix/cat.c index 160bd6ff..431c7751 100644 --- a/toys/posix/cat.c +++ b/toys/posix/cat.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * cat.c - copy inputs to stdout. +/* cat.c - copy inputs to stdout. * * Copyright 2006 Rob Landley <rob@landley.net> * @@ -9,34 +7,34 @@ USE_CAT(NEWTOY(cat, "u", TOYFLAG_BIN)) config CAT - bool "cat" - default y - help - usage: cat [-u] [file...] - Copy (concatenate) files to stdout. If no files listed, copy from stdin. - Filename "-" is a synonym for stdin. + bool "cat" + default y + help + usage: cat [-u] [file...] + Copy (concatenate) files to stdout. If no files listed, copy from stdin. + Filename "-" is a synonym for stdin. - -u Copy one byte at a time (slow). + -u Copy one byte at a time (slow). */ #include "toys.h" static void do_cat(int fd, char *name) { - int len, size=toys.optflags ? 1 : sizeof(toybuf); + int len, size=toys.optflags ? 1 : sizeof(toybuf); - for (;;) { - len = read(fd, toybuf, size); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - xwrite(1, toybuf, len); - } + for (;;) { + len = read(fd, toybuf, size); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + xwrite(1, toybuf, len); + } } void cat_main(void) { - loopfiles(toys.optargs, do_cat); + loopfiles(toys.optargs, do_cat); } diff --git a/toys/posix/chgrp.c b/toys/posix/chgrp.c index 48ce6751..ed2ff9b2 100644 --- a/toys/posix/chgrp.c +++ b/toys/posix/chgrp.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * chown.c - Change ownership +/* chgrp.c - Change user and group ownership * * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> * @@ -13,103 +11,103 @@ USE_CHGRP(NEWTOY(chgrp, "<2hPLHRfv", TOYFLAG_BIN)) USE_CHGRP(OLDTOY(chown, chgrp, "<2hPLHRfv", TOYFLAG_BIN)) config CHGRP - bool "chgrp/chown" - default y - help - usage: chown [-RHLP] [-fvh] [owner][:group] file... - usage: chgrp [-RHLP] [-fvh] group file... - - Change ownership of one or more files. - - -f suppress most error messages. - -h change symlinks instead of what they point to - -R recurse into subdirectories (implies -h). - -H with -R change target of symlink, follow command line symlinks - -L with -R change target of symlink, follow all symlinks - -P with -R change symlink, do not follow symlinks (default) - -v verbose output. + bool "chgrp/chown" + default y + help + usage: chown [-RHLP] [-fvh] [owner][:group] file... + usage: chgrp [-RHLP] [-fvh] group file... + + Change ownership of one or more files. + + -f suppress most error messages. + -h change symlinks instead of what they point to + -R recurse into subdirectories (implies -h). + -H with -R change target of symlink, follow command line symlinks + -L with -R change target of symlink, follow all symlinks + -P with -R change symlink, do not follow symlinks (default) + -v verbose output. */ #define FOR_chgrp #include "toys.h" GLOBALS( - uid_t owner; - gid_t group; - char *owner_name, *group_name; - int symfollow; + uid_t owner; + gid_t group; + char *owner_name, *group_name; + int symfollow; ) static int do_chgrp(struct dirtree *node) { - int fd, ret, flags = toys.optflags; - - // Depth first search - if (!dirtree_notdotdot(node)) return 0; - if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) - return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); - - fd = dirtree_parentfd(node); - ret = fchownat(fd, node->name, TT.owner, TT.group, - (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) - ? 0 : AT_SYMLINK_NOFOLLOW); - - if (ret || (flags & FLAG_v)) { - char *path = dirtree_path(node, 0); - if (flags & FLAG_v) - xprintf("%s %s%s%s %s\n", toys.which->name, - TT.owner_name ? TT.owner_name : "", - toys.which->name[2]=='o' && TT.group_name ? ":" : "", - TT.group_name ? TT.group_name : "", path); - if (ret == -1 && !(toys.optflags & FLAG_f)) - perror_msg("changing owner:group of '%s' to '%s:%s'", path, - TT.owner_name, TT.group_name); - free(path); - } - toys.exitval |= ret; - - return 0; + int fd, ret, flags = toys.optflags; + + // Depth first search + if (!dirtree_notdotdot(node)) return 0; + if ((flags & FLAG_R) && node->data != -1 && S_ISDIR(node->st.st_mode)) + return DIRTREE_COMEAGAIN|((flags&FLAG_L) ? DIRTREE_SYMFOLLOW : 0); + + fd = dirtree_parentfd(node); + ret = fchownat(fd, node->name, TT.owner, TT.group, + (flags&(FLAG_L|FLAG_H)) || !(flags&(FLAG_h|FLAG_R)) + ? 0 : AT_SYMLINK_NOFOLLOW); + + if (ret || (flags & FLAG_v)) { + char *path = dirtree_path(node, 0); + if (flags & FLAG_v) + xprintf("%s %s%s%s %s\n", toys.which->name, + TT.owner_name ? TT.owner_name : "", + toys.which->name[2]=='o' && TT.group_name ? ":" : "", + TT.group_name ? TT.group_name : "", path); + if (ret == -1 && !(toys.optflags & FLAG_f)) + perror_msg("changing owner:group of '%s' to '%s:%s'", path, + TT.owner_name, TT.group_name); + free(path); + } + toys.exitval |= ret; + + return 0; } void chgrp_main(void) { - int ischown = toys.which->name[2] == 'o'; - char **s, *own; - - // Distinguish chown from chgrp - if (ischown) { - char *grp; - struct passwd *p; - - own = xstrdup(*toys.optargs); - if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) { - *(grp++) = 0; - TT.group_name = grp; - } - if (*own) { - TT.owner_name = own; - p = getpwnam(own); - // TODO: trailing garbage? - if (!p && isdigit(*own)) p=getpwuid(atoi(own)); - if (!p) error_exit("no user '%s'", own); - TT.owner = p->pw_uid; - } - } else TT.group_name = *toys.optargs; - - if (TT.group_name) { - struct group *g; - g = getgrnam(TT.group_name); - if (!g) g=getgrgid(atoi(TT.group_name)); - if (!g) error_exit("no group '%s'", TT.group_name); - TT.group = g->gr_gid; - } - - for (s=toys.optargs+1; *s; s++) { - struct dirtree *new = dirtree_add_node(AT_FDCWD, *s, - toys.optflags&(FLAG_H|FLAG_L)); - if (new) handle_callback(new, do_chgrp); - else toys.exitval = 1; - } - - if (CFG_TOYBOX_FREE) free(own); + int ischown = toys.which->name[2] == 'o'; + char **s, *own; + + // Distinguish chown from chgrp + if (ischown) { + char *grp; + struct passwd *p; + + own = xstrdup(*toys.optargs); + if ((grp = strchr(own, ':')) || (grp = strchr(own, '.'))) { + *(grp++) = 0; + TT.group_name = grp; + } + if (*own) { + TT.owner_name = own; + p = getpwnam(own); + // TODO: trailing garbage? + if (!p && isdigit(*own)) p=getpwuid(atoi(own)); + if (!p) error_exit("no user '%s'", own); + TT.owner = p->pw_uid; + } + } else TT.group_name = *toys.optargs; + + if (TT.group_name) { + struct group *g; + g = getgrnam(TT.group_name); + if (!g) g=getgrgid(atoi(TT.group_name)); + if (!g) error_exit("no group '%s'", TT.group_name); + TT.group = g->gr_gid; + } + + for (s=toys.optargs+1; *s; s++) { + struct dirtree *new = dirtree_add_node(AT_FDCWD, *s, + toys.optflags&(FLAG_H|FLAG_L)); + if (new) handle_callback(new, do_chgrp); + else toys.exitval = 1; + } + + if (CFG_TOYBOX_FREE) free(own); } diff --git a/toys/posix/chmod.c b/toys/posix/chmod.c index dcef9751..89b6e083 100644 --- a/toys/posix/chmod.c +++ b/toys/posix/chmod.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * chmod.c - Change file mode bits +/* chmod.c - Change file mode bits * * Copyright 2012 Rob Landley <rob@landley.net> * @@ -9,59 +7,59 @@ USE_CHMOD(NEWTOY(chmod, "<2?vR", TOYFLAG_BIN)) config CHMOD - bool "chmod" - default y - help - usage: chmod [-R] MODE FILE... + bool "chmod" + default y + help + usage: chmod [-R] MODE FILE... - Change mode of listed file[s] (recursively with -R). + Change mode of listed file[s] (recursively with -R). - MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo] + MODE can be (comma-separated) stanzas: [ugoa][+-=][rwxstXugo] - Stanzas are applied in order: For each category (u = user, - g = group, o = other, a = all three, if none specified default is a), - set (+), clear (-), or copy (=), r = read, w = write, x = execute. - s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s). - suid/sgid: execute as the user/group who owns the file. - sticky: can't delete files you don't own out of this directory - X = x for directories or if any category already has x set. + Stanzas are applied in order: For each category (u = user, + g = group, o = other, a = all three, if none specified default is a), + set (+), clear (-), or copy (=), r = read, w = write, x = execute. + s = u+s = suid, g+s = sgid, o+s = sticky. (+t is an alias for o+s). + suid/sgid: execute as the user/group who owns the file. + sticky: can't delete files you don't own out of this directory + X = x for directories or if any category already has x set. - Or MODE can be an octal value up to 7777 ug uuugggooo top + - bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1 sstrwxrwxrwx bottom + Or MODE can be an octal value up to 7777 ug uuugggooo top + + bit 1 = o+x, bit 1<<8 = u+w, 1<<11 = g+1 sstrwxrwxrwx bottom - Examples: - chmod u+w file - allow owner of "file" to write to it. - chmod 744 file - user can read/write/execute, everyone else read only + Examples: + chmod u+w file - allow owner of "file" to write to it. + chmod 744 file - user can read/write/execute, everyone else read only */ #define FOR_chmod #include "toys.h" GLOBALS( - char *mode; + char *mode; ) int do_chmod(struct dirtree *try) { - mode_t mode; + mode_t mode; - if (!dirtree_notdotdot(try)) return 0; + if (!dirtree_notdotdot(try)) return 0; - mode = string_to_mode(TT.mode, try->st.st_mode); - if (toys.optflags & FLAG_v) { - char *s = dirtree_path(try, 0); - printf("chmod '%s' to %04o\n", s, mode); - free(s); - } - wfchmodat(dirtree_parentfd(try), try->name, mode); + mode = string_to_mode(TT.mode, try->st.st_mode); + if (toys.optflags & FLAG_v) { + char *s = dirtree_path(try, 0); + printf("chmod '%s' to %04o\n", s, mode); + free(s); + } + wfchmodat(dirtree_parentfd(try), try->name, mode); - return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0; + return (toys.optflags & FLAG_R) ? DIRTREE_RECURSE : 0; } void chmod_main(void) { - TT.mode = *toys.optargs; - char **file; + TT.mode = *toys.optargs; + char **file; - for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod); + for (file = toys.optargs+1; *file; file++) dirtree_read(*file, do_chmod); } diff --git a/toys/posix/cksum.c b/toys/posix/cksum.c index 3e27b4cb..1192077c 100644 --- a/toys/posix/cksum.c +++ b/toys/posix/cksum.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * cksum.c - produce crc32 checksum value for each input +/* cksum.c - produce crc32 checksum value for each input * * Copyright 2008 Rob Landley <rob@landley.net> * @@ -9,78 +7,77 @@ USE_CKSUM(NEWTOY(cksum, "IPLN", TOYFLAG_BIN)) config CKSUM - bool "cksum" - default y - help - usage: cksum [-IPLN] [file...] - - For each file, output crc32 checksum value, length and name of file. - If no files listed, copy from stdin. Filename "-" is a synonym for stdin. - - -L Little endian (defaults to big endian) - -P Pre-inversion - -I Skip post-inversion - -N Do not include length in CRC calculation + bool "cksum" + default y + help + usage: cksum [-IPLN] [file...] + + For each file, output crc32 checksum value, length and name of file. + If no files listed, copy from stdin. Filename "-" is a synonym for stdin. + + -L Little endian (defaults to big endian) + -P Pre-inversion + -I Skip post-inversion + -N Do not include length in CRC calculation */ #define FOR_cksum #include "toys.h" GLOBALS( - unsigned crc_table[256]; + unsigned crc_table[256]; ) static unsigned cksum_be(unsigned crc, unsigned char c) { - return (crc<<8)^TT.crc_table[(crc>>24)^c]; + return (crc<<8)^TT.crc_table[(crc>>24)^c]; } static unsigned cksum_le(unsigned crc, unsigned char c) { - return TT.crc_table[(crc^c)&0xff] ^ (crc>>8); + return TT.crc_table[(crc^c)&0xff] ^ (crc>>8); } static void do_cksum(int fd, char *name) { - unsigned crc = (toys.optflags&4) ? 0xffffffff : 0; - uint64_t llen = 0, llen2; - unsigned (*cksum)(unsigned crc, unsigned char c); - - - cksum = (toys.optflags&2) ? cksum_le : cksum_be; - // CRC the data - - for (;;) { - int len, i; - - len = read(fd, toybuf, sizeof(toybuf)); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - - llen += len; - for (i=0; i<len; i++) crc=cksum(crc, toybuf[i]); - } - - // CRC the length - - llen2 = llen; - if (!(toys.optflags&1)) { - while (llen) { - crc = cksum(crc, llen); - llen >>= 8; - } - } - - printf("%u %"PRIu64, (toys.optflags&8) ? crc : ~crc, llen2); - if (strcmp("-", name)) printf(" %s", name); - xputc('\n'); + unsigned crc = (toys.optflags&4) ? 0xffffffff : 0; + uint64_t llen = 0, llen2; + unsigned (*cksum)(unsigned crc, unsigned char c); + + cksum = (toys.optflags&2) ? cksum_le : cksum_be; + // CRC the data + + for (;;) { + int len, i; + + len = read(fd, toybuf, sizeof(toybuf)); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + + llen += len; + for (i=0; i<len; i++) crc=cksum(crc, toybuf[i]); + } + + // CRC the length + + llen2 = llen; + if (!(toys.optflags&1)) { + while (llen) { + crc = cksum(crc, llen); + llen >>= 8; + } + } + + printf("%u %"PRIu64, (toys.optflags&8) ? crc : ~crc, llen2); + if (strcmp("-", name)) printf(" %s", name); + xputc('\n'); } void cksum_main(void) { - crc_init(TT.crc_table, toys.optflags&2); - loopfiles(toys.optargs, do_cksum); + crc_init(TT.crc_table, toys.optflags&2); + loopfiles(toys.optargs, do_cksum); } diff --git a/toys/posix/cmp.c b/toys/posix/cmp.c index 4bbd3f30..13990d45 100644 --- a/toys/posix/cmp.c +++ b/toys/posix/cmp.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * cmp.c - Compare two files. +/* cmp.c - Compare two files. * * Copyright 2012 Timothy Elliott <tle@holymonkey.com> * @@ -9,80 +7,78 @@ USE_CMP(NEWTOY(cmp, "<2>2ls", TOYFLAG_USR|TOYFLAG_BIN)) config CMP - bool "cmp" - default y - help - usage: cmp [-l] [-s] FILE1 FILE2 + bool "cmp" + default y + help + usage: cmp [-l] [-s] FILE1 FILE2 - Compare the contents of two files. + Compare the contents of two files. - -l show all differing bytes - -s silent + -l show all differing bytes + -s silent */ #define FOR_cmp #include "toys.h" GLOBALS( - int fd; - char *name; + int fd; + char *name; ) -// This handles opening the file and +// This handles opening the file and void do_cmp(int fd, char *name) { - int i, len1, len2, min_len, size = sizeof(toybuf)/2; - long byte_no = 1, line_no = 1; - char *buf2 = toybuf+size; + int i, len1, len2, min_len, size = sizeof(toybuf)/2; + long byte_no = 1, line_no = 1; + char *buf2 = toybuf+size; - // First time through, cache the data and return. - if (!TT.fd) { - TT.name = name; - // On return the old filehandle is closed, and this assures that even - // if we were called with stdin closed, the new filehandle != 0. - TT.fd = dup(fd); - return; - } + // First time through, cache the data and return. + if (!TT.fd) { + TT.name = name; + // On return the old filehandle is closed, and this assures that even + // if we were called with stdin closed, the new filehandle != 0. + TT.fd = dup(fd); + return; + } - for (;;) { - len1 = readall(TT.fd, toybuf, size); - len2 = readall(fd, buf2, size); + for (;;) { + len1 = readall(TT.fd, toybuf, size); + len2 = readall(fd, buf2, size); - min_len = len1 < len2 ? len1 : len2; - for (i=0; i<min_len; i++) { - if (toybuf[i] != buf2[i]) { - toys.exitval = 1; - if (toys.optflags & FLAG_l) - printf("%ld %o %o\n", byte_no, toybuf[i], buf2[i]); - else { - if (!(toys.optflags & FLAG_s)) { - printf("%s %s differ: char %ld, line %ld\n", - TT.name, name, byte_no, line_no); - toys.exitval++; - } - goto out; - } - } - byte_no++; - if (toybuf[i] == '\n') line_no++; - } - if (len1 != len2) { - if (!(toys.optflags & FLAG_s)) { - fprintf(stderr, "cmp: EOF on %s\n", - len1 < len2 ? TT.name : name); - } - toys.exitval = 1; - break; - } - if (len1 < 1) break; - } + min_len = len1 < len2 ? len1 : len2; + for (i=0; i<min_len; i++) { + if (toybuf[i] != buf2[i]) { + toys.exitval = 1; + if (toys.optflags & FLAG_l) + printf("%ld %o %o\n", byte_no, toybuf[i], buf2[i]); + else { + if (!(toys.optflags & FLAG_s)) { + printf("%s %s differ: char %ld, line %ld\n", + TT.name, name, byte_no, line_no); + toys.exitval++; + } + goto out; + } + } + byte_no++; + if (toybuf[i] == '\n') line_no++; + } + if (len1 != len2) { + if (!(toys.optflags & FLAG_s)) + fprintf(stderr, "cmp: EOF on %s\n", len1 < len2 ? TT.name : name); + toys.exitval = 1; + break; + } + if (len1 < 1) break; + } out: - if (CFG_TOYBOX_FREE) close(TT.fd); + if (CFG_TOYBOX_FREE) close(TT.fd); } void cmp_main(void) { - loopfiles_rw(toys.optargs, O_RDONLY, 0, toys.optflags&FLAG_s, do_cmp); + loopfiles_rw(toys.optargs, O_RDONLY, 0, toys.optflags&FLAG_s, do_cmp); } diff --git a/toys/posix/comm.c b/toys/posix/comm.c index 477d5160..bbdcccef 100644 --- a/toys/posix/comm.c +++ b/toys/posix/comm.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * comm.c - select or reject lines common to two files +/* comm.c - select or reject lines common to two files * * Copyright 2012 Ilya Kuzmich <ikv@safe-mail.net> * @@ -10,18 +8,18 @@ USE_COMM(NEWTOY(comm, "<2>2321", TOYFLAG_USR|TOYFLAG_BIN)) config COMM - bool "comm" - default y - help - usage: comm [-123] FILE1 FILE2 + bool "comm" + default y + help + usage: comm [-123] FILE1 FILE2 - Reads FILE1 and FILE2, which should be ordered, and produces three text - columns as output: lines only in FILE1; lines only in FILE2; and lines - in both files. Filename "-" is a synonym for stdin. + Reads FILE1 and FILE2, which should be ordered, and produces three text + columns as output: lines only in FILE1; lines only in FILE2; and lines + in both files. Filename "-" is a synonym for stdin. - -1 suppress the output column of lines unique to FILE1 - -2 suppress the output column of lines unique to FILE2 - -3 suppress the output column of lines duplicated in FILE1 and FILE2 + -1 suppress the output column of lines unique to FILE1 + -2 suppress the output column of lines unique to FILE2 + -3 suppress the output column of lines duplicated in FILE1 and FILE2 */ #define FOR_comm @@ -29,54 +27,55 @@ config COMM static void writeline(const char *line, int col) { - if (col == 0 && toys.optflags & FLAG_1) return; - else if (col == 1) { - if (toys.optflags & FLAG_2) return; - if (!(toys.optflags & FLAG_1)) putchar('\t'); - } else if (col == 2) { - if (toys.optflags & FLAG_3) return; - if (!(toys.optflags & FLAG_1)) putchar('\t'); - if (!(toys.optflags & FLAG_2)) putchar('\t'); - } - puts(line); + if (col == 0 && toys.optflags & FLAG_1) return; + else if (col == 1) { + if (toys.optflags & FLAG_2) return; + if (!(toys.optflags & FLAG_1)) putchar('\t'); + } else if (col == 2) { + if (toys.optflags & FLAG_3) return; + if (!(toys.optflags & FLAG_1)) putchar('\t'); + if (!(toys.optflags & FLAG_2)) putchar('\t'); + } + puts(line); } void comm_main(void) { - int file[2]; - char *line[2]; - int i; + int file[2]; + char *line[2]; + int i; - if (toys.optflags == 7) return; + if (toys.optflags == 7) return; - for (i = 0; i < 2; i++) { - file[i] = strcmp("-", toys.optargs[i]) ? xopen(toys.optargs[i], O_RDONLY) : 0; - line[i] = get_line(file[i]); - } + for (i = 0; i < 2; i++) { + file[i] = strcmp("-", toys.optargs[i]) + ? xopen(toys.optargs[i], O_RDONLY) : 0; + line[i] = get_line(file[i]); + } - while (line[0] && line[1]) { - int order = strcmp(line[0], line[1]); + while (line[0] && line[1]) { + int order = strcmp(line[0], line[1]); - if (order == 0) { - writeline(line[0], 2); - for (i = 0; i < 2; i++) { - free(line[i]); - line[i] = get_line(file[i]); - } - } else { - i = order < 0 ? 0 : 1; - writeline(line[i], i); - free(line[i]); - line[i] = get_line(file[i]); - } - } + if (order == 0) { + writeline(line[0], 2); + for (i = 0; i < 2; i++) { + free(line[i]); + line[i] = get_line(file[i]); + } + } else { + i = order < 0 ? 0 : 1; + writeline(line[i], i); + free(line[i]); + line[i] = get_line(file[i]); + } + } - /* print rest of the longer file */ - for (i = line[0] ? 0 : 1; line[i];) { - writeline(line[i], i); - free(line[i]); - line[i] = get_line(file[i]); - } + /* print rest of the longer file */ + for (i = line[0] ? 0 : 1; line[i];) { + writeline(line[i], i); + free(line[i]); + line[i] = get_line(file[i]); + } - if (CFG_TOYBOX_FREE) for (i = 0; i < 2; i--) xclose(file[i]); + if (CFG_TOYBOX_FREE) for (i = 0; i < 2; i--) xclose(file[i]); } diff --git a/toys/posix/cp.c b/toys/posix/cp.c index b7834e86..e25dad46 100644 --- a/toys/posix/cp.c +++ b/toys/posix/cp.c @@ -1,8 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * cp.c - Copy files. - * - * Copyright 2008 Rob Landley <rob@landley.net> +/* Copyright 2008 Rob Landley <rob@landley.net> * * See http://opengroup.org/onlinepubs/9699919799/utilities/cp.html * @@ -11,35 +7,35 @@ USE_CP(NEWTOY(cp, "<2"USE_CP_MORE("rdavsl")"RHLPfip", TOYFLAG_BIN)) config CP - bool "cp (broken by dirtree changes)" - default n - help - usage: cp [-fipRHLP] SOURCE... DEST - - Copy files from SOURCE to DEST. If more than one SOURCE, DEST must - be a directory. - - -f force copy by deleting destination file - -i interactive, prompt before overwriting existing DEST - -p preserve timestamps, ownership, and permissions - -R recurse into subdirectories (DEST must be a directory) - -H Follow symlinks listed on command line - -L Follow all symlinks - -P Do not follow symlinks [default] + bool "cp (broken by dirtree changes)" + default n + help + usage: cp [-fipRHLP] SOURCE... DEST + + Copy files from SOURCE to DEST. If more than one SOURCE, DEST must + be a directory. + + -f force copy by deleting destination file + -i interactive, prompt before overwriting existing DEST + -p preserve timestamps, ownership, and permissions + -R recurse into subdirectories (DEST must be a directory) + -H Follow symlinks listed on command line + -L Follow all symlinks + -P Do not follow symlinks [default] config CP_MORE - bool "cp -rdavsl options" - default y - depends on CP - help - usage: cp [-rdavsl] - - -r synonym for -R - -d don't dereference symlinks - -a same as -dpr - -l hard link instead of copy - -s symlink instead of copy - -v verbose + bool "cp -rdavsl options" + default y + depends on CP + help + usage: cp [-rdavsl] + + -r synonym for -R + -d don't dereference symlinks + -a same as -dpr + -l hard link instead of copy + -s symlink instead of copy + -v verbose */ #define FOR_cp @@ -48,180 +44,176 @@ config CP_MORE // TODO: PLHlsd GLOBALS( - char *destname; - int destisdir; - int keep_symlinks; + char *destname; + int destisdir; + int keep_symlinks; ) // Copy an individual file or directory to target. void cp_file(char *src, char *dst, struct stat *srcst) { - int fdout = -1; - - // -i flag is specified and dst file exists. - if ((toys.optflags&FLAG_i) && !access(dst, R_OK) - && !yesno("cp: overwrite", 1)) - return; - - if (toys.optflags & FLAG_v) - printf("'%s' -> '%s'\n", src, dst); - - // Copy directory or file to destination. - - if (S_ISDIR(srcst->st_mode)) { - struct stat st2; - - // Always make directory writeable to us, so we can create files in it. - // - // Yes, there's a race window between mkdir() and open() so it's - // possible that -p can be made to chown a directory other than the one - // we created. The closest we can do to closing this is make sure - // that what we open _is_ a directory rather than something else. - - if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST) - || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2) - || !S_ISDIR(st2.st_mode)) - { - perror_exit("mkdir '%s'", dst); - } - } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) { - char *link = xreadlink(src); - - // Note: -p currently has no effect on symlinks. How do you get a - // filehandle to them? O_NOFOLLOW causes the open to fail. - if (!link || symlink(link, dst)) perror_msg("link '%s'", dst); - free(link); - return; - } else if (toys.optflags & FLAG_l) { - if (link(src, dst)) perror_msg("link '%s'"); - return; - } else { - int fdin, i; - - fdin = xopen(src, O_RDONLY); - for (i=2 ; i; i--) { - fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); - if (fdout>=0 || !(toys.optflags & FLAG_f)) break; - unlink(dst); - } - if (fdout<0) perror_exit("%s", dst); - xsendfile(fdin, fdout); - close(fdin); - } - - // Inability to set these isn't fatal, some require root access. - // Can't do fchmod() etc here because -p works on mkdir, too. - - if (toys.optflags & (FLAG_p|FLAG_a)) { - int mask = umask(0); - struct utimbuf ut; - - (void) fchown(fdout,srcst->st_uid, srcst->st_gid); - ut.actime = srcst->st_atime; - ut.modtime = srcst->st_mtime; - utime(dst, &ut); - umask(mask); - } - xclose(fdout); + int fdout = -1; + + // -i flag is specified and dst file exists. + if ((toys.optflags&FLAG_i) && !access(dst, R_OK) + && !yesno("cp: overwrite", 1)) + return; + + if (toys.optflags & FLAG_v) printf("'%s' -> '%s'\n", src, dst); + + // Copy directory or file to destination. + + if (S_ISDIR(srcst->st_mode)) { + struct stat st2; + + // Always make directory writeable to us, so we can create files in it. + // + // Yes, there's a race window between mkdir() and open() so it's + // possible that -p can be made to chown a directory other than the one + // we created. The closest we can do to closing this is make sure + // that what we open _is_ a directory rather than something else. + + if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST) + || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2) || !S_ISDIR(st2.st_mode)) + { + perror_exit("mkdir '%s'", dst); + } + } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) { + char *link = xreadlink(src); + + // Note: -p currently has no effect on symlinks. How do you get a + // filehandle to them? O_NOFOLLOW causes the open to fail. + if (!link || symlink(link, dst)) perror_msg("link '%s'", dst); + free(link); + return; + } else if (toys.optflags & FLAG_l) { + if (link(src, dst)) perror_msg("link '%s'"); + return; + } else { + int fdin, i; + + fdin = xopen(src, O_RDONLY); + for (i=2 ; i; i--) { + fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); + if (fdout>=0 || !(toys.optflags & FLAG_f)) break; + unlink(dst); + } + if (fdout<0) perror_exit("%s", dst); + xsendfile(fdin, fdout); + close(fdin); + } + + // Inability to set these isn't fatal, some require root access. + // Can't do fchmod() etc here because -p works on mkdir, too. + + if (toys.optflags & (FLAG_p|FLAG_a)) { + int mask = umask(0); + struct utimbuf ut; + + (void) fchown(fdout,srcst->st_uid, srcst->st_gid); + ut.actime = srcst->st_atime; + ut.modtime = srcst->st_mtime; + utime(dst, &ut); + umask(mask); + } + xclose(fdout); } // Callback from dirtree_read() for each file/directory under a source dir. int cp_node(struct dirtree *node) { - char *path = dirtree_path(node, 0); // TODO: use openat() instead - char *s = path+strlen(path); - struct dirtree *n; - - // Find appropriate chunk of path for destination. - - n = node; - if (!TT.destisdir) n = n->parent; - for (;;n = n->parent) { - while (s!=path) { - if (*(--s)=='/') break; - } - if (!n) break; - } - if (s != path) s++; - - s = xmsprintf("%s/%s", TT.destname, s); - cp_file(path, s, &(node->st)); - free(s); - free(path); // redo this whole darn function. - - return 0; + char *path = dirtree_path(node, 0); // TODO: use openat() instead + char *s = path+strlen(path); + struct dirtree *n; + + // Find appropriate chunk of path for destination. + + n = node; + if (!TT.destisdir) n = n->parent; + for (;;n = n->parent) { + while (s!=path) if (*(--s)=='/') break; + if (!n) break; + } + if (s != path) s++; + + s = xmsprintf("%s/%s", TT.destname, s); + cp_file(path, s, &(node->st)); + free(s); + free(path); // redo this whole darn function. + + return 0; } void cp_main(void) { - char *dpath = NULL; - struct stat st, std; - int i; + char *dpath = NULL; + struct stat st, std; + int i; - // Identify destination + // Identify destination - if (!stat(TT.destname, &std) && S_ISDIR(std.st_mode)) TT.destisdir++; - else if (toys.optc>1) error_exit("'%s' not directory", TT.destname); + if (!stat(TT.destname, &std) && S_ISDIR(std.st_mode)) TT.destisdir++; + else if (toys.optc>1) error_exit("'%s' not directory", TT.destname); // TODO: This is too early: we haven't created it yet if we need to - if (toys.optflags & (FLAG_R|FLAG_r|FLAG_a)) - dpath = realpath(TT.destname = toys.optargs[--toys.optc], NULL); + if (toys.optflags & (FLAG_R|FLAG_r|FLAG_a)) + dpath = realpath(TT.destname = toys.optargs[--toys.optc], NULL); - // Loop through sources + // Loop through sources - for (i=0; i<toys.optc; i++) { - char *dst, *src = toys.optargs[i]; + for (i=0; i<toys.optc; i++) { + char *dst, *src = toys.optargs[i]; - // Skip src==dest (TODO check inodes to catch "cp blah ./blah"). + // Skip src==dest (TODO check inodes to catch "cp blah ./blah"). - if (!strncmp(src, TT.destname)) continue; + if (!strncmp(src, TT.destname)) continue; - // Skip nonexistent sources. + // Skip nonexistent sources. - TT.keep_symlinks = toys.optflags & (FLAG_d|FLAG_a); - if (TT.keep_symlinks ? lstat(src, &st) : stat(src, &st) - || (st.st_dev = dst.st_dev && st.st_ino == dst.dst_ino)) - { + TT.keep_symlinks = toys.optflags & (FLAG_d|FLAG_a); + if (TT.keep_symlinks ? lstat(src, &st) : stat(src, &st) + || (st.st_dev = dst.st_dev && st.st_ino == dst.dst_ino)) + { objection: - perror_msg("bad '%s'", src); - toys.exitval = 1; - continue; - } - - // Copy directory or file. - - if (TT.destisdir) { - char *s; - - // Catch "cp -R .. ." and friends that would go on forever - if (dpath && (s = realpath(src, NULL)) { - int i = strlen(s); - i = (!strncmp(s, dst, i) && (!s[i] || s[i]=='/')); - free(s); - - if (i) goto objection; - } - - // Create destination filename within directory - dst = strrchr(src, '/'); - if (dst) dst++; - else dst=src; - dst = xmsprintf("%s/%s", TT.destname, dst); - } else dst = TT.destname; - - if (S_ISDIR(st.st_mode)) { - if (toys.optflags & (FLAG_r|FLAG_R|FLAG_a)) { - cp_file(src, dst, &st); - - TT.keep_symlinks++; - dirtree_read(src, cp_node); - } else error_msg("Skipped dir '%s'", src); - } else cp_file(src, dst, &st); - if (TT.destisdir) free(dst); - } - - if (CFG_TOYBOX_FREE) free(dpath); - return; + perror_msg("bad '%s'", src); + toys.exitval = 1; + continue; + } + + // Copy directory or file. + + if (TT.destisdir) { + char *s; + + // Catch "cp -R .. ." and friends that would go on forever + if (dpath && (s = realpath(src, NULL)) { + int i = strlen(s); + i = (!strncmp(s, dst, i) && (!s[i] || s[i]=='/')); + free(s); + + if (i) goto objection; + } + + // Create destination filename within directory + dst = strrchr(src, '/'); + if (dst) dst++; + else dst=src; + dst = xmsprintf("%s/%s", TT.destname, dst); + } else dst = TT.destname; + + if (S_ISDIR(st.st_mode)) { + if (toys.optflags & (FLAG_r|FLAG_R|FLAG_a)) { + cp_file(src, dst, &st); + + TT.keep_symlinks++; + dirtree_read(src, cp_node); + } else error_msg("Skipped dir '%s'", src); + } else cp_file(src, dst, &st); + if (TT.destisdir) free(dst); + } + + if (CFG_TOYBOX_FREE) free(dpath); + return; } diff --git a/toys/posix/date.c b/toys/posix/date.c index 9beaaa1a..68751043 100644 --- a/toys/posix/date.c +++ b/toys/posix/date.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * date.c - set/get the date +/* date.c - set/get the date * * Copyright 2012 Andre Renaud <andre@bluewatersys.com> * @@ -9,83 +7,83 @@ USE_DATE(NEWTOY(date, "r:u", TOYFLAG_BIN)) config DATE - bool "date" - default y - help - usage: date [-u] [-r file] [+format] | mmddhhmm[[cc]yy] + bool "date" + default y + help + usage: date [-u] [-r file] [+format] | mmddhhmm[[cc]yy] - Set/get the current date/time + Set/get the current date/time */ #define FOR_date #include "toys.h" GLOBALS( - char *file; + char *file; ) void date_main(void) { - const char *format_string = "%a %b %e %H:%M:%S %Z %Y"; - time_t now = time(NULL); - struct tm tm; - - if (TT.file) { - struct stat st; - - xstat(TT.file, &st); - now = st.st_mtim.tv_sec; - } - ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm); - - // Display the date? - if (!toys.optargs[0] || toys.optargs[0][0] == '+') { - if (toys.optargs[0]) format_string = toys.optargs[0]+1; - if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) - perror_msg("bad format `%s'", format_string); - - puts(toybuf); - - // Set the date - } else { - struct timeval tv; - char *s = *toys.optargs; - int len = strlen(s); - - if (len < 8 || len > 12 || (len & 1)) error_msg("bad date `%s'", s); - - // Date format: mmddhhmm[[cc]yy] - memset(&tm, 0, sizeof(tm)); - len = sscanf(s, "%2u%2u%2u%2u", &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, - &tm.tm_min); - tm.tm_mon--; - - // If year specified, overwrite one we fetched earlier - if (len > 8) { - sscanf(s, "%u", &tm.tm_year); - if (len == 12) tm.tm_year -= 1900; - /* 69-99 = 1969-1999, 0 - 68 = 2000-2068 */ - else if (tm.tm_year < 69) tm.tm_year += 100; - } - - if (toys.optflags & FLAG_u) { - // Get the UTC version of a struct tm - char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0; - setenv("TZ", "UTC", 1); - tzset(); - tv.tv_sec = mktime(&tm); - if (CFG_TOYBOX_FREE) { - if (tz) setenv("TZ", tz, 1); - else unsetenv("TZ"); - tzset(); - } - } else tv.tv_sec = mktime(&tm); - - if (tv.tv_sec == (time_t)-1) error_msg("bad `%s'", toys.optargs[0]); - tv.tv_usec = 0; - if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) - perror_msg("bad format `%s'", format_string); - puts(toybuf); - if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date"); + const char *format_string = "%a %b %e %H:%M:%S %Z %Y"; + time_t now = time(NULL); + struct tm tm; + + if (TT.file) { + struct stat st; + + xstat(TT.file, &st); + now = st.st_mtim.tv_sec; + } + ((toys.optflags & FLAG_u) ? gmtime_r : localtime_r)(&now, &tm); + + // Display the date? + if (!toys.optargs[0] || toys.optargs[0][0] == '+') { + if (toys.optargs[0]) format_string = toys.optargs[0]+1; + if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) + perror_msg("bad format `%s'", format_string); + + puts(toybuf); + + // Set the date + } else { + struct timeval tv; + char *s = *toys.optargs; + int len = strlen(s); + + if (len < 8 || len > 12 || (len & 1)) error_msg("bad date `%s'", s); + + // Date format: mmddhhmm[[cc]yy] + memset(&tm, 0, sizeof(tm)); + len = sscanf(s, "%2u%2u%2u%2u", &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min); + tm.tm_mon--; + + // If year specified, overwrite one we fetched earlier + if (len > 8) { + sscanf(s, "%u", &tm.tm_year); + if (len == 12) tm.tm_year -= 1900; + /* 69-99 = 1969-1999, 0 - 68 = 2000-2068 */ + else if (tm.tm_year < 69) tm.tm_year += 100; } + + if (toys.optflags & FLAG_u) { + // Get the UTC version of a struct tm + char *tz = CFG_TOYBOX_FREE ? getenv("TZ") : 0; + setenv("TZ", "UTC", 1); + tzset(); + tv.tv_sec = mktime(&tm); + if (CFG_TOYBOX_FREE) { + if (tz) setenv("TZ", tz, 1); + else unsetenv("TZ"); + tzset(); + } + } else tv.tv_sec = mktime(&tm); + + if (tv.tv_sec == (time_t)-1) error_msg("bad `%s'", toys.optargs[0]); + tv.tv_usec = 0; + if (!strftime(toybuf, sizeof(toybuf), format_string, &tm)) + perror_msg("bad format `%s'", format_string); + puts(toybuf); + if (settimeofday(&tv, NULL) < 0) perror_msg("cannot set date"); + } } diff --git a/toys/posix/df.c b/toys/posix/df.c index 66e86b3b..5641ff34 100644 --- a/toys/posix/df.c +++ b/toys/posix/df.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * df.c - report free disk space. +/* df.c - report free disk space. * * Copyright 2006 Rob Landley <rob@landley.net> * @@ -9,156 +7,155 @@ USE_DF(NEWTOY(df, "Pkt*a", TOYFLAG_USR|TOYFLAG_SBIN)) config DF - bool "df (disk free)" - default y - help - usage: df [-t type] [FILESYSTEM ...] + bool "df (disk free)" + default y + help + usage: df [-t type] [FILESYSTEM ...] - The "disk free" command, df shows total/used/available disk space for - each filesystem listed on the command line, or all currently mounted - filesystems. + The "disk free" command, df shows total/used/available disk space for + each filesystem listed on the command line, or all currently mounted + filesystems. - -t type - Display only filesystems of this type. + -t type Display only filesystems of this type. config DF_PEDANTIC - bool "options -P and -k" - default y - depends on DF - help - usage: df [-Pk] + bool "options -P and -k" + default y + depends on DF + help + usage: df [-Pk] - -P The SUSv3 "Pedantic" option + -P The SUSv3 "Pedantic" option - Provides a slightly less useful output format dictated by - the Single Unix Specification version 3, and sets the - units to 512 bytes instead of the default 1024 bytes. + Provides a slightly less useful output format dictated by + the Single Unix Specification version 3, and sets the + units to 512 bytes instead of the default 1024 bytes. - -k Sets units back to 1024 bytes (the default without -P) + -k Sets units back to 1024 bytes (the default without -P) */ #define FOR_df #include "toys.h" GLOBALS( - struct arg_list *fstype; + struct arg_list *fstype; - long units; + long units; ) static void show_mt(struct mtab_list *mt) { - int len; - long long size, used, avail, percent, block; - char *device; - - // Return if it wasn't found (should never happen, but with /etc/mtab...) - if (!mt) return; - - // If we have -t, skip other filesystem types - if (TT.fstype) { - struct arg_list *al; - - for (al = TT.fstype; al; al = al->next) { - if (!strcmp(mt->type, al->arg)) break; - } - if (!al) return; - } - - // If we don't have -a, skip synthetic filesystems - if (!(toys.optflags & FLAG_a) && !mt->statvfs.f_blocks) return; - - // Figure out how much total/used/free space this filesystem has, - // forcing 64-bit math because filesystems are big now. - block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1; - size = (block * mt->statvfs.f_blocks) / TT.units; - used = (block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) / TT.units; - avail = (block * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) - / TT.units; - if (!(used+avail)) percent = 0; - else { - percent = (used*100)/(used+avail); - if (used*100 != percent*(used+avail)) percent++; - } - - device = *mt->device == '/' ? realpath(mt->device, NULL) : NULL; - if (!device) device = mt->device; - - // Figure out appropriate spacing - len = 25 - strlen(device); - if (len < 1) len = 1; - if (CFG_DF_PEDANTIC && (toys.optflags & FLAG_P)) { - xprintf("%s %lld %lld %lld %lld%% %s\n", device, size, used, avail, - percent, mt->dir); - } else { - xprintf("%s% *lld % 10lld % 9lld % 3lld%% %s\n", device, len, - size, used, avail, percent, mt->dir); - } - - if (device != mt->device) free(device); + int len; + long long size, used, avail, percent, block; + char *device; + + // Return if it wasn't found (should never happen, but with /etc/mtab...) + if (!mt) return; + + // If we have -t, skip other filesystem types + if (TT.fstype) { + struct arg_list *al; + + for (al = TT.fstype; al; al = al->next) + if (!strcmp(mt->type, al->arg)) break; + + if (!al) return; + } + + // If we don't have -a, skip synthetic filesystems + if (!(toys.optflags & FLAG_a) && !mt->statvfs.f_blocks) return; + + // Figure out how much total/used/free space this filesystem has, + // forcing 64-bit math because filesystems are big now. + block = mt->statvfs.f_bsize ? mt->statvfs.f_bsize : 1; + size = (block * mt->statvfs.f_blocks) / TT.units; + used = (block * (mt->statvfs.f_blocks-mt->statvfs.f_bfree)) / TT.units; + avail = (block * (getuid() ? mt->statvfs.f_bavail : mt->statvfs.f_bfree)) + / TT.units; + if (!(used+avail)) percent = 0; + else { + percent = (used*100)/(used+avail); + if (used*100 != percent*(used+avail)) percent++; + } + + device = *mt->device == '/' ? realpath(mt->device, NULL) : NULL; + if (!device) device = mt->device; + + // Figure out appropriate spacing + len = 25 - strlen(device); + if (len < 1) len = 1; + if (CFG_DF_PEDANTIC && (toys.optflags & FLAG_P)) { + xprintf("%s %lld %lld %lld %lld%% %s\n", device, size, used, avail, + percent, mt->dir); + } else { + xprintf("%s% *lld % 10lld % 9lld % 3lld%% %s\n", device, len, + size, used, avail, percent, mt->dir); + } + + if (device != mt->device) free(device); } void df_main(void) { - struct mtab_list *mt, *mt2, *mtlist; - - // Handle -P and -k - TT.units = 1024; - if (CFG_DF_PEDANTIC && (toys.optflags & FLAG_P)) { - // Units are 512 bytes if you select "pedantic" without "kilobytes". - if ((toys.optflags&(FLAG_P|FLAG_k)) == FLAG_P) TT.units = 512; - printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", - TT.units); - } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); - - mtlist = getmountlist(1); - - // If we have a list of filesystems on the command line, loop through them. - if (*toys.optargs) { - char **next; - - for(next = toys.optargs; *next; next++) { - struct stat st; - - // Stat it (complain if we can't). - if(stat(*next, &st)) { - perror_msg("`%s'", *next); - toys.exitval = 1; - continue; - } - - // Find and display this filesystem. Use _last_ hit in case of - // -- bind mounts. - mt2 = NULL; - for (mt = mtlist; mt; mt = mt->next) { - if (st.st_dev == mt->stat.st_dev) { - mt2 = mt; - break; - } - } - show_mt(mt2); - } - } else { - // Get and loop through mount list. - - for (mt = mtlist; mt; mt = mt->next) { - struct mtab_list *mt2, *mt3; - - if (!mt->stat.st_dev) continue; - - // Filter out overmounts. - mt3 = mt; - for (mt2 = mt->next; mt2; mt2 = mt2->next) { - if (mt->stat.st_dev == mt2->stat.st_dev) { - // For --bind mounts, take last match - if (!strcmp(mt->device, mt2->device)) mt3 = mt2; - // Filter out overmounts - mt2->stat.st_dev = 0; - } - } - show_mt(mt3); - } - } - - if (CFG_TOYBOX_FREE) llist_traverse(mtlist, free); + struct mtab_list *mt, *mt2, *mtlist; + + // Handle -P and -k + TT.units = 1024; + if (CFG_DF_PEDANTIC && (toys.optflags & FLAG_P)) { + // Units are 512 bytes if you select "pedantic" without "kilobytes". + if ((toys.optflags&(FLAG_P|FLAG_k)) == FLAG_P) TT.units = 512; + printf("Filesystem %ld-blocks Used Available Capacity Mounted on\n", + TT.units); + } else puts("Filesystem\t1K-blocks\tUsed Available Use% Mounted on"); + + mtlist = getmountlist(1); + + // If we have a list of filesystems on the command line, loop through them. + if (*toys.optargs) { + char **next; + + for(next = toys.optargs; *next; next++) { + struct stat st; + + // Stat it (complain if we can't). + if(stat(*next, &st)) { + perror_msg("`%s'", *next); + toys.exitval = 1; + continue; + } + + // Find and display this filesystem. Use _last_ hit in case of + // -- bind mounts. + mt2 = NULL; + for (mt = mtlist; mt; mt = mt->next) { + if (st.st_dev == mt->stat.st_dev) { + mt2 = mt; + break; + } + } + show_mt(mt2); + } + } else { + // Get and loop through mount list. + + for (mt = mtlist; mt; mt = mt->next) { + struct mtab_list *mt2, *mt3; + + if (!mt->stat.st_dev) continue; + + // Filter out overmounts. + mt3 = mt; + for (mt2 = mt->next; mt2; mt2 = mt2->next) { + if (mt->stat.st_dev == mt2->stat.st_dev) { + // For --bind mounts, take last match + if (!strcmp(mt->device, mt2->device)) mt3 = mt2; + // Filter out overmounts + mt2->stat.st_dev = 0; + } + } + show_mt(mt3); + } + } + + if (CFG_TOYBOX_FREE) llist_traverse(mtlist, free); } diff --git a/toys/posix/dirname.c b/toys/posix/dirname.c index 5dc60181..06470ad8 100644 --- a/toys/posix/dirname.c +++ b/toys/posix/dirname.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * dirname.c - show directory portion of path +/* dirname.c - show directory portion of path * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,17 +7,17 @@ USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN)) config DIRNAME - bool "dirname" - default y - help - usage: dirname PATH + bool "dirname" + default y + help + usage: dirname PATH - Show directory portion of path. + Show directory portion of path. */ #include "toys.h" void dirname_main(void) { - puts(dirname(*toys.optargs)); + puts(dirname(*toys.optargs)); } diff --git a/toys/posix/du.c b/toys/posix/du.c index 8013810c..68cf286d 100644 --- a/toys/posix/du.c +++ b/toys/posix/du.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * du.c - disk usage program. +/* du.c - disk usage program. * * Copyright 2012 Ashwini Kumar <ak.ashwini@gmail.com> * @@ -9,45 +7,45 @@ USE_DU(NEWTOY(du, "d#<0hmlcaHkLsx", TOYFLAG_USR|TOYFLAG_BIN)) config DU - bool "du" - default y - help - usage: du [-d N] [-askxHLlmc] [file...] - - Estimate file space usage (default in unit of 512 blocks). - -a Show all file sizes - -H Follow symlinks on cmdline - -L Follow all symlinks - -k Show size in units of 1024. - -s Show only the total Size for each file specified - -x Estimate size only on the same device - -c Print total size of all arguments - -d N Limit output to directories (and files with -a) of depth < N - -l Count sizes many times if hard linked - -h Sizes in human readable format (e.g., 1K 243M 2G ) - -m Sizes in megabytes + bool "du" + default y + help + usage: du [-d N] [-askxHLlmc] [file...] + + Estimate file space usage (default in unit of 512 blocks). + -a Show all file sizes + -H Follow symlinks on cmdline + -L Follow all symlinks + -k Show size in units of 1024. + -s Show only the total Size for each file specified + -x Estimate size only on the same device + -c Print total size of all arguments + -d N Limit output to directories (and files with -a) of depth < N + -l Count sizes many times if hard linked + -h Sizes in human readable format (e.g., 1K 243M 2G ) + -m Sizes in megabytes */ #define FOR_du #include "toys.h" GLOBALS( - long maxdepth; - long depth; - long *dirsum; - long total; - dev_t st_dev; - struct arg_list *inodes; + long maxdepth; + long depth; + long *dirsum; + long total; + dev_t st_dev; + struct arg_list *inodes; ) typedef struct node_size { - struct dirtree *node; - long size; + struct dirtree *node; + long size; }node_size; typedef struct inode_ent { - ino_t ino; - dev_t dev; + ino_t ino; + dev_t dev; }inode_ent_t; /* @@ -56,18 +54,18 @@ typedef struct inode_ent { char *make_pathproper(char *str) { - char *path = str; - switch(strlen(str)) { - case 1: - if(str[0] == '.') path = xstrdup("./"); - break; - case 2: - if(str[0] == '.' && str[1] == '.') path = xstrdup("../"); - break; - default: - break; - } - return path; + char *path = str; + switch(strlen(str)) { + case 1: + if(str[0] == '.') path = xstrdup("./"); + break; + case 2: + if(str[0] == '.' && str[1] == '.') path = xstrdup("../"); + break; + default: + break; + } + return path; } /* @@ -75,38 +73,38 @@ char *make_pathproper(char *str) */ void print(long size, char* name) { - unsigned long long tempsize = (unsigned long long)size * 512; - unsigned long unit = 512; - char *sizestr = NULL; - if(TT.depth > TT.maxdepth) return; - if(toys.optflags & FLAG_h) unit = 0; - if(toys.optflags & FLAG_k) unit = 1024; - if(toys.optflags & FLAG_m) unit = 1024*1024; - sizestr = make_human_readable(tempsize, unit); //make human readable string, depending upon unit size. - xprintf("%s\t%s\n",sizestr, name); - free(sizestr); + unsigned long long tempsize = (unsigned long long)size * 512; + unsigned long unit = 512; + char *sizestr = NULL; + if(TT.depth > TT.maxdepth) return; + if(toys.optflags & FLAG_h) unit = 0; + if(toys.optflags & FLAG_k) unit = 1024; + if(toys.optflags & FLAG_m) unit = 1024*1024; + sizestr = make_human_readable(tempsize, unit); //make human readable string, depending upon unit size. + xprintf("%s\t%s\n",sizestr, name); + free(sizestr); } /* - * free the inodes which are stored for hard link reference + * free the inodes which are stored for hard link reference */ void free_inodes(void *data) { - void *arg = ((struct arg_list*)data)->arg; - if(arg) free(arg); - free(data); + void *arg = ((struct arg_list*)data)->arg; + if(arg) free(arg); + free(data); } /* * allocate and add a node to the list */ static void llist_add_inode(struct arg_list **old, void *data) -{ - struct arg_list *new = xmalloc(sizeof(struct arg_list)); +{ + struct arg_list *new = xmalloc(sizeof(struct arg_list)); - new->arg = (char*)data; - new->next = *old; - *old = new; + new->arg = (char*)data; + new->next = *old; + *old = new; } /* @@ -114,14 +112,14 @@ static void llist_add_inode(struct arg_list **old, void *data) */ int is_inode_present(struct stat *st) { - struct arg_list *temparg = NULL; - inode_ent_t *ent = NULL; - if(!TT.inodes) return 0; - for(temparg = TT.inodes; temparg; temparg = (struct arg_list *)temparg->next) { - ent = (inode_ent_t*)temparg->arg; - if(ent && ent->ino == st->st_ino && ent->dev == st->st_dev) return 1; - } - return 0; + struct arg_list *temparg = NULL; + inode_ent_t *ent = NULL; + if(!TT.inodes) return 0; + for(temparg = TT.inodes; temparg; temparg = (struct arg_list *)temparg->next) { + ent = (inode_ent_t*)temparg->arg; + if(ent && ent->ino == st->st_ino && ent->dev == st->st_dev) return 1; + } + return 0; } /* @@ -129,66 +127,66 @@ int is_inode_present(struct stat *st) */ int do_du(struct dirtree *node) { - inode_ent_t *ino_details = NULL; - node_size *nd = NULL; - if(!dirtree_notdotdot(node)) return 0; - if((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) //if file not on same device, don't count size - return DIRTREE_RECURSE; - - if(!(toys.optflags & FLAG_l) && node->st.st_nlink > 1 && !node->extra) { //keeping reference for hard links - if(is_inode_present(&node->st)) return DIRTREE_RECURSE; - ino_details = xzalloc(sizeof(inode_ent_t)); - ino_details->ino = node->st.st_ino; - ino_details->dev = node->st.st_dev; - llist_add_inode(&TT.inodes, (void*)ino_details); - } + inode_ent_t *ino_details = NULL; + node_size *nd = NULL; + if(!dirtree_notdotdot(node)) return 0; + if((toys.optflags & FLAG_x) && (TT.st_dev != node->st.st_dev)) //if file not on same device, don't count size + return DIRTREE_RECURSE; - if(S_ISDIR(node->st.st_mode)) { - if(!(node->extra && (long)((node_size*)(node->extra))->node == (long)node)) { - nd = xzalloc(sizeof(node_size)); - nd->node = node; - nd->size = 0; - TT.dirsum = (long*)&(nd->size); - node->extra = (long)nd; - *TT.dirsum = 0; - TT.depth++; - return (DIRTREE_RECURSE|DIRTREE_COMEAGAIN | ((toys.optflags & FLAG_L) ? DIRTREE_SYMFOLLOW : 0)); //DIRTREE_COMEAGAIN to comeback and print the entry. - } - else if(node->extra) { //extra is set for a returning DIR entry. - long offset = 0; - nd = (node_size*)node->extra; - offset = nd->size; - nd->size += node->st.st_blocks; - TT.depth--; - if(!(toys.optflags & FLAG_s)) - print(*TT.dirsum, dirtree_path(node, NULL)); - if((node->parent) && (node->parent->extra)) { - /* when returning from internal directory, get the saved size of the parent and continue from there */ - nd = (node_size*)node->parent->extra; - TT.dirsum = (long*)&(nd->size); - *TT.dirsum += offset; - *TT.dirsum += node->st.st_blocks; - return DIRTREE_RECURSE; - } - else if(!node->parent) { - /*if node has no parent, it means it is the top in the tree, stop recursing here */ - TT.total += *TT.dirsum; - if((toys.optflags & FLAG_s)) - print(*TT.dirsum, dirtree_path(node, NULL)); - return 0; - } - } + if(!(toys.optflags & FLAG_l) && node->st.st_nlink > 1 && !node->extra) { //keeping reference for hard links + if(is_inode_present(&node->st)) return DIRTREE_RECURSE; + ino_details = xzalloc(sizeof(inode_ent_t)); + ino_details->ino = node->st.st_ino; + ino_details->dev = node->st.st_dev; + llist_add_inode(&TT.inodes, (void*)ino_details); + } + + if(S_ISDIR(node->st.st_mode)) { + if(!(node->extra && (long)((node_size*)(node->extra))->node == (long)node)) { + nd = xzalloc(sizeof(node_size)); + nd->node = node; + nd->size = 0; + TT.dirsum = (long*)&(nd->size); + node->extra = (long)nd; + *TT.dirsum = 0; + TT.depth++; + return (DIRTREE_RECURSE|DIRTREE_COMEAGAIN | ((toys.optflags & FLAG_L) ? DIRTREE_SYMFOLLOW : 0)); //DIRTREE_COMEAGAIN to comeback and print the entry. } - else if(!(node->parent)) { - /* this is the file specified on cmdline */ - TT.total += node->st.st_blocks; - print(node->st.st_blocks, dirtree_path(node, NULL)); + else if(node->extra) { //extra is set for a returning DIR entry. + long offset = 0; + nd = (node_size*)node->extra; + offset = nd->size; + nd->size += node->st.st_blocks; + TT.depth--; + if(!(toys.optflags & FLAG_s)) + print(*TT.dirsum, dirtree_path(node, NULL)); + if((node->parent) && (node->parent->extra)) { + /* when returning from internal directory, get the saved size of the parent and continue from there */ + nd = (node_size*)node->parent->extra; + TT.dirsum = (long*)&(nd->size); + *TT.dirsum += offset; + *TT.dirsum += node->st.st_blocks; + return DIRTREE_RECURSE; + } + else if(!node->parent) { + /*if node has no parent, it means it is the top in the tree, stop recursing here */ + TT.total += *TT.dirsum; + if((toys.optflags & FLAG_s)) + print(*TT.dirsum, dirtree_path(node, NULL)); return 0; + } } - if(TT.dirsum) *TT.dirsum += node->st.st_blocks; - if(toys.optflags & FLAG_a && !(toys.optflags & FLAG_s)) - print(node->st.st_blocks, dirtree_path(node, NULL)); - return DIRTREE_RECURSE; + } + else if(!(node->parent)) { + /* this is the file specified on cmdline */ + TT.total += node->st.st_blocks; + print(node->st.st_blocks, dirtree_path(node, NULL)); + return 0; + } + if(TT.dirsum) *TT.dirsum += node->st.st_blocks; + if(toys.optflags & FLAG_a && !(toys.optflags & FLAG_s)) + print(node->st.st_blocks, dirtree_path(node, NULL)); + return DIRTREE_RECURSE; } /* @@ -196,22 +194,22 @@ int do_du(struct dirtree *node) */ void du_main(void) { - int symfollow = toys.optflags & (FLAG_H | FLAG_L); - TT.total = 0; - TT.inodes = NULL; - - if(!(toys.optflags & FLAG_d)) TT.maxdepth = INT_MAX; - if(toys.optc == 0) toys.optargs[0] = "./"; - while(*toys.optargs) { - TT.depth = 0; - char *path = make_pathproper(*toys.optargs); - struct dirtree *root = dirtree_add_node(AT_FDCWD, path, symfollow); //create a node - if(root) { - TT.st_dev = root->st.st_dev; - handle_callback(root, do_du); //this will recurse thru the DIR children. - } - toys.optargs++; + int symfollow = toys.optflags & (FLAG_H | FLAG_L); + TT.total = 0; + TT.inodes = NULL; + + if(!(toys.optflags & FLAG_d)) TT.maxdepth = INT_MAX; + if(toys.optc == 0) toys.optargs[0] = "./"; + while(*toys.optargs) { + TT.depth = 0; + char *path = make_pathproper(*toys.optargs); + struct dirtree *root = dirtree_add_node(AT_FDCWD, path, symfollow); //create a node + if(root) { + TT.st_dev = root->st.st_dev; + handle_callback(root, do_du); //this will recurse thru the DIR children. } - if(TT.inodes) llist_traverse(TT.inodes, free_inodes); //free the stored nodes - if(toys.optflags & FLAG_c) print(TT.total, "total"); + toys.optargs++; + } + if(TT.inodes) llist_traverse(TT.inodes, free_inodes); //free the stored nodes + if(toys.optflags & FLAG_c) print(TT.total, "total"); } diff --git a/toys/posix/echo.c b/toys/posix/echo.c index 1bf4d399..28284bfb 100644 --- a/toys/posix/echo.c +++ b/toys/posix/echo.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * echo.c - echo supporting -n and -e. +/* echo.c - echo supporting -n and -e. * * Copyright 2007 Rob Landley <rob@landley.net> * @@ -9,27 +7,27 @@ USE_ECHO(NEWTOY(echo, "^?en", TOYFLAG_BIN)) config ECHO - bool "echo" - default y - help - usage: echo [-ne] [args...] + bool "echo" + default y + help + usage: echo [-ne] [args...] - Write each argument to stdout, with one space between each, followed - by a newline. + Write each argument to stdout, with one space between each, followed + by a newline. - -n No trailing newline. - -e Process the following escape sequences: - \\ backslash - \0NNN octal values (1 to 3 digits) - \a alert (beep/flash) - \b backspace - \c stop output here (avoids trailing newline) - \f form feed - \n newline - \r carriage return - \t horizontal tab - \v vertical tab - \xHH hexadecimal values (1 to 2 digits) + -n No trailing newline. + -e Process the following escape sequences: + \\ backslash + \0NNN octal values (1 to 3 digits) + \a alert (beep/flash) + \b backspace + \c stop output here (avoids trailing newline) + \f form feed + \n newline + \r carriage return + \t horizontal tab + \v vertical tab + \xHH hexadecimal values (1 to 2 digits) */ #define FOR_echo @@ -37,58 +35,56 @@ config ECHO void echo_main(void) { - int i = 0, out; - char *arg, *from = "\\abfnrtv", *to = "\\\a\b\f\n\r\t\v", *c; + int i = 0, out; + char *arg, *from = "\\abfnrtv", *to = "\\\a\b\f\n\r\t\v", *c; - for (;;) { - arg = toys.optargs[i]; - if (!arg) break; - if (i++) xputc(' '); + for (;;) { + arg = toys.optargs[i]; + if (!arg) break; + if (i++) xputc(' '); - // Should we output arg verbatim? + // Should we output arg verbatim? - if (!(toys.optflags&FLAG_e)) { - xprintf("%s", arg); - continue; - } + if (!(toys.optflags & FLAG_e)) { + xprintf("%s", arg); + continue; + } - // Handle -e + // Handle -e - for (c=arg;;) { - if (!(out = *(c++))) break; + for (c=arg;;) { + if (!(out = *(c++))) break; - // handle \escapes - if (out == '\\' && *c) { - int n = 0, slash = *(c++); - char *found = strchr(from, slash); - if (found) out = to[found-from]; - else if (slash == 'c') goto done; - else if (slash == '0') { - out = 0; - while (*c>='0' && *c<='7' && n++<3) - out = (out*8)+*(c++)-'0'; - } else if (slash == 'x') { - out = 0; - while (n++<2) { - if (*c>='0' && *c<='9') - out = (out*16)+*(c++)-'0'; - else { - int temp = tolower(*c); - if (temp>='a' && temp<='f') { - out = (out*16)+temp-'a'+10; - c++; - } else break; - } - } - // Slash in front of unknown character, print literal. - } else c--; - } - xputc(out); - } - } + // handle \escapes + if (out == '\\' && *c) { + int n = 0, slash = *(c++); + char *found = strchr(from, slash); + if (found) out = to[found-from]; + else if (slash == 'c') goto done; + else if (slash == '0') { + out = 0; + while (*c>='0' && *c<='7' && n++<3) out = (out*8)+*(c++)-'0'; + } else if (slash == 'x') { + out = 0; + while (n++<2) { + if (*c>='0' && *c<='9') out = (out*16)+*(c++)-'0'; + else { + int temp = tolower(*c); + if (temp>='a' && temp<='f') { + out = (out*16)+temp-'a'+10; + c++; + } else break; + } + } + // Slash in front of unknown character, print literal. + } else c--; + } + xputc(out); + } + } - // Output "\n" if no -n - if (!(toys.optflags&FLAG_n)) xputc('\n'); + // Output "\n" if no -n + if (!(toys.optflags&FLAG_n)) xputc('\n'); done: - xflush(); + xflush(); } diff --git a/toys/posix/env.c b/toys/posix/env.c index 32272799..8f7ccf1f 100644 --- a/toys/posix/env.c +++ b/toys/posix/env.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * env.c - Set the environment for command invocation. +/* env.c - Set the environment for command invocation. * * Copyright 2012 Tryn Mirell <tryn@mirell.org> * @@ -9,14 +7,14 @@ USE_ENV(NEWTOY(env, "^i", TOYFLAG_USR|TOYFLAG_BIN)) config ENV - bool "env" - default y - help - usage: env [-i] [NAME=VALUE...] [command [option...]] + bool "env" + default y + help + usage: env [-i] [NAME=VALUE...] [command [option...]] - Set the environment for command invocation. + Set the environment for command invocation. - -i Clear existing environment. + -i Clear existing environment. */ #include "toys.h" @@ -25,29 +23,29 @@ extern char **environ; void env_main(void) { - char **ev; - char **command = NULL; - char *del = "="; - - if (toys.optflags) clearenv(); - - for (ev = toys.optargs; *ev != NULL; ev++) { - char *env, *val = NULL; - - env = strtok(*ev, del); - - if (env) val = strtok(NULL, del); - - if (val) setenv(env, val, 1); - else { - command = ev; - break; - } + char **ev; + char **command = NULL; + char *del = "="; + + if (toys.optflags) clearenv(); + + for (ev = toys.optargs; *ev != NULL; ev++) { + char *env, *val = NULL; + + env = strtok(*ev, del); + + if (env) val = strtok(NULL, del); + + if (val) setenv(env, val, 1); + else { + command = ev; + break; } - - if (!command) { - char **ep; - for (ep = environ; *ep; ep++) xputs(*ep); - return; - } else xexec(command); + } + + if (!command) { + char **ep; + for (ep = environ; *ep; ep++) xputs(*ep); + return; + } else xexec(command); } diff --git a/toys/posix/false.c b/toys/posix/false.c index 7208ea7a..73458bea 100644 --- a/toys/posix/false.c +++ b/toys/posix/false.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * false.c - Return nonzero. +/* false.c - Return nonzero. * * Copyright 2007 Rob Landley <rob@landley.net> * @@ -9,15 +7,15 @@ USE_FALSE(NEWTOY(false, NULL, TOYFLAG_BIN)) config FALSE - bool "false" - default y - help - Return nonzero. + bool "false" + default y + help + Return nonzero. */ #include "toys.h" void false_main(void) { - toys.exitval = 1; + toys.exitval = 1; } diff --git a/toys/posix/head.c b/toys/posix/head.c index 77978f74..ba7b7385 100644 --- a/toys/posix/head.c +++ b/toys/posix/head.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * head.c - copy first lines from input to stdout. +/* head.c - copy first lines from input to stdout. * * Copyright 2006 Timothy Elliott <tle@holymonkey.com> * @@ -9,52 +7,51 @@ USE_HEAD(NEWTOY(head, "n#<0=10", TOYFLAG_BIN)) config HEAD - bool "head" - default y - help - usage: head [-n number] [file...] + bool "head" + default y + help + usage: head [-n number] [file...] - Copy first lines from files to stdout. If no files listed, copy from - stdin. Filename "-" is a synonym for stdin. + Copy first lines from files to stdout. If no files listed, copy from + stdin. Filename "-" is a synonym for stdin. - -n Number of lines to copy. + -n Number of lines to copy. */ #define FOR_head #include "toys.h" GLOBALS( - long lines; - int file_no; + long lines; + int file_no; ) static void do_head(int fd, char *name) { - int i, len, lines=TT.lines, size=sizeof(toybuf); - - if (toys.optc > 1) { - // Print an extra newline for all but the first file - if (TT.file_no++) xprintf("\n"); - xprintf("==> %s <==\n", name); - xflush(); - } - - while (lines) { - len = read(fd, toybuf, size); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - - for(i=0; i<len;) - if (toybuf[i++] == '\n' && !--lines) break; - - xwrite(1, toybuf, i); - } + int i, len, lines=TT.lines, size=sizeof(toybuf); + + if (toys.optc > 1) { + // Print an extra newline for all but the first file + if (TT.file_no++) xprintf("\n"); + xprintf("==> %s <==\n", name); + xflush(); + } + + while (lines) { + len = read(fd, toybuf, size); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + + for(i=0; i<len;) if (toybuf[i++] == '\n' && !--lines) break; + + xwrite(1, toybuf, i); + } } void head_main(void) { - loopfiles(toys.optargs, do_head); + loopfiles(toys.optargs, do_head); } diff --git a/toys/posix/id.c b/toys/posix/id.c index 523d4f3a..0cdd2b0c 100644 --- a/toys/posix/id.c +++ b/toys/posix/id.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * id.c - print real and effective user and group IDs +/* id.c - print real and effective user and group IDs * * Copyright 2012 Sony Network Entertainment, Inc. * @@ -11,18 +9,18 @@ USE_ID(NEWTOY(id, "nGgru", TOYFLAG_BIN)) config ID - bool "id" - default y - help - usage: id [-nGgru] - - Print user and group ID. - - -n print names instead of numeric IDs (to be used with -Ggu) - -G Show only the group IDs - -g Show only the effective group ID - -r Show real ID instead of effective ID - -u Show only the effective user ID + bool "id" + default y + help + usage: id [-nGgru] + + Print user and group ID. + + -n print names instead of numeric IDs (to be used with -Ggu) + -G Show only the group IDs + -g Show only the effective group ID + -r Show real ID instead of effective ID + -u Show only the effective user ID */ #define FOR_id @@ -30,85 +28,83 @@ config ID static void s_or_u(char *s, unsigned u, int done) { - if (toys.optflags & FLAG_n) printf("%s", s); - else printf("%u", u); - if (done) { - xputc('\n'); - exit(0); - } + if (toys.optflags & FLAG_n) printf("%s", s); + else printf("%u", u); + if (done) { + xputc('\n'); + exit(0); + } } static void showid(char *header, unsigned u, char *s) { - printf("%s%u(%s)", header, u, s); + printf("%s%u(%s)", header, u, s); } struct passwd *xgetpwuid(uid_t uid) { - struct passwd *pwd = getpwuid(uid); - if (!pwd) error_exit(NULL); - return pwd; + struct passwd *pwd = getpwuid(uid); + if (!pwd) error_exit(NULL); + return pwd; } struct group *xgetgrgid(gid_t gid) { - struct group *group = getgrgid(gid); - if (!group) error_exit(NULL); - return group; + struct group *group = getgrgid(gid); + if (!group) error_exit(NULL); + return group; } void id_main(void) { - int flags = toys.optflags, i, ngroups; - struct passwd *pw; - struct group *grp; - uid_t uid = getuid(), euid = geteuid(); - gid_t gid = getgid(), egid = getegid(), *groups; - - /* check if a username is given */ - if (*toys.optargs) { - if (!(pw = getpwnam(*toys.optargs))) - error_exit("no such user '%s'", *toys.optargs); - uid = euid = pw->pw_uid; - gid = egid = pw->pw_gid; - } - - i = toys.optflags & FLAG_r; - pw = xgetpwuid(i ? uid : euid); - if (flags & FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1); - - grp = xgetgrgid(i ? gid : egid); - if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1); - - if (!(flags & FLAG_G)) { - showid("uid=", pw->pw_uid, pw->pw_name); - showid(" gid=", grp->gr_gid, grp->gr_name); - - if (!i) { - if (uid != euid) { - pw = xgetpwuid(euid); - showid(" euid=", pw->pw_uid, pw->pw_name); - } - if (gid != egid) { - grp = xgetgrgid(egid); - showid(" egid=", grp->gr_gid, grp->gr_name); - } - } - - showid(" groups=", grp->gr_gid, grp->gr_name); - } - - - groups = (gid_t *)toybuf; - if (0 >= (ngroups = getgroups(sizeof(toybuf)/sizeof(gid_t), groups))) - perror_exit(0); - - for (i = 0; i < ngroups; i++) { - xputc(' '); - if (!(grp = getgrgid(groups[i]))) perror_msg(0); - else if (flags & FLAG_G) - s_or_u(grp->gr_name, grp->gr_gid, 0); - else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name); - } - xputc('\n'); + int flags = toys.optflags, i, ngroups; + struct passwd *pw; + struct group *grp; + uid_t uid = getuid(), euid = geteuid(); + gid_t gid = getgid(), egid = getegid(), *groups; + + // check if a username is given + if (*toys.optargs) { + if (!(pw = getpwnam(*toys.optargs))) + error_exit("no such user '%s'", *toys.optargs); + uid = euid = pw->pw_uid; + gid = egid = pw->pw_gid; + } + + i = toys.optflags & FLAG_r; + pw = xgetpwuid(i ? uid : euid); + if (flags & FLAG_u) s_or_u(pw->pw_name, pw->pw_uid, 1); + + grp = xgetgrgid(i ? gid : egid); + if (flags & FLAG_g) s_or_u(grp->gr_name, grp->gr_gid, 1); + + if (!(flags & FLAG_G)) { + showid("uid=", pw->pw_uid, pw->pw_name); + showid(" gid=", grp->gr_gid, grp->gr_name); + + if (!i) { + if (uid != euid) { + pw = xgetpwuid(euid); + showid(" euid=", pw->pw_uid, pw->pw_name); + } + if (gid != egid) { + grp = xgetgrgid(egid); + showid(" egid=", grp->gr_gid, grp->gr_name); + } + } + + showid(" groups=", grp->gr_gid, grp->gr_name); + } + + groups = (gid_t *)toybuf; + if (0 >= (ngroups = getgroups(sizeof(toybuf)/sizeof(gid_t), groups))) + perror_exit(0); + + for (i = 0; i < ngroups; i++) { + xputc(' '); + if (!(grp = getgrgid(groups[i]))) perror_msg(0); + else if (flags & FLAG_G) s_or_u(grp->gr_name, grp->gr_gid, 0); + else if (grp->gr_gid != egid) showid("", grp->gr_gid, grp->gr_name); + } + xputc('\n'); } diff --git a/toys/posix/kill.c b/toys/posix/kill.c index 7810b899..2d1606b4 100644 --- a/toys/posix/kill.c +++ b/toys/posix/kill.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * kill.c - a program to send signals to processes +/* kill.c - a program to send signals to processes * * Copyright 2012 Daniel Walter <d.walter@0x90.at> * @@ -9,65 +7,64 @@ USE_KILL(NEWTOY(kill, "?s: l", TOYFLAG_BIN)) config KILL - bool "kill" - default y - help - usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid... - - Send a signal to a process + bool "kill" + default y + help + usage: kill [-l [SIGNAL] | -s SIGNAL | -SIGNAL] pid... + Send a signal to a process */ #define FOR_kill #include "toys.h" GLOBALS( - char *signame; + char *signame; ) void kill_main(void) { - int signum; - char *tmp, **args = toys.optargs; - pid_t pid; + int signum; + char *tmp, **args = toys.optargs; + pid_t pid; - // list signal(s) - if (toys.optflags & FLAG_l) { - if (*args) { - int signum = sig_to_num(*args); - char *s = NULL; + // list signal(s) + if (toys.optflags & FLAG_l) { + if (*args) { + int signum = sig_to_num(*args); + char *s = NULL; - if (signum>=0) s = num_to_sig(signum&127); - puts(s ? s : "UNKNOWN"); - } else sig_to_num(NULL); - return; - } + if (signum>=0) s = num_to_sig(signum&127); + puts(s ? s : "UNKNOWN"); + } else sig_to_num(NULL); + return; + } - // signal must come before pids, so "kill -9 -1" isn't confusing. + // signal must come before pids, so "kill -9 -1" isn't confusing. - if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1; - if (TT.signame) { - char *arg; - int i = strtol(TT.signame, &arg, 10); - if (!*arg) arg = num_to_sig(i); - else arg = TT.signame; + if (!TT.signame && *args && **args=='-') TT.signame=*(args++)+1; + if (TT.signame) { + char *arg; + int i = strtol(TT.signame, &arg, 10); + if (!*arg) arg = num_to_sig(i); + else arg = TT.signame; - if (!arg || -1 == (signum = sig_to_num(arg))) - error_exit("Unknown signal '%s'", arg); - } else signum = SIGTERM; + if (!arg || -1 == (signum = sig_to_num(arg))) + error_exit("Unknown signal '%s'", arg); + } else signum = SIGTERM; - if (!*args) { - toys.exithelp++; - error_exit("missing argument"); - } + if (!*args) { + toys.exithelp++; + error_exit("missing argument"); + } - while (*args) { - char *arg = *(args++); + while (*args) { + char *arg = *(args++); - pid = strtol(arg, &tmp, 10); - if (*tmp || kill(pid, signum) < 0) { - error_msg("unknown pid '%s'", arg); - toys.exitval = EXIT_FAILURE; - } - } + pid = strtol(arg, &tmp, 10); + if (*tmp || kill(pid, signum) < 0) { + error_msg("unknown pid '%s'", arg); + toys.exitval = EXIT_FAILURE; + } + } } diff --git a/toys/posix/link.c b/toys/posix/link.c index 69a9a60f..38d2cf05 100644 --- a/toys/posix/link.c +++ b/toys/posix/link.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * link.c - hardlink a file +/* link.c - hardlink a file * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,19 +7,19 @@ USE_LINK(NEWTOY(link, "<2>2", TOYFLAG_USR|TOYFLAG_BIN)) config LINK - bool "link" - default y - help - usage: link FILE NEWLINK + bool "link" + default y + help + usage: link FILE NEWLINK - Create hardlink to a file. + Create hardlink to a file. */ #include "toys.h" void link_main(void) { - if (link(toys.optargs[0], toys.optargs[1])) - perror_exit("couldn't link '%s' to '%s'", toys.optargs[1], - toys.optargs[0]); + if (link(toys.optargs[0], toys.optargs[1])) + perror_exit("couldn't link '%s' to '%s'", toys.optargs[1], + toys.optargs[0]); } diff --git a/toys/posix/ln.c b/toys/posix/ln.c index a83df7f6..bde77269 100644 --- a/toys/posix/ln.c +++ b/toys/posix/ln.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * ln.c - Create filesystem links +/* ln.c - Create filesystem links * * Copyright 2012 Andre Renaud <andre@bluewatersys.com> * @@ -9,17 +7,17 @@ USE_LN(NEWTOY(ln, "<1nfs", TOYFLAG_BIN)) config LN - bool "ln" - default y - help - usage: ln [-sf] [FROM...] TO + bool "ln" + default y + help + usage: ln [-sf] [FROM...] TO - Create a link between FROM and TO. - With only one argument, create link in current directory. + Create a link between FROM and TO. + With only one argument, create link in current directory. - -s Create a symbolic link - -f Force the creation of the link, even if TO already exists - -n Symlink at destination treated as file + -s Create a symbolic link + -f Force the creation of the link, even if TO already exists + -n Symlink at destination treated as file */ #define FOR_ln @@ -27,41 +25,41 @@ config LN void ln_main(void) { - char *dest = toys.optargs[--toys.optc], *new; - struct stat buf; - int i; + char *dest = toys.optargs[--toys.optc], *new; + struct stat buf; + int i; - // With one argument, create link in current directory. - if (!toys.optc) { - toys.optc++; - dest="."; - } + // With one argument, create link in current directory. + if (!toys.optc) { + toys.optc++; + dest="."; + } - // Is destination a directory? - if (((toys.optflags&FLAG_n) ? lstat : stat)(dest, &buf) - || !S_ISDIR(buf.st_mode)) - { - if (toys.optc>1) error_exit("'%s' not a directory"); - buf.st_mode = 0; - } + // Is destination a directory? + if (((toys.optflags&FLAG_n) ? lstat : stat)(dest, &buf) + || !S_ISDIR(buf.st_mode)) + { + if (toys.optc>1) error_exit("'%s' not a directory"); + buf.st_mode = 0; + } - for (i=0; i<toys.optc; i++) { - int rc; - char *try = toys.optargs[i]; + for (i=0; i<toys.optc; i++) { + int rc; + char *try = toys.optargs[i]; - if (S_ISDIR(buf.st_mode)) { - new = strrchr(try, '/'); - if (!new) new = try; - new = xmsprintf("%s/%s", dest, new); - } else new = dest; - /* Silently unlink the existing target. If it doesn't exist, - * then we just move on */ - if (toys.optflags & FLAG_f) unlink(new); + if (S_ISDIR(buf.st_mode)) { + new = strrchr(try, '/'); + if (!new) new = try; + new = xmsprintf("%s/%s", dest, new); + } else new = dest; + /* Silently unlink the existing target. If it doesn't exist, + * then we just move on */ + if (toys.optflags & FLAG_f) unlink(new); - rc = (toys.optflags & FLAG_s) ? symlink(try, new) : link(try, new); - if (rc) - perror_exit("cannot create %s link from '%s' to '%s'", - (toys.optflags & FLAG_s) ? "symbolic" : "hard", try, new); - if (new != dest) free(new); - } + rc = (toys.optflags & FLAG_s) ? symlink(try, new) : link(try, new); + if (rc) + perror_exit("cannot create %s link from '%s' to '%s'", + (toys.optflags & FLAG_s) ? "symbolic" : "hard", try, new); + if (new != dest) free(new); + } } diff --git a/toys/posix/logname.c b/toys/posix/logname.c index 6ebdb329..b638ea2f 100644 --- a/toys/posix/logname.c +++ b/toys/posix/logname.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * logname.c - Print user's login name. +/* logname.c - Print user's login name. * * Copyright 2012 Elie De Brauwer <eliedebrauwer@gmail.com> * @@ -9,19 +7,19 @@ USE_LOGNAME(NEWTOY(logname, ">0", TOYFLAG_BIN)) config LOGNAME - bool "logname" - default y - help - usage: logname + bool "logname" + default y + help + usage: logname - Prints the calling user's name or an error when this cannot be - determined. + Prints the calling user's name or an error when this cannot be + determined. */ #include "toys.h" void logname_main(void) { - if (getlogin_r(toybuf, sizeof(toybuf))) error_exit("no login name"); - xputs(toybuf); + if (getlogin_r(toybuf, sizeof(toybuf))) error_exit("no login name"); + xputs(toybuf); } diff --git a/toys/posix/ls.c b/toys/posix/ls.c index 6492fb9e..201c7e24 100644 --- a/toys/posix/ls.c +++ b/toys/posix/ls.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * ls.c - list files +/* ls.c - list files * * Copyright 2012 Andre Renaud <andre@bluewatersys.com> * Copyright 2012 Rob Landley <rob@landley.net> @@ -11,43 +9,43 @@ USE_LS(NEWTOY(ls, "goACFHLRSacdfiklmnpqrstux1", TOYFLAG_BIN)) config LS - bool "ls" - default y - help - usage: ls [-ACFHLRSacdfiklmnpqrstux1] [directory...] - list files - - what to show: - -a all files including .hidden - -c use ctime for timestamps - -d directory, not contents - -i inode number - -k block sizes in kilobytes - -p put a '/' after directory names - -q unprintable chars as '?' - -s size (in blocks) - -u use access time for timestamps - -A list all files except . and .. - -H follow command line symlinks - -L follow symlinks - -R recursively list files in subdirectories - -F append file type indicator (/=dir, *=exe, @=symlink, |=FIFO) - - output formats: - -1 list one file per line - -C columns (sorted vertically) - -g like -l but no owner - -l long (show full details for each file) - -m comma separated - -n like -l but numeric uid/gid - -o like -l but no group - -x columns (sorted horizontally) - - sorting (default is alphabetical): - -f unsorted - -r reverse - -t timestamp - -S size + bool "ls" + default y + help + usage: ls [-ACFHLRSacdfiklmnpqrstux1] [directory...] + list files + + what to show: + -a all files including .hidden + -c use ctime for timestamps + -d directory, not contents + -i inode number + -k block sizes in kilobytes + -p put a '/' after directory names + -q unprintable chars as '?' + -s size (in blocks) + -u use access time for timestamps + -A list all files except . and .. + -H follow command line symlinks + -L follow symlinks + -R recursively list files in subdirectories + -F append file type indicator (/=dir, *=exe, @=symlink, |=FIFO) + + output formats: + -1 list one file per line + -C columns (sorted vertically) + -g like -l but no owner + -l long (show full details for each file) + -m comma separated + -n like -l but numeric uid/gid + -o like -l but no group + -x columns (sorted horizontally) + + sorting (default is alphabetical): + -f unsorted + -r reverse + -t timestamp + -S size */ #define FOR_ls @@ -58,156 +56,156 @@ config LS // ls -lR starts .: then ./subdir: GLOBALS( - struct dirtree *files; + struct dirtree *files; - unsigned screen_width; - int nl_title; + unsigned screen_width; + int nl_title; - // group and user can make overlapping use of the utoa() buf, so move it - char uid_buf[12]; + // group and user can make overlapping use of the utoa() buf, so move it + char uid_buf[12]; ) void dlist_to_dirtree(struct dirtree *parent) { - // Turn double_list into dirtree - struct dirtree *dt = parent->child; - if (dt) { - dt->parent->next = NULL; - while (dt) { - dt->parent = parent; - dt = dt->next; - } + // Turn double_list into dirtree + struct dirtree *dt = parent->child; + if (dt) { + dt->parent->next = NULL; + while (dt) { + dt->parent = parent; + dt = dt->next; } + } } static char endtype(struct stat *st) { - mode_t mode = st->st_mode; - if ((toys.optflags&(FLAG_F|FLAG_p)) && S_ISDIR(mode)) return '/'; - if (toys.optflags & FLAG_F) { - if (S_ISLNK(mode)) return '@'; - if (S_ISREG(mode) && (mode&0111)) return '*'; - if (S_ISFIFO(mode)) return '|'; - if (S_ISSOCK(mode)) return '='; - } - return 0; + mode_t mode = st->st_mode; + if ((toys.optflags&(FLAG_F|FLAG_p)) && S_ISDIR(mode)) return '/'; + if (toys.optflags & FLAG_F) { + if (S_ISLNK(mode)) return '@'; + if (S_ISREG(mode) && (mode&0111)) return '*'; + if (S_ISFIFO(mode)) return '|'; + if (S_ISSOCK(mode)) return '='; + } + return 0; } static char *getusername(uid_t uid) { - struct passwd *pw = getpwuid(uid); - utoa_to_buf(uid, TT.uid_buf, 12); - return pw ? pw->pw_name : TT.uid_buf; + struct passwd *pw = getpwuid(uid); + utoa_to_buf(uid, TT.uid_buf, 12); + return pw ? pw->pw_name : TT.uid_buf; } static char *getgroupname(gid_t gid) { - struct group *gr = getgrgid(gid); - return gr ? gr->gr_name : utoa(gid); + struct group *gr = getgrgid(gid); + return gr ? gr->gr_name : utoa(gid); } // Figure out size of printable entry fields for display indent/wrap static void entrylen(struct dirtree *dt, unsigned *len) { - struct stat *st = &(dt->st); - unsigned flags = toys.optflags; - - *len = strlen(dt->name); - if (endtype(st)) ++*len; - if (flags & FLAG_m) ++*len; - - if (flags & FLAG_i) *len += (len[1] = numlen(st->st_ino)); - if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { - unsigned fn = flags & FLAG_n; - len[2] = numlen(st->st_nlink); - len[3] = strlen(fn ? utoa(st->st_uid) : getusername(st->st_uid)); - len[4] = strlen(fn ? utoa(st->st_gid) : getgroupname(st->st_gid)); - len[5] = numlen(st->st_size); - } - if (flags & FLAG_s) *len += (len[6] = numlen(st->st_blocks)); + struct stat *st = &(dt->st); + unsigned flags = toys.optflags; + + *len = strlen(dt->name); + if (endtype(st)) ++*len; + if (flags & FLAG_m) ++*len; + + if (flags & FLAG_i) *len += (len[1] = numlen(st->st_ino)); + if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { + unsigned fn = flags & FLAG_n; + len[2] = numlen(st->st_nlink); + len[3] = strlen(fn ? utoa(st->st_uid) : getusername(st->st_uid)); + len[4] = strlen(fn ? utoa(st->st_gid) : getgroupname(st->st_gid)); + len[5] = numlen(st->st_size); + } + if (flags & FLAG_s) *len += (len[6] = numlen(st->st_blocks)); } static int compare(void *a, void *b) { - struct dirtree *dta = *(struct dirtree **)a; - struct dirtree *dtb = *(struct dirtree **)b; - int ret = 0, reverse = (toys.optflags & FLAG_r) ? -1 : 1; - - if (toys.optflags & FLAG_S) { - if (dta->st.st_size > dtb->st.st_size) ret = -1; - else if (dta->st.st_size < dtb->st.st_size) ret = 1; - } - if (toys.optflags & FLAG_t) { - if (dta->st.st_mtime > dtb->st.st_mtime) ret = -1; - else if (dta->st.st_mtime < dtb->st.st_mtime) ret = 1; - } - if (!ret) ret = strcmp(dta->name, dtb->name); - return ret * reverse; + struct dirtree *dta = *(struct dirtree **)a; + struct dirtree *dtb = *(struct dirtree **)b; + int ret = 0, reverse = (toys.optflags & FLAG_r) ? -1 : 1; + + if (toys.optflags & FLAG_S) { + if (dta->st.st_size > dtb->st.st_size) ret = -1; + else if (dta->st.st_size < dtb->st.st_size) ret = 1; + } + if (toys.optflags & FLAG_t) { + if (dta->st.st_mtime > dtb->st.st_mtime) ret = -1; + else if (dta->st.st_mtime < dtb->st.st_mtime) ret = 1; + } + if (!ret) ret = strcmp(dta->name, dtb->name); + return ret * reverse; } // callback from dirtree_recurse() determining how to handle this entry. static int filter(struct dirtree *new) { - int flags = toys.optflags; + int flags = toys.optflags; - // Special case to handle enormous dirs without running out of memory. - if (flags == (FLAG_1|FLAG_f)) { - xprintf("%s\n", new->name); - return 0; - } + // Special case to handle enormous dirs without running out of memory. + if (flags == (FLAG_1|FLAG_f)) { + xprintf("%s\n", new->name); + return 0; + } - if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime; - if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime; - if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2; + if (flags & FLAG_u) new->st.st_mtime = new->st.st_atime; + if (flags & FLAG_c) new->st.st_mtime = new->st.st_ctime; + if (flags & FLAG_k) new->st.st_blocks = (new->st.st_blocks + 1) / 2; - if (flags & (FLAG_a|FLAG_f)) return DIRTREE_SAVE; - if (!(flags & FLAG_A) && new->name[0]=='.') return 0; + if (flags & (FLAG_a|FLAG_f)) return DIRTREE_SAVE; + if (!(flags & FLAG_A) && new->name[0]=='.') return 0; - return dirtree_notdotdot(new) & DIRTREE_SAVE; + return dirtree_notdotdot(new) & DIRTREE_SAVE; } // For column view, calculate horizontal position (for padding) and return // index of next entry to display. static unsigned long next_column(unsigned long ul, unsigned long dtlen, - unsigned columns, unsigned *xpos) + unsigned columns, unsigned *xpos) { - unsigned long transition; - unsigned height, widecols; + unsigned long transition; + unsigned height, widecols; - // Horizontal sort is easy - if (!(toys.optflags & FLAG_C)) { - *xpos = ul % columns; - return ul; - } + // Horizontal sort is easy + if (!(toys.optflags & FLAG_C)) { + *xpos = ul % columns; + return ul; + } - // vertical sort + // vertical sort - // For -x, calculate height of display, rounded up - height = (dtlen+columns-1)/columns; + // For -x, calculate height of display, rounded up + height = (dtlen+columns-1)/columns; - // Sanity check: does wrapping render this column count impossible - // due to the right edge wrapping eating a whole row? - if (height*columns - dtlen >= height) { - *xpos = columns; - return 0; - } + // Sanity check: does wrapping render this column count impossible + // due to the right edge wrapping eating a whole row? + if (height*columns - dtlen >= height) { + *xpos = columns; + return 0; + } - // Uneven rounding goes along right edge - widecols = dtlen % height; - if (!widecols) widecols = height; - transition = widecols * columns; - if (ul < transition) { - *xpos = ul % columns; - return (*xpos*height) + (ul/columns); - } + // Uneven rounding goes along right edge + widecols = dtlen % height; + if (!widecols) widecols = height; + transition = widecols * columns; + if (ul < transition) { + *xpos = ul % columns; + return (*xpos*height) + (ul/columns); + } - ul -= transition; - *xpos = ul % (columns-1); + ul -= transition; + *xpos = ul % (columns-1); - return (*xpos*height) + widecols + (ul/(columns-1)); + return (*xpos*height) + widecols + (ul/(columns-1)); } // Display a list of dirtree entries, according to current format @@ -215,250 +213,247 @@ static unsigned long next_column(unsigned long ul, unsigned long dtlen, static void listfiles(int dirfd, struct dirtree *indir) { - struct dirtree *dt, **sort = 0; - unsigned long dtlen = 0, ul = 0; - unsigned width, flags = toys.optflags, totals[7], len[7], - *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; - - memset(totals, 0, sizeof(totals)); - - // Silently descend into single directory listed by itself on command line. - // In this case only show dirname/total header when given -R. - if (!indir->parent) { - if (!(dt = indir->child)) return; - if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags & FLAG_d)) { - dt->extra = 1; - listfiles(open(dt->name, 0), dt); - return; - } - } else { - // Read directory contents. We dup() the fd because this will close it. - indir->data = dup(dirfd); - dirtree_recurse(indir, filter, (flags&FLAG_L)); + struct dirtree *dt, **sort = 0; + unsigned long dtlen = 0, ul = 0; + unsigned width, flags = toys.optflags, totals[7], len[7], + *colsizes = (unsigned *)(toybuf+260), columns = (sizeof(toybuf)-260)/4; + + memset(totals, 0, sizeof(totals)); + + // Silently descend into single directory listed by itself on command line. + // In this case only show dirname/total header when given -R. + if (!indir->parent) { + if (!(dt = indir->child)) return; + if (S_ISDIR(dt->st.st_mode) && !dt->next && !(flags & FLAG_d)) { + dt->extra = 1; + listfiles(open(dt->name, 0), dt); + return; } - - // Copy linked list to array and sort it. Directories go in array because - // we visit them in sorted order. - - for (;;) { - for (dt = indir->child; dt; dt = dt->next) { - if (sort) sort[dtlen] = dt; - dtlen++; + } else { + // Read directory contents. We dup() the fd because this will close it. + indir->data = dup(dirfd); + dirtree_recurse(indir, filter, (flags&FLAG_L)); + } + + // Copy linked list to array and sort it. Directories go in array because + // we visit them in sorted order. + + for (;;) { + for (dt = indir->child; dt; dt = dt->next) { + if (sort) sort[dtlen] = dt; + dtlen++; + } + if (sort) break; + sort = xmalloc(dtlen * sizeof(void *)); + dtlen = 0; + continue; + } + + // Label directory if not top of tree, or if -R + if (indir->parent && (!indir->extra || (flags & FLAG_R))) + { + char *path = dirtree_path(indir, 0); + + if (TT.nl_title++) xputc('\n'); + xprintf("%s:\n", path); + free(path); + } + + if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare); + + // Find largest entry in each field for display alignment + if (flags & (FLAG_C|FLAG_x)) { + + // columns can't be more than toybuf can hold, or more than files, + // or > 1/2 screen width (one char filename, one space). + if (columns > TT.screen_width/2) columns = TT.screen_width/2; + if (columns > dtlen) columns = dtlen; + + // Try to fit as many columns as we can, dropping down by one each time + for (;columns > 1; columns--) { + unsigned c, totlen = columns; + + memset(colsizes, 0, columns*sizeof(unsigned)); + for (ul=0; ul<dtlen; ul++) { + entrylen(sort[next_column(ul, dtlen, columns, &c)], len); + if (c == columns) break; + // Does this put us over budget? + if (*len > colsizes[c]) { + totlen += *len-colsizes[c]; + colsizes[c] = *len; + if (totlen > TT.screen_width) break; } - if (sort) break; - sort = xmalloc(dtlen * sizeof(void *)); - dtlen = 0; - continue; + } + // If it fit, stop here + if (ul == dtlen) break; } + } else if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) { + unsigned long blocks = 0; - // Label directory if not top of tree, or if -R - if (indir->parent && (!indir->extra || (flags & FLAG_R))) + for (ul = 0; ul<dtlen; ul++) { - char *path = dirtree_path(indir, 0); - - if (TT.nl_title++) xputc('\n'); - xprintf("%s:\n", path); - free(path); + entrylen(sort[ul], len); + for (width=0; width<6; width++) + if (len[width] > totals[width]) totals[width] = len[width]; + blocks += sort[ul]->st.st_blocks; } - if (!(flags & FLAG_f)) qsort(sort, dtlen, sizeof(void *), (void *)compare); + if (indir->parent) xprintf("total %lu\n", blocks); + } - // Find largest entry in each field for display alignment - if (flags & (FLAG_C|FLAG_x)) { + // Loop through again to produce output. + memset(toybuf, ' ', 256); + width = 0; + for (ul = 0; ul<dtlen; ul++) { + unsigned curcol; + unsigned long next = next_column(ul, dtlen, columns, &curcol); + struct stat *st = &(sort[next]->st); + mode_t mode = st->st_mode; + char et = endtype(st); + + // Skip directories at the top of the tree when -d isn't set + if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; + TT.nl_title=1; + + // Handle padding and wrapping for display purposes + entrylen(sort[next], len); + if (ul) { + if (flags & FLAG_m) xputc(','); + if (flags & (FLAG_C|FLAG_x)) { + if (!curcol) xputc('\n'); + } else if ((flags & FLAG_1) || width+1+*len > TT.screen_width) { + xputc('\n'); + width = 0; + } else { + xputc(' '); + width++; + } + } + width += *len; - // columns can't be more than toybuf can hold, or more than files, - // or > 1/2 screen width (one char filename, one space). - if (columns > TT.screen_width/2) columns = TT.screen_width/2; - if (columns > dtlen) columns = dtlen; - - // Try to fit as many columns as we can, dropping down by one each time - for (;columns > 1; columns--) { - unsigned c, totlen = columns; - - memset(colsizes, 0, columns*sizeof(unsigned)); - for (ul=0; ul<dtlen; ul++) { - entrylen(sort[next_column(ul, dtlen, columns, &c)], len); - if (c == columns) break; - // Does this put us over budget? - if (*len > colsizes[c]) { - totlen += *len-colsizes[c]; - colsizes[c] = *len; - if (totlen > TT.screen_width) break; - } - } - // If it fit, stop here - if (ul == dtlen) break; - } - } else if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g|FLAG_s)) { - unsigned long blocks = 0; - - for (ul = 0; ul<dtlen; ul++) - { - entrylen(sort[ul], len); - for (width=0; width<6; width++) - if (len[width] > totals[width]) totals[width] = len[width]; - blocks += sort[ul]->st.st_blocks; - } + if (flags & FLAG_i) xprintf("% *lu ", len[1], (unsigned long)st->st_ino); + if (flags & FLAG_s) xprintf("% *lu ", len[6], (unsigned long)st->st_blocks); - if (indir->parent) xprintf("total %lu\n", blocks); + if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { + struct tm *tm; + char perm[11], thyme[64], c, d, *usr, *upad, *grp, *grpad; + int i, bit; + + perm[10]=0; + for (i=0; i<9; i++) { + bit = mode & (1<<i); + c = i%3; + if (!c && (mode & (1<<((d=i/3)+9)))) { + c = "tss"[d]; + if (!bit) c &= ~0x20; + } else c = bit ? "xwr"[c] : '-'; + perm[9-i] = c; + } + + if (S_ISDIR(mode)) c = 'd'; + else if (S_ISBLK(mode)) c = 'b'; + else if (S_ISCHR(mode)) c = 'c'; + else if (S_ISLNK(mode)) c = 'l'; + else if (S_ISFIFO(mode)) c = 'p'; + else if (S_ISSOCK(mode)) c = 's'; + else c = '-'; + *perm = c; + + tm = localtime(&(st->st_mtime)); + strftime(thyme, sizeof(thyme), "%F %H:%M", tm); + + if (flags&FLAG_o) grp = grpad = toybuf+256; + else { + grp = (flags&FLAG_n) ? utoa(st->st_gid) : getgroupname(st->st_gid); + grpad = toybuf+256-(totals[4]-len[4]); + } + + if (flags&FLAG_g) usr = upad = toybuf+256; + else { + upad = toybuf+255-(totals[3]-len[3]); + if (flags&FLAG_n) { + usr = TT.uid_buf; + utoa_to_buf(st->st_uid, TT.uid_buf, 12); + } else usr = getusername(st->st_uid); + } + + // Coerce the st types into something we know we can print. + xprintf("%s% *ld %s%s%s%s% *"PRId64" %s ", perm, totals[2]+1, + (long)st->st_nlink, usr, upad, grp, grpad, totals[5]+1, + (int64_t)st->st_size, thyme); } - // Loop through again to produce output. - memset(toybuf, ' ', 256); - width = 0; - for (ul = 0; ul<dtlen; ul++) { - unsigned curcol; - unsigned long next = next_column(ul, dtlen, columns, &curcol); - struct stat *st = &(sort[next]->st); - mode_t mode = st->st_mode; - char et = endtype(st); - - // Skip directories at the top of the tree when -d isn't set - if (S_ISDIR(mode) && !indir->parent && !(flags & FLAG_d)) continue; - TT.nl_title=1; - - // Handle padding and wrapping for display purposes - entrylen(sort[next], len); - if (ul) { - if (flags & FLAG_m) xputc(','); - if (flags & (FLAG_C|FLAG_x)) { - if (!curcol) xputc('\n'); - } else if ((flags & FLAG_1) || width+1+*len > TT.screen_width) { - xputc('\n'); - width = 0; - } else { - xputc(' '); - width++; - } - } - width += *len; - - if (flags & FLAG_i) - xprintf("% *lu ", len[1], (unsigned long)st->st_ino); - if (flags & FLAG_s) - xprintf("% *lu ", len[6], (unsigned long)st->st_blocks); - - if (flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) { - struct tm *tm; - char perm[11], thyme[64], c, d, *usr, *upad, *grp, *grpad; - int i, bit; - - perm[10]=0; - for (i=0; i<9; i++) { - bit = mode & (1<<i); - c = i%3; - if (!c && (mode & (1<<((d=i/3)+9)))) { - c = "tss"[d]; - if (!bit) c &= ~0x20; - } else c = bit ? "xwr"[c] : '-'; - perm[9-i] = c; - } - - if (S_ISDIR(mode)) c = 'd'; - else if (S_ISBLK(mode)) c = 'b'; - else if (S_ISCHR(mode)) c = 'c'; - else if (S_ISLNK(mode)) c = 'l'; - else if (S_ISFIFO(mode)) c = 'p'; - else if (S_ISSOCK(mode)) c = 's'; - else c = '-'; - *perm = c; - - tm = localtime(&(st->st_mtime)); - strftime(thyme, sizeof(thyme), "%F %H:%M", tm); - - if (flags&FLAG_o) grp = grpad = toybuf+256; - else { - grp = (flags&FLAG_n) ? utoa(st->st_gid) - : getgroupname(st->st_gid); - grpad = toybuf+256-(totals[4]-len[4]); - } - - if (flags&FLAG_g) usr = upad = toybuf+256; - else { - upad = toybuf+255-(totals[3]-len[3]); - if (flags&FLAG_n) { - usr = TT.uid_buf; - utoa_to_buf(st->st_uid, TT.uid_buf, 12); - } else usr = getusername(st->st_uid); - } - - // Coerce the st types into something we know we can print. - xprintf("%s% *ld %s%s%s%s% *"PRId64" %s ", perm, totals[2]+1, - (long)st->st_nlink, usr, upad, grp, grpad, totals[5]+1, - (int64_t)st->st_size, thyme); - } + if (flags & FLAG_q) { + char *p; + for (p=sort[next]->name; *p; p++) xputc(isprint(*p) ? *p : '?'); + } else xprintf("%s", sort[next]->name); + if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) + xprintf(" -> %s", sort[next]->symlink); - if (flags & FLAG_q) { - char *p; - for (p=sort[next]->name; *p; p++) xputc(isprint(*p) ? *p : '?'); - } else xprintf("%s", sort[next]->name); - if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) - xprintf(" -> %s", sort[next]->symlink); + if (et) xputc(et); - if (et) xputc(et); - - // Pad columns - if (flags & (FLAG_C|FLAG_x)) { - curcol = colsizes[curcol] - *len; - if (curcol >= 0) xprintf("%s", toybuf+255-curcol); - } + // Pad columns + if (flags & (FLAG_C|FLAG_x)) { + curcol = colsizes[curcol] - *len; + if (curcol >= 0) xprintf("%s", toybuf+255-curcol); } + } - if (width) xputc('\n'); + if (width) xputc('\n'); - // Free directory entries, recursing first if necessary. + // Free directory entries, recursing first if necessary. - for (ul = 0; ul<dtlen; free(sort[ul++])) { - if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode) - || !dirtree_notdotdot(sort[ul])) continue; + for (ul = 0; ul<dtlen; free(sort[ul++])) { + if ((flags & FLAG_d) || !S_ISDIR(sort[ul]->st.st_mode) + || !dirtree_notdotdot(sort[ul])) continue; - // Recurse into dirs if at top of the tree or given -R - if (!indir->parent || (flags & FLAG_R)) - listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]); - } - free(sort); - if (dirfd != AT_FDCWD) close(indir->data); + // Recurse into dirs if at top of the tree or given -R + if (!indir->parent || (flags & FLAG_R)) + listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]); + } + free(sort); + if (dirfd != AT_FDCWD) close(indir->data); } void ls_main(void) { - char **s, *noargs[] = {".", 0}; - struct dirtree *dt; - - // Do we have an implied -1 - if (!isatty(1) || (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g))) - toys.optflags |= FLAG_1; - else { - TT.screen_width = 80; - terminal_size(&TT.screen_width, NULL); + char **s, *noargs[] = {".", 0}; + struct dirtree *dt; + + // Do we have an implied -1 + if (!isatty(1) || (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g))) + toys.optflags |= FLAG_1; + else { + TT.screen_width = 80; + terminal_size(&TT.screen_width, NULL); + } + // The optflags parsing infrastructure should really do this for us, + // but currently it has "switch off when this is set", so "-dR" and "-Rd" + // behave differently + if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R; + + // Iterate through command line arguments, collecting directories and files. + // Non-absolute paths are relative to current directory. + TT.files = dirtree_add_node(0, 0, 0); + for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { + dt = dirtree_add_node(AT_FDCWD, *s, + (toys.optflags & (FLAG_L|FLAG_H|FLAG_l))^FLAG_l); + + if (!dt) { + toys.exitval = 1; + continue; } - // The optflags parsing infrastructure should really do this for us, - // but currently it has "switch off when this is set", so "-dR" and "-Rd" - // behave differently - if (toys.optflags & FLAG_d) toys.optflags &= ~FLAG_R; - - // Iterate through command line arguments, collecting directories and files. - // Non-absolute paths are relative to current directory. - TT.files = dirtree_add_node(0, 0, 0); - for (s = *toys.optargs ? toys.optargs : noargs; *s; s++) { - dt = dirtree_add_node(AT_FDCWD, *s, - (toys.optflags & (FLAG_L|FLAG_H|FLAG_l))^FLAG_l); - - if (!dt) { - toys.exitval = 1; - continue; - } - // Typecast means double_list->prev temporarirly goes in dirtree->parent - dlist_add_nomalloc((struct double_list **)&TT.files->child, - (struct double_list *)dt); - } + // Typecast means double_list->prev temporarirly goes in dirtree->parent + dlist_add_nomalloc((struct double_list **)&TT.files->child, + (struct double_list *)dt); + } - // Turn double_list into dirtree - dlist_to_dirtree(TT.files); + // Turn double_list into dirtree + dlist_to_dirtree(TT.files); - // Display the files we collected - listfiles(AT_FDCWD, TT.files); + // Display the files we collected + listfiles(AT_FDCWD, TT.files); - if (CFG_TOYBOX_FREE) free(TT.files); + if (CFG_TOYBOX_FREE) free(TT.files); } diff --git a/toys/posix/mkdir.c b/toys/posix/mkdir.c index e4e591d7..33fb8326 100644 --- a/toys/posix/mkdir.c +++ b/toys/posix/mkdir.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * mkdir.c - Make directories +/* mkdir.c - Make directories * * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> * @@ -11,65 +9,65 @@ USE_MKDIR(NEWTOY(mkdir, "<1p", TOYFLAG_BIN)) config MKDIR - bool "mkdir" - default y - help - usage: mkdir [-p] [dirname...] - Create one or more directories. + bool "mkdir" + default y + help + usage: mkdir [-p] [dirname...] + Create one or more directories. - -p make parent directories as needed. + -p make parent directories as needed. */ #define FOR_mkdir #include "toys.h" GLOBALS( - long mode; + long mode; ) static int do_mkdir(char *dir) { - struct stat buf; - char *s; + struct stat buf; + char *s; - // mkdir -p one/two/three is not an error if the path already exists, - // but is if "three" is a file. The others we dereference and catch - // not-a-directory along the way, but the last one we must explicitly - // test for. Might as well do it up front. + // mkdir -p one/two/three is not an error if the path already exists, + // but is if "three" is a file. The others we dereference and catch + // not-a-directory along the way, but the last one we must explicitly + // test for. Might as well do it up front. - if (!stat(dir, &buf) && !S_ISDIR(buf.st_mode)) { - errno = EEXIST; - return 1; - } + if (!stat(dir, &buf) && !S_ISDIR(buf.st_mode)) { + errno = EEXIST; + return 1; + } - for (s=dir; ; s++) { - char save=0; + for (s=dir; ; s++) { + char save=0; - // Skip leading / of absolute paths. - if (s!=dir && *s == '/' && toys.optflags) { - save = *s; - *s = 0; - } else if (*s) continue; + // Skip leading / of absolute paths. + if (s!=dir && *s == '/' && toys.optflags) { + save = *s; + *s = 0; + } else if (*s) continue; - if (mkdir(dir, TT.mode)<0 && (!toys.optflags || errno != EEXIST)) - return 1; + if (mkdir(dir, TT.mode)<0 && (!toys.optflags || errno != EEXIST)) + return 1; - if (!(*s = save)) break; - } + if (!(*s = save)) break; + } - return 0; + return 0; } void mkdir_main(void) { - char **s; + char **s; - TT.mode = 0777; + TT.mode = 0777; - for (s=toys.optargs; *s; s++) { - if (do_mkdir(*s)) { - perror_msg("cannot create directory '%s'", *s); - toys.exitval = 1; - } - } + for (s=toys.optargs; *s; s++) { + if (do_mkdir(*s)) { + perror_msg("cannot create directory '%s'", *s); + toys.exitval = 1; + } + } } diff --git a/toys/posix/mkfifo.c b/toys/posix/mkfifo.c index 44775788..44fbc994 100644 --- a/toys/posix/mkfifo.c +++ b/toys/posix/mkfifo.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * mkfifo.c - Create FIFOs (named pipes) +/* mkfifo.c - Create FIFOs (named pipes) * * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> * @@ -11,35 +9,35 @@ USE_MKFIFO(NEWTOY(mkfifo, "<1m:", TOYFLAG_BIN)) config MKFIFO - bool "mkfifo" - default y - help - usage: mkfifo [fifo_name...] + bool "mkfifo" + default y + help + usage: mkfifo [fifo_name...] - Create FIFOs (named pipes). + Create FIFOs (named pipes). */ #define FOR_mkfifo #include "toys.h" GLOBALS( - char *m_string; - mode_t mode; + char *m_string; + mode_t mode; ) void mkfifo_main(void) { - char **s; - - TT.mode = 0666; - if (toys.optflags & FLAG_m) { - TT.mode = string_to_mode(TT.m_string, 0); - } - - for (s = toys.optargs; *s; s++) { - if (mknod(*s, S_IFIFO | TT.mode, 0) < 0) { - perror_msg("cannot create fifo '%s'", *s); - toys.exitval = 1; - } - } + char **s; + + TT.mode = 0666; + if (toys.optflags & FLAG_m) { + TT.mode = string_to_mode(TT.m_string, 0); + } + + for (s = toys.optargs; *s; s++) { + if (mknod(*s, S_IFIFO | TT.mode, 0) < 0) { + perror_msg("cannot create fifo '%s'", *s); + toys.exitval = 1; + } + } } diff --git a/toys/posix/nice.c b/toys/posix/nice.c index d45429f8..4b587ee6 100644 --- a/toys/posix/nice.c +++ b/toys/posix/nice.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * nice.c - Run a program at a different niceness level. +/* nice.c - Run a program at a different niceness level. * * Copyright 2010 Rob Landley <rob@landley.net> * @@ -9,32 +7,32 @@ USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_USR|TOYFLAG_BIN)) config NICE - bool "nice" - default y - help - usage: nice [-n PRIORITY] command [args...] + bool "nice" + default y + help + usage: nice [-n PRIORITY] command [args...] - Run a command line at an increased or decreased scheduling priority. + Run a command line at an increased or decreased scheduling priority. - Higher numbers make a program yield more CPU time, from -20 (highest - priority) to 19 (lowest). By default processes inherit their parent's - niceness (usually 0). By default this command adds 10 to the parent's - priority. Only root can set a negative niceness level. + Higher numbers make a program yield more CPU time, from -20 (highest + priority) to 19 (lowest). By default processes inherit their parent's + niceness (usually 0). By default this command adds 10 to the parent's + priority. Only root can set a negative niceness level. */ #define FOR_nice #include "toys.h" GLOBALS( - long priority; + long priority; ) void nice_main(void) { - if (!toys.optflags) TT.priority = 10; + if (!toys.optflags) TT.priority = 10; - errno = 0; - if (nice(TT.priority)==-1 && errno) perror_exit("Can't set priority"); + errno = 0; + if (nice(TT.priority)==-1 && errno) perror_exit("Can't set priority"); - xexec(toys.optargs); + xexec(toys.optargs); } diff --git a/toys/posix/nohup.c b/toys/posix/nohup.c index e11fb094..b936a093 100644 --- a/toys/posix/nohup.c +++ b/toys/posix/nohup.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * nohup.c - run commandline with SIGHUP blocked. +/* nohup.c - run commandline with SIGHUP blocked. * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,34 +7,34 @@ USE_NOHUP(NEWTOY(nohup, "<1", TOYFLAG_USR|TOYFLAG_BIN)) config NOHUP - bool "nohup" - default y - help - usage: nohup COMMAND [ARGS...] + bool "nohup" + default y + help + usage: nohup COMMAND [ARGS...] - Run a command that survives the end of its terminal. - If stdin is a tty, redirect from /dev/null - If stdout is a tty, redirect to file "nohup.out" + Run a command that survives the end of its terminal. + If stdin is a tty, redirect from /dev/null + If stdout is a tty, redirect to file "nohup.out" */ #include "toys.h" void nohup_main(void) { - signal(SIGHUP, SIG_IGN); - if (isatty(1)) { - close(1); - if (-1 == open("nohup.out", O_CREAT|O_APPEND|O_WRONLY, - S_IRUSR|S_IWUSR )) - { - char *temp = getenv("HOME"); - temp = xmsprintf("%s/%s", temp ? temp : "", "nohup.out"); - xcreate(temp, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR); - } - } - if (isatty(0)) { - close(0); - open("/dev/null", O_RDONLY); - } - xexec(toys.optargs); + signal(SIGHUP, SIG_IGN); + if (isatty(1)) { + close(1); + if (-1 == open("nohup.out", O_CREAT|O_APPEND|O_WRONLY, + S_IRUSR|S_IWUSR )) + { + char *temp = getenv("HOME"); + temp = xmsprintf("%s/%s", temp ? temp : "", "nohup.out"); + xcreate(temp, O_CREAT|O_APPEND|O_WRONLY, S_IRUSR|S_IWUSR); + } + } + if (isatty(0)) { + close(0); + open("/dev/null", O_RDONLY); + } + xexec(toys.optargs); } diff --git a/toys/posix/od.c b/toys/posix/od.c index ef420b87..948a99e1 100644 --- a/toys/posix/od.c +++ b/toys/posix/od.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * od.c - Provide octal/hex dumps of data +/* od.c - Provide octal/hex dumps of data * * Copyright 2012 Andre Renaud <andre@bluewatersys.com> * Copyright 2012 Rob Landley <rob@landley.net> @@ -10,253 +8,253 @@ USE_OD(NEWTOY(od, "j#vN#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN)) config OD - bool "od" - default y - help - usage: od [-bdosxv] [-j #] [-N #] [-A doxn] [-t arg] + bool "od" + default y + help + usage: od [-bdosxv] [-j #] [-N #] [-A doxn] [-t arg] - -A Address base (decimal, octal, hexdecimal, none) - -t output type(s) a (ascii) c (char) d (decimal) foux + -A Address base (decimal, octal, hexdecimal, none) + -t output type(s) a (ascii) c (char) d (decimal) foux */ #define FOR_od #include "toys.h" GLOBALS( - struct arg_list *output_base; - char *address_base; - long max_count; - long jump_bytes; - - unsigned types, leftover, star, address_idx; - char *buf; - uint64_t bufs[4]; // force 64-bit alignment - off_t pos; + struct arg_list *output_base; + char *address_base; + long max_count; + long jump_bytes; + + unsigned types, leftover, star, address_idx; + char *buf; + uint64_t bufs[4]; // force 64-bit alignment + off_t pos; ) static char *ascii = "nulsohstxetxeotenqackbel bs ht nl vt ff cr so si" - "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp"; + "dledc1dc2dc3dc4naksynetbcan emsubesc fs gs rs us sp"; struct odtype { - int type; - int size; + int type; + int size; }; static void od_outline(void) { - unsigned flags = toys.optflags; - char *abases[] = {"", "%07d", "%07o", "%06x"}; - struct odtype *types = (struct odtype *)toybuf, *t; - int i, len; - - if (TT.leftover<16) memset(TT.buf+TT.leftover, 0, 16-TT.leftover); - - // Handle duplciate lines as * - if (!(flags&FLAG_v) && TT.jump_bytes != TT.pos && TT.leftover - && !memcmp(TT.bufs, TT.bufs + 2, 16)) - { - if (!TT.star) { - xputs("*"); - TT.star++; - } - - // Print line position - } else { - TT.star = 0; - - xprintf(abases[TT.address_idx], TT.pos); - if (!TT.leftover) { - if (TT.address_idx) xputc('\n'); - return; - } - } - - TT.pos += len = TT.leftover; - TT.leftover = 0; - if (TT.star) return; - - // For each output type, print one line - - for (i=0; i<TT.types; i++) { - int j = 0, pad = i ? 8 : 0; - char buf[128]; - - t = types+i; - while (j<len) { - unsigned k; - int throw = 0; - - // Handle ascii - if (t->type < 2) { - char c = TT.buf[j++]; - pad += 4; - - if (!t->type) { - c &= 127; - if (c<=32) sprintf(buf, "%.3s", ascii+(3*c)); - else if (c==127) strcpy(buf, "del"); - else sprintf(buf, "%c", c); - } else { - char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c); - if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]); - else if (c < 32 || c >= 127) sprintf(buf, "%03o", c); - else { - // TODO: this should be UTF8 aware. - sprintf(buf, "%c", c); - } - } - } else if (CFG_TOYBOX_FLOAT && t->type == 6) { - long double ld; - union {float f; double d; long double ld;} fdl; - - memcpy(&fdl, TT.buf+j, t->size); - j += t->size; - if (sizeof(float) == t->size) { - ld = fdl.f; - pad += (throw = 8)+7; - } else if (sizeof(double) == t->size) { - ld = fdl.d; - pad += (throw = 17)+8; - } else if (sizeof(long double) == t->size) { - ld = fdl.ld; - pad += (throw = 21)+9; - } else error_exit("bad -tf '%d'", t->size); - - sprintf(buf, "%.*Le", throw, ld); - // Integer types - } else { - unsigned long long ll = 0, or; - char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"}, - *class = c[t->type-2]; - - // Work out width of field - if (t->size == 8) { - or = -1LL; - if (t->type == 2) or >>= 1; - } else or = (1LL<<(8*t->size))-1; - throw = sprintf(buf, class, 0, or); - - // Accumulate integer based on size argument - for (k=0; k < t->size; k++) { - or = TT.buf[j++]; - ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k)); - } - - // Handle negative values - if (t->type == 2) { - or = sizeof(or) - t->size; - throw++; - if (or && (ll & (1l<<((8*t->size)-1)))) - ll |= ((or<<(8*or))-1) << (8*t->size); - } - - sprintf(buf, class, throw, ll); - pad += throw+1; - } - xprintf("%*s", pad, buf); - pad = 0; - } - xputc('\n'); - } - - // buffer toggle for "same as last time" check. - TT.buf = (char *)((TT.buf == (char *)TT.bufs) ? TT.bufs+2 : TT.bufs); + unsigned flags = toys.optflags; + char *abases[] = {"", "%07d", "%07o", "%06x"}; + struct odtype *types = (struct odtype *)toybuf, *t; + int i, len; + + if (TT.leftover<16) memset(TT.buf+TT.leftover, 0, 16-TT.leftover); + + // Handle duplciate lines as * + if (!(flags&FLAG_v) && TT.jump_bytes != TT.pos && TT.leftover + && !memcmp(TT.bufs, TT.bufs + 2, 16)) + { + if (!TT.star) { + xputs("*"); + TT.star++; + } + + // Print line position + } else { + TT.star = 0; + + xprintf(abases[TT.address_idx], TT.pos); + if (!TT.leftover) { + if (TT.address_idx) xputc('\n'); + return; + } + } + + TT.pos += len = TT.leftover; + TT.leftover = 0; + if (TT.star) return; + + // For each output type, print one line + + for (i=0; i<TT.types; i++) { + int j = 0, pad = i ? 8 : 0; + char buf[128]; + + t = types+i; + while (j<len) { + unsigned k; + int throw = 0; + + // Handle ascii + if (t->type < 2) { + char c = TT.buf[j++]; + pad += 4; + + if (!t->type) { + c &= 127; + if (c<=32) sprintf(buf, "%.3s", ascii+(3*c)); + else if (c==127) strcpy(buf, "del"); + else sprintf(buf, "%c", c); + } else { + char *bfnrtav = "\b\f\n\r\t\a\v", *s = strchr(bfnrtav, c); + if (s) sprintf(buf, "\\%c", "bfnrtav0"[s-bfnrtav]); + else if (c < 32 || c >= 127) sprintf(buf, "%03o", c); + else { + // TODO: this should be UTF8 aware. + sprintf(buf, "%c", c); + } + } + } else if (CFG_TOYBOX_FLOAT && t->type == 6) { + long double ld; + union {float f; double d; long double ld;} fdl; + + memcpy(&fdl, TT.buf+j, t->size); + j += t->size; + if (sizeof(float) == t->size) { + ld = fdl.f; + pad += (throw = 8)+7; + } else if (sizeof(double) == t->size) { + ld = fdl.d; + pad += (throw = 17)+8; + } else if (sizeof(long double) == t->size) { + ld = fdl.ld; + pad += (throw = 21)+9; + } else error_exit("bad -tf '%d'", t->size); + + sprintf(buf, "%.*Le", throw, ld); + // Integer types + } else { + unsigned long long ll = 0, or; + char *c[] = {"%*lld", "%*llu", "%0*llo", "%0*llx"}, + *class = c[t->type-2]; + + // Work out width of field + if (t->size == 8) { + or = -1LL; + if (t->type == 2) or >>= 1; + } else or = (1LL<<(8*t->size))-1; + throw = sprintf(buf, class, 0, or); + + // Accumulate integer based on size argument + for (k=0; k < t->size; k++) { + or = TT.buf[j++]; + ll |= or << (8*(IS_BIG_ENDIAN ? t->size-k-1 : k)); + } + + // Handle negative values + if (t->type == 2) { + or = sizeof(or) - t->size; + throw++; + if (or && (ll & (1l<<((8*t->size)-1)))) + ll |= ((or<<(8*or))-1) << (8*t->size); + } + + sprintf(buf, class, throw, ll); + pad += throw+1; + } + xprintf("%*s", pad, buf); + pad = 0; + } + xputc('\n'); + } + + // buffer toggle for "same as last time" check. + TT.buf = (char *)((TT.buf == (char *)TT.bufs) ? TT.bufs+2 : TT.bufs); } static void do_od(int fd, char *name) { - // Skip input, possibly more than one entire file. - if (TT.jump_bytes < TT.pos) { - off_t off = lskip(fd, TT.jump_bytes); - if (off > 0) TT.pos += off; - if (TT.jump_bytes < TT.pos) return; - } - - for(;;) { - char *buf = TT.buf + TT.leftover; - int len = 16 - TT.leftover; - - if (toys.optflags & FLAG_N) { - if (!TT.max_count) break; - if (TT.max_count < len) len = TT.max_count; - } - - len = readall(fd, buf, len); - if (len < 0) { - perror_msg("%s", name); - break; - } - if (TT.max_count) TT.max_count -= len; - TT.leftover += len; - if (TT.leftover < 16) break; - - od_outline(); - } + // Skip input, possibly more than one entire file. + if (TT.jump_bytes < TT.pos) { + off_t off = lskip(fd, TT.jump_bytes); + if (off > 0) TT.pos += off; + if (TT.jump_bytes < TT.pos) return; + } + + for(;;) { + char *buf = TT.buf + TT.leftover; + int len = 16 - TT.leftover; + + if (toys.optflags & FLAG_N) { + if (!TT.max_count) break; + if (TT.max_count < len) len = TT.max_count; + } + + len = readall(fd, buf, len); + if (len < 0) { + perror_msg("%s", name); + break; + } + if (TT.max_count) TT.max_count -= len; + TT.leftover += len; + if (TT.leftover < 16) break; + + od_outline(); + } } static void append_base(char *base) { - char *s = base; - struct odtype *types = (struct odtype *)toybuf; - int type; - - for (;;) { - int size = 1; - - if (!*s) return; - if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break; - if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break; - - if (isdigit(*s)) { - size = strtol(s, &s, 10); - if (type < 2 && size != 1) break; - if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double)); - else if (size < 0 || size > 8) break; - } else if (CFG_TOYBOX_FLOAT && type == 6) { - int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)}; - if (-1 == (size = stridx("FDL", *s))) size = sizeof(double); - else { - s++; - size = sizes[size]; - } - } else if (type > 1) { - if (-1 == (size = stridx("CSIL", *s))) size = 4; - else { - s++; - size = 1 << size; - } - } - - types[TT.types].type = type; - types[TT.types].size = size; - TT.types++; - } - - error_exit("bad -t %s", base); + char *s = base; + struct odtype *types = (struct odtype *)toybuf; + int type; + + for (;;) { + int size = 1; + + if (!*s) return; + if (TT.types >= sizeof(toybuf)/sizeof(struct odtype)) break; + if (-1 == (type = stridx("acduox"USE_TOYBOX_FLOAT("f"), *(s++)))) break; + + if (isdigit(*s)) { + size = strtol(s, &s, 10); + if (type < 2 && size != 1) break; + if (CFG_TOYBOX_FLOAT && type == 6 && size == sizeof(long double)); + else if (size < 0 || size > 8) break; + } else if (CFG_TOYBOX_FLOAT && type == 6) { + int sizes[] = {sizeof(float), sizeof(double), sizeof(long double)}; + if (-1 == (size = stridx("FDL", *s))) size = sizeof(double); + else { + s++; + size = sizes[size]; + } + } else if (type > 1) { + if (-1 == (size = stridx("CSIL", *s))) size = 4; + else { + s++; + size = 1 << size; + } + } + + types[TT.types].type = type; + types[TT.types].size = size; + TT.types++; + } + + error_exit("bad -t %s", base); } void od_main(void) { - struct arg_list *arg; + struct arg_list *arg; - TT.buf = (char *)TT.bufs; + TT.buf = (char *)TT.bufs; - if (!TT.address_base) TT.address_idx = 2; - else if (0>(TT.address_idx = stridx("ndox", *TT.address_base))) - error_exit("bad -A '%c'", *TT.address_base); + if (!TT.address_base) TT.address_idx = 2; + else if (0>(TT.address_idx = stridx("ndox", *TT.address_base))) + error_exit("bad -A '%c'", *TT.address_base); - // Collect -t entries + // Collect -t entries - for (arg = TT.output_base; arg; arg = arg->next) append_base(arg->arg); - if (toys.optflags & FLAG_b) append_base("o1"); - if (toys.optflags & FLAG_d) append_base("u2"); - if (toys.optflags & FLAG_o) append_base("o2"); - if (toys.optflags & FLAG_s) append_base("d2"); - if (toys.optflags & FLAG_x) append_base("x2"); - if (!TT.output_base) append_base("o2"); + for (arg = TT.output_base; arg; arg = arg->next) append_base(arg->arg); + if (toys.optflags & FLAG_b) append_base("o1"); + if (toys.optflags & FLAG_d) append_base("u2"); + if (toys.optflags & FLAG_o) append_base("o2"); + if (toys.optflags & FLAG_s) append_base("d2"); + if (toys.optflags & FLAG_x) append_base("x2"); + if (!TT.output_base) append_base("o2"); - loopfiles(toys.optargs, do_od); + loopfiles(toys.optargs, do_od); - if (TT.leftover) od_outline(); - od_outline(); + if (TT.leftover) od_outline(); + od_outline(); } diff --git a/toys/posix/patch.c b/toys/posix/patch.c index 40d7cbcf..12e4b8c3 100644 --- a/toys/posix/patch.c +++ b/toys/posix/patch.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * patch.c - Apply a "universal" diff. +/* patch.c - Apply a "universal" diff. * * Copyright 2007 Rob Landley <rob@landley.net> * @@ -24,39 +22,39 @@ USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"ulp#i:R", TOYFLAG_USR|TOYFLAG_BIN)) config PATCH - bool "patch" - default y - help - usage: patch [-i file] [-p depth] [-Ru] + bool "patch" + default y + help + usage: patch [-i file] [-p depth] [-Ru] - Apply a unified diff to one or more files. + Apply a unified diff to one or more files. - -i Input file (defaults=stdin) - -l Loose match (ignore whitespace) - -p Number of '/' to strip from start of file paths (default=all) - -R Reverse patch. - -u Ignored (only handles "unified" diffs) + -i Input file (defaults=stdin) + -l Loose match (ignore whitespace) + -p Number of '/' to strip from start of file paths (default=all) + -R Reverse patch. + -u Ignored (only handles "unified" diffs) - This version of patch only handles unified diffs, and only modifies - a file when all all hunks to that file apply. Patch prints failed - hunks to stderr, and exits with nonzero status if any hunks fail. + This version of patch only handles unified diffs, and only modifies + a file when all all hunks to that file apply. Patch prints failed + hunks to stderr, and exits with nonzero status if any hunks fail. - A file compared against /dev/null (or with a date <= the epoch) is - created/deleted as appropriate. + A file compared against /dev/null (or with a date <= the epoch) is + created/deleted as appropriate. */ #define FOR_patch #include "toys.h" GLOBALS( - char *infile; - long prefix; - - struct double_list *current_hunk; - long oldline, oldlen, newline, newlen; - long linenum; - int context, state, filein, fileout, filepatch, hunknum; - char *tempname; + char *infile; + long prefix; + + struct double_list *current_hunk; + long oldline, oldlen, newline, newlen; + long linenum; + int context, state, filein, fileout, filepatch, hunknum; + char *tempname; ) // Dispose of a line of input, either by writing it out or discarding it. @@ -70,59 +68,59 @@ GLOBALS( static void do_line(void *data) { - struct double_list *dlist = (struct double_list *)data; + struct double_list *dlist = (struct double_list *)data; - if (TT.state>1 && *dlist->data != TT.state) { - char *s = dlist->data+(TT.state>3 ? 1 : 0); - int i = TT.state == 2 ? 2 : TT.fileout; + if (TT.state>1 && *dlist->data != TT.state) { + char *s = dlist->data+(TT.state>3 ? 1 : 0); + int i = TT.state == 2 ? 2 : TT.fileout; - xwrite(i, s, strlen(s)); - xwrite(i, "\n", 1); - } + xwrite(i, s, strlen(s)); + xwrite(i, "\n", 1); + } - if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data); + if (PATCH_DEBUG) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data); - free(dlist->data); - free(data); + free(dlist->data); + free(data); } static void finish_oldfile(void) { - if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.fileout = TT.filein = -1; + if (TT.tempname) replace_tempfile(TT.filein, TT.fileout, &TT.tempname); + TT.fileout = TT.filein = -1; } static void fail_hunk(void) { - if (!TT.current_hunk) return; - TT.current_hunk->prev->next = 0; + if (!TT.current_hunk) return; + TT.current_hunk->prev->next = 0; - fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", - TT.hunknum, TT.oldline, TT.newline); - toys.exitval = 1; + fprintf(stderr, "Hunk %d FAILED %ld/%ld.\n", + TT.hunknum, TT.oldline, TT.newline); + toys.exitval = 1; - // If we got to this point, we've seeked to the end. Discard changes to - // this file and advance to next file. + // If we got to this point, we've seeked to the end. Discard changes to + // this file and advance to next file. - TT.state = 2; - llist_traverse(TT.current_hunk, do_line); - TT.current_hunk = NULL; - delete_tempfile(TT.filein, TT.fileout, &TT.tempname); - TT.state = 0; + TT.state = 2; + llist_traverse(TT.current_hunk, do_line); + TT.current_hunk = NULL; + delete_tempfile(TT.filein, TT.fileout, &TT.tempname); + TT.state = 0; } -// Compare ignoring whitespace. Just returns +// Compare ignoring whitespace. Just returns static int loosecmp(char *aa, char *bb) { - int a = 0, b = 0; - - for (;;) { - while (isspace(aa[a])) a++; - while (isspace(bb[b])) b++; - if (aa[a] != bb[b]) return 1; - if (!aa[a]) return 0; - a++, b++; - } + int a = 0, b = 0; + + for (;;) { + while (isspace(aa[a])) a++; + while (isspace(bb[b])) b++; + if (aa[a] != bb[b]) return 1; + if (!aa[a]) return 0; + a++, b++; + } } // Given a hunk of a unified diff, make the appropriate change to the file. @@ -134,116 +132,114 @@ static int loosecmp(char *aa, char *bb) static int apply_one_hunk(void) { - struct double_list *plist, *buf = NULL, *check; - int matcheof = 0, reverse = toys.optflags & FLAG_R, backwarn = 0; - int (*lcmp)(char *aa, char *bb); - - lcmp = (toys.optflags & FLAG_l) ? (void *)loosecmp : (void *)strcmp; - - // Break doubly linked list so we can use singly linked traversal function. - TT.current_hunk->prev->next = NULL; - - // Match EOF if there aren't as many ending context lines as beginning - for (plist = TT.current_hunk; plist; plist = plist->next) { - if (plist->data[0]==' ') matcheof++; - else matcheof = 0; - if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data); - } - matcheof = matcheof < TT.context; - - if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); - - // Loop through input data searching for this hunk. Match all context - // lines and all lines to be removed until we've found the end of a - // complete hunk. - plist = TT.current_hunk; - buf = NULL; - if (TT.context) for (;;) { - char *data = get_line(TT.filein); - - TT.linenum++; - - // Figure out which line of hunk to compare with next. (Skip lines - // of the hunk we'd be adding.) - while (plist && *plist->data == "+-"[reverse]) { - if (data && !lcmp(data, plist->data+1)) { - if (!backwarn) backwarn = TT.linenum; - } - plist = plist->next; - } - - // Is this EOF? - if (!data) { - if (PATCH_DEBUG) fprintf(stderr, "INEOF\n"); - - // Does this hunk need to match EOF? - if (!plist && matcheof) break; - - if (backwarn) - fprintf(stderr, "Possibly reversed hunk %d at %ld\n", - TT.hunknum, TT.linenum); - - // File ended before we found a place for this hunk. - fail_hunk(); - goto done; - } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data); - check = dlist_add(&buf, data); - - // Compare this line with next expected line of hunk. - - // A match can fail because the next line doesn't match, or because - // we hit the end of a hunk that needed EOF, and this isn't EOF. - - // If match failed, flush first line of buffered data and - // recheck buffered data for a new match until we find one or run - // out of buffer. - - for (;;) { - if (!plist || lcmp(check->data, plist->data+1)) { - // Match failed. Write out first line of buffered data and - // recheck remaining buffered data for a new match. - - if (PATCH_DEBUG) - fprintf(stderr, "NOT: %s\n", plist->data); - - TT.state = 3; - check = llist_pop(&buf); - check->prev->next = buf; - buf->prev = check->prev; - do_line(check); - plist = TT.current_hunk; - - // If we've reached the end of the buffer without confirming a - // match, read more lines. - if (check==buf) { - buf = 0; - break; - } - check = buf; - } else { - if (PATCH_DEBUG) - fprintf(stderr, "MAYBE: %s\n", plist->data); - // This line matches. Advance plist, detect successful match. - plist = plist->next; - if (!plist && !matcheof) goto out; - check = check->next; - if (check == buf) break; - } - } - } + struct double_list *plist, *buf = NULL, *check; + int matcheof = 0, reverse = toys.optflags & FLAG_R, backwarn = 0; + int (*lcmp)(char *aa, char *bb); + + lcmp = (toys.optflags & FLAG_l) ? (void *)loosecmp : (void *)strcmp; + + // Break doubly linked list so we can use singly linked traversal function. + TT.current_hunk->prev->next = NULL; + + // Match EOF if there aren't as many ending context lines as beginning + for (plist = TT.current_hunk; plist; plist = plist->next) { + if (plist->data[0]==' ') matcheof++; + else matcheof = 0; + if (PATCH_DEBUG) fprintf(stderr, "HUNK:%s\n", plist->data); + } + matcheof = matcheof < TT.context; + + if (PATCH_DEBUG) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); + + // Loop through input data searching for this hunk. Match all context + // lines and all lines to be removed until we've found the end of a + // complete hunk. + plist = TT.current_hunk; + buf = NULL; + if (TT.context) for (;;) { + char *data = get_line(TT.filein); + + TT.linenum++; + + // Figure out which line of hunk to compare with next. (Skip lines + // of the hunk we'd be adding.) + while (plist && *plist->data == "+-"[reverse]) { + if (data && !lcmp(data, plist->data+1)) { + if (!backwarn) backwarn = TT.linenum; + } + plist = plist->next; + } + + // Is this EOF? + if (!data) { + if (PATCH_DEBUG) fprintf(stderr, "INEOF\n"); + + // Does this hunk need to match EOF? + if (!plist && matcheof) break; + + if (backwarn) + fprintf(stderr, "Possibly reversed hunk %d at %ld\n", + TT.hunknum, TT.linenum); + + // File ended before we found a place for this hunk. + fail_hunk(); + goto done; + } else if (PATCH_DEBUG) fprintf(stderr, "IN: %s\n", data); + check = dlist_add(&buf, data); + + // Compare this line with next expected line of hunk. + + // A match can fail because the next line doesn't match, or because + // we hit the end of a hunk that needed EOF, and this isn't EOF. + + // If match failed, flush first line of buffered data and + // recheck buffered data for a new match until we find one or run + // out of buffer. + + for (;;) { + if (!plist || lcmp(check->data, plist->data+1)) { + // Match failed. Write out first line of buffered data and + // recheck remaining buffered data for a new match. + + if (PATCH_DEBUG) fprintf(stderr, "NOT: %s\n", plist->data); + + TT.state = 3; + check = llist_pop(&buf); + check->prev->next = buf; + buf->prev = check->prev; + do_line(check); + plist = TT.current_hunk; + + // If we've reached the end of the buffer without confirming a + // match, read more lines. + if (check==buf) { + buf = 0; + break; + } + check = buf; + } else { + if (PATCH_DEBUG) fprintf(stderr, "MAYBE: %s\n", plist->data); + // This line matches. Advance plist, detect successful match. + plist = plist->next; + if (!plist && !matcheof) goto out; + check = check->next; + if (check == buf) break; + } + } + } out: - // We have a match. Emit changed data. - TT.state = "-+"[reverse]; - llist_traverse(TT.current_hunk, do_line); - TT.current_hunk = NULL; - TT.state = 1; + // We have a match. Emit changed data. + TT.state = "-+"[reverse]; + llist_traverse(TT.current_hunk, do_line); + TT.current_hunk = NULL; + TT.state = 1; done: - if (buf) { - buf->prev->next = NULL; - llist_traverse(buf, do_line); - } + if (buf) { + buf->prev->next = NULL; + llist_traverse(buf, do_line); + } - return TT.state; + return TT.state; } // Read a patch file and find hunks, opening/creating/deleting files. @@ -256,172 +252,170 @@ done: void patch_main(void) { - int reverse = toys.optflags&FLAG_R, state = 0, patchlinenum = 0, - strip = 0; - char *oldname = NULL, *newname = NULL; - - if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY); - TT.filein = TT.fileout = -1; - - // Loop through the lines in the patch - for (;;) { - char *patchline; - - patchline = get_line(TT.filepatch); - if (!patchline) break; - - // Other versions of patch accept damaged patches, - // so we need to also. - if (strip || !patchlinenum++) { - int len = strlen(patchline); - if (patchline[len-1] == '\r') { - if (!strip) fprintf(stderr, "Removing DOS newlines\n"); - strip = 1; - patchline[len-1]=0; - } - } - if (!*patchline) { - free(patchline); - patchline = xstrdup(" "); - } - - // Are we assembling a hunk? - if (state >= 2) { - if (*patchline==' ' || *patchline=='+' || *patchline=='-') { - dlist_add(&TT.current_hunk, patchline); - - if (*patchline != '+') TT.oldlen--; - if (*patchline != '-') TT.newlen--; - - // Context line? - if (*patchline==' ' && state==2) TT.context++; - else state=3; - - // If we've consumed all expected hunk lines, apply the hunk. - - if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); - continue; - } - fail_hunk(); - state = 0; - continue; - } - - // Open a new file? - if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { - char *s, **name = &oldname; - int i; - - if (*patchline == '+') { - name = &newname; - state = 1; - } - - free(*name); - finish_oldfile(); - - // Trim date from end of filename (if any). We don't care. - for (s = patchline+4; *s && *s!='\t'; s++) - if (*s=='\\' && s[1]) s++; - i = atoi(s); - if (i>1900 && i<=1970) - *name = xstrdup("/dev/null"); - else { - *s = 0; - *name = xstrdup(patchline+4); - } - - // We defer actually opening the file because svn produces broken - // patches that don't signal they want to create a new file the - // way the patch man page says, so you have to read the first hunk - // and _guess_. - - // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ - // but a missing ,value means the value is 1. - } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { - int i; - char *s = patchline+4; - - // Read oldline[,oldlen] +newline[,newlen] - - TT.oldlen = TT.newlen = 1; - TT.oldline = strtol(s, &s, 10); - if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); - TT.newline = strtol(s+2, &s, 10); - if (*s == ',') TT.newlen = strtol(s+1, &s, 10); - - TT.context = 0; - state = 2; - - // If this is the first hunk, open the file. - if (TT.filein == -1) { - int oldsum, newsum, del = 0; - char *name; - - oldsum = TT.oldline + TT.oldlen; - newsum = TT.newline + TT.newlen; - - name = reverse ? oldname : newname; - - // We're deleting oldname if new file is /dev/null (before -p) - // or if new hunk is empty (zero context) after patching - if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) - { - name = reverse ? newname : oldname; - del++; - } - - // handle -p path truncation. - for (i = 0, s = name; *s;) { - if ((toys.optflags & FLAG_p) && TT.prefix == i) break; - if (*s++ != '/') continue; - while (*s == '/') s++; - name = s; - i++; - } - - if (del) { - printf("removing %s\n", name); - xunlink(name); - state = 0; - // If we've got a file to open, do so. - } else if (!(toys.optflags & FLAG_p) || i <= TT.prefix) { - // If the old file was null, we're creating a new one. - if ((!strcmp(oldname, "/dev/null") || !oldsum) - && access(name, F_OK)) - { - printf("creating %s\n", name); - s = strrchr(name, '/'); - if (s) { - *s = 0; - xmkpath(name, -1); - *s = '/'; - } - TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); - } else { - printf("patching %s\n", name); - TT.filein = xopen(name, O_RDWR); - } - TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); - TT.linenum = 0; - TT.hunknum = 0; - } - } - - TT.hunknum++; - - continue; - } - - // If we didn't continue above, discard this line. - free(patchline); - } - - finish_oldfile(); - - if (CFG_TOYBOX_FREE) { - close(TT.filepatch); - free(oldname); - free(newname); - } + int reverse = toys.optflags&FLAG_R, state = 0, patchlinenum = 0, + strip = 0; + char *oldname = NULL, *newname = NULL; + + if (TT.infile) TT.filepatch = xopen(TT.infile, O_RDONLY); + TT.filein = TT.fileout = -1; + + // Loop through the lines in the patch + for (;;) { + char *patchline; + + patchline = get_line(TT.filepatch); + if (!patchline) break; + + // Other versions of patch accept damaged patches, + // so we need to also. + if (strip || !patchlinenum++) { + int len = strlen(patchline); + if (patchline[len-1] == '\r') { + if (!strip) fprintf(stderr, "Removing DOS newlines\n"); + strip = 1; + patchline[len-1]=0; + } + } + if (!*patchline) { + free(patchline); + patchline = xstrdup(" "); + } + + // Are we assembling a hunk? + if (state >= 2) { + if (*patchline==' ' || *patchline=='+' || *patchline=='-') { + dlist_add(&TT.current_hunk, patchline); + + if (*patchline != '+') TT.oldlen--; + if (*patchline != '-') TT.newlen--; + + // Context line? + if (*patchline==' ' && state==2) TT.context++; + else state=3; + + // If we've consumed all expected hunk lines, apply the hunk. + + if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); + continue; + } + fail_hunk(); + state = 0; + continue; + } + + // Open a new file? + if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { + char *s, **name = &oldname; + int i; + + if (*patchline == '+') { + name = &newname; + state = 1; + } + + free(*name); + finish_oldfile(); + + // Trim date from end of filename (if any). We don't care. + for (s = patchline+4; *s && *s!='\t'; s++) + if (*s=='\\' && s[1]) s++; + i = atoi(s); + if (i>1900 && i<=1970) *name = xstrdup("/dev/null"); + else { + *s = 0; + *name = xstrdup(patchline+4); + } + + // We defer actually opening the file because svn produces broken + // patches that don't signal they want to create a new file the + // way the patch man page says, so you have to read the first hunk + // and _guess_. + + // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ + // but a missing ,value means the value is 1. + } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { + int i; + char *s = patchline+4; + + // Read oldline[,oldlen] +newline[,newlen] + + TT.oldlen = TT.newlen = 1; + TT.oldline = strtol(s, &s, 10); + if (*s == ',') TT.oldlen=strtol(s+1, &s, 10); + TT.newline = strtol(s+2, &s, 10); + if (*s == ',') TT.newlen = strtol(s+1, &s, 10); + + TT.context = 0; + state = 2; + + // If this is the first hunk, open the file. + if (TT.filein == -1) { + int oldsum, newsum, del = 0; + char *name; + + oldsum = TT.oldline + TT.oldlen; + newsum = TT.newline + TT.newlen; + + name = reverse ? oldname : newname; + + // We're deleting oldname if new file is /dev/null (before -p) + // or if new hunk is empty (zero context) after patching + if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) + { + name = reverse ? newname : oldname; + del++; + } + + // handle -p path truncation. + for (i = 0, s = name; *s;) { + if ((toys.optflags & FLAG_p) && TT.prefix == i) break; + if (*s++ != '/') continue; + while (*s == '/') s++; + name = s; + i++; + } + + if (del) { + printf("removing %s\n", name); + xunlink(name); + state = 0; + // If we've got a file to open, do so. + } else if (!(toys.optflags & FLAG_p) || i <= TT.prefix) { + // If the old file was null, we're creating a new one. + if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK)) + { + printf("creating %s\n", name); + s = strrchr(name, '/'); + if (s) { + *s = 0; + xmkpath(name, -1); + *s = '/'; + } + TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666); + } else { + printf("patching %s\n", name); + TT.filein = xopen(name, O_RDWR); + } + TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname); + TT.linenum = 0; + TT.hunknum = 0; + } + } + + TT.hunknum++; + + continue; + } + + // If we didn't continue above, discard this line. + free(patchline); + } + + finish_oldfile(); + + if (CFG_TOYBOX_FREE) { + close(TT.filepatch); + free(oldname); + free(newname); + } } diff --git a/toys/posix/pwd.c b/toys/posix/pwd.c index d5a3bb69..f70f9098 100644 --- a/toys/posix/pwd.c +++ b/toys/posix/pwd.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * pwd.c - Print working directory. +/* pwd.c - Print working directory. * * Copyright 2006 Rob Landley <rob@landley.net> * @@ -11,20 +9,20 @@ USE_PWD(NEWTOY(pwd, NULL, TOYFLAG_BIN)) config PWD - bool "pwd" - default y - help - usage: pwd + bool "pwd" + default y + help + usage: pwd - The print working directory command prints the current directory. + The print working directory command prints the current directory. */ #include "toys.h" void pwd_main(void) { - char *pwd = xgetcwd(); + char *pwd = xgetcwd(); - xprintf("%s\n", pwd); - if (CFG_TOYBOX_FREE) free(pwd); + xprintf("%s\n", pwd); + if (CFG_TOYBOX_FREE) free(pwd); } diff --git a/toys/posix/rmdir.c b/toys/posix/rmdir.c index be93cb69..289b0156 100644 --- a/toys/posix/rmdir.c +++ b/toys/posix/rmdir.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * rmdir.c - remove directory/path +/* rmdir.c - remove directory/path * * Copyright 2008 Rob Landley <rob@landley.net> * @@ -9,35 +7,35 @@ USE_RMDIR(NEWTOY(rmdir, "<1p", TOYFLAG_BIN)) config RMDIR - bool "rmdir" - default y - help - usage: rmdir [-p] [dirname...] - Remove one or more directories. + bool "rmdir" + default y + help + usage: rmdir [-p] [dirname...] + Remove one or more directories. - -p Remove path. + -p Remove path. */ #include "toys.h" static void do_rmdir(char *name) { - for (;;) { - char *temp; - - if (rmdir(name)) { - perror_msg("%s",name); - return; - } - if (!toys.optflags) return; - if (!(temp=strrchr(name,'/'))) return; - *temp=0; - } + for (;;) { + char *temp; + + if (rmdir(name)) { + perror_msg("%s",name); + return; + } + if (!toys.optflags) return; + if (!(temp=strrchr(name,'/'))) return; + *temp=0; + } } void rmdir_main(void) { - char **s; + char **s; - for (s=toys.optargs; *s; s++) do_rmdir(*s); + for (s=toys.optargs; *s; s++) do_rmdir(*s); } diff --git a/toys/posix/sed.c b/toys/posix/sed.c index a3ba9e38..15099cc6 100644 --- a/toys/posix/sed.c +++ b/toys/posix/sed.c @@ -1,21 +1,24 @@ -/* vi: set sw=4 ts=4: +/* sed.c - Stream editor. * - * sed.c - Stream editor. - * - * Copyright 2008 Rob Landley <rob@landley.net> + * Copyright 2012 Rob Landley <rob@landley.net> * * See http://opengroup.org/onlinepubs/9699919799/utilities/sed.c USE_SED(NEWTOY(sed, "irne*", TOYFLAG_BIN)) config SED - bool "sed" - default n - help - usage: sed [-irn] {command | [-e command]...} [FILE...] + bool "sed" + default n + help + usage: sed [-irn] {command | [-e command]...} [FILE...] + + Stream EDitor, transforms text by appling script of command to each line + of input. - Stream EDitor, transforms text by appling commands to each line - of input. + -e Add expression to the command script (if no -e, use first argument) + -i Modify file in place + -n No default output (p commands only) + -r Use extended regular expression syntex */ #define FOR_sed @@ -23,40 +26,106 @@ config SED #include "lib/xregcomp.h" GLOBALS( - struct arg_list *commands; + struct arg_list *scripts; + struct double_list *commands; + + void *parsed; ) +// Digested version of what sed commands can actually tell use to do. + + struct sed_command { - // Doubly linked list of commands. - struct sed_command *next, *prev; + // double_list compatibility (easier to create in-order) + struct sed_command *next, *prev; - // Regexes for s/match/data/ and /match_begin/,/match_end/command - regex_t *match, *match_begin, *match_end; + // data string for (saicytb) + char c, *data; + // Regexes for s/match/data/ and /begin/,/end/command + regex_t *match, *begin, *end; + // For numeric ranges ala 10,20command + long lstart, lstop; + // Which match to replace, 0 for all. s and w commands can write to a file + int which, outfd; +}; - // For numeric ranges ala 10,20command - int first_line, last_line; +// Space. Space. Gotta get past space. Spaaaaaaaace! (But not newline.) +void spaceorb(char **s) +{ + while (**s == ' ' || **s == '\t') *s++; +} - // Which match to replace, 0 for all. - int which; +void parse_scripts(void) +{ + struct sed_command *commands = 0; + struct arg_list *script; + int which = 0; + long l; - // s and w commands can write to a file. Slight optimization: we use 0 - // instead of -1 to mean no file here, because even when there's no stdin - // our input file would take fd 0. - int outfd; + for (script = TT.scripts; *script; script = script->next) { + char *str = script->arg, *s; + struct sed_command *cmd; - // Data string for (saicytb) - char *data; + which++; + for (i=1;;) { + if (!*str) break; - // Which command letter is this? - char command; -}; + cmd = xzalloc(sizeof(struct sed_command)); + + // Identify prefix + for (;;) { + long l; + + spaceorb(&str); + if (*str == '$') { + l = -1; + str++; + } else if (isdigit(*str)) l = strtol(str, &str, 10); + else if (!cmd->lstart) break; + else goto parse_fail; + + spaceorb(&str); + if (!cmd->lstart) { + if (!l) goto parse_fail; + cmd->lstart = l; + if (*str != ',') break; + str++; + continue; + } + cmd->lstop = l; + break; + } else if (*str == '/') { + printf("regex\n"); + } + l = stridx("{bcdDgGhHlnNpPstwxyrqia= \t#:}", *str); + if (l == -1) goto parse_fail; + + + } + } + + return; + +parse_fail: + error_exit("bad expression %d@%d: %s", which, i, script->arg+i); +} void sed_main(void) { - struct arg_list *test; + char **files=toys.optargs; + + // If no -e, use first argument + if (!TT.scripts) { + if (!*files) error_exit("Need script"); + (TT.scripts=xzalloc(sizeof(struct arg_list)))->arg=*(files++); + } + - for (test = TT.commands; test; test = test->next) - dprintf(2,"command=%s\n",test->arg); + { + struct arg_list *test; - printf("Hello world\n"); + for (test = TT.commands; test; test = test->next) + dprintf(2,"command=%s\n",test->arg); + while (*files) dprintf(2,"file=%s\n", *(files++)); + } } diff --git a/toys/posix/sh.c b/toys/posix/sh.c index 44c39119..30900b30 100644 --- a/toys/posix/sh.c +++ b/toys/posix/sh.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * sh.c - toybox shell +/* sh.c - toybox shell * * Copyright 2006 Rob Landley <rob@landley.net> * @@ -30,157 +28,157 @@ USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN)) USE_SH(OLDTOY(toysh, sh, "c:i", TOYFLAG_BIN)) config SH - bool "sh (toysh)" - default n - help - usage: sh [-c command] [script] + bool "sh (toysh)" + default n + help + usage: sh [-c command] [script] - Command shell. Runs a shell script, or reads input interactively - and responds to it. + Command shell. Runs a shell script, or reads input interactively + and responds to it. - -c command line to execute + -c command line to execute config SH_TTY - bool "Interactive shell (terminal control)" - default n - depends on SH - help - Add terminal control to toysh. This is necessary for interactive use, - so the shell isn't killed by CTRL-C. + bool "Interactive shell (terminal control)" + default n + depends on SH + help + Add terminal control to toysh. This is necessary for interactive use, + so the shell isn't killed by CTRL-C. config SH_PROFILE - bool "Profile support" - default n - depends on SH_TTY - help - Read /etc/profile and ~/.profile when running interactively. + bool "Profile support" + default n + depends on SH_TTY + help + Read /etc/profile and ~/.profile when running interactively. - Also enables the built-in command "source". + Also enables the built-in command "source". config SH_JOBCTL - bool "Job Control (fg, bg, jobs)" - default n - depends on SH_TTY - help - Add job control to toysh. This lets toysh handle CTRL-Z, and enables - the built-in commands "fg", "bg", and "jobs". + bool "Job Control (fg, bg, jobs)" + default n + depends on SH_TTY + help + Add job control to toysh. This lets toysh handle CTRL-Z, and enables + the built-in commands "fg", "bg", and "jobs". - With pipe support, enable use of "&" to run background processes. + With pipe support, enable use of "&" to run background processes. config SH_FLOWCTL - bool "Flow control (if, while, for, functions)" - default n - depends on SH - help - Add flow control to toysh. This enables the if/then/else/fi, - while/do/done, and for/do/done constructs. + bool "Flow control (if, while, for, functions)" + default n + depends on SH + help + Add flow control to toysh. This enables the if/then/else/fi, + while/do/done, and for/do/done constructs. - With pipe support, this enables the ability to define functions - using the "function name" or "name()" syntax, plus curly brackets - "{ }" to group commands. + With pipe support, this enables the ability to define functions + using the "function name" or "name()" syntax, plus curly brackets + "{ }" to group commands. config SH_QUOTES - bool "Smarter argument parsing (quotes)" - default n - depends on SH - help - Add support for parsing "" and '' style quotes to the toysh command - parser, with lets arguments have spaces in them. + bool "Smarter argument parsing (quotes)" + default n + depends on SH + help + Add support for parsing "" and '' style quotes to the toysh command + parser, with lets arguments have spaces in them. config SH_WILDCARDS - bool "Wildcards ( ?*{,} )" - default n - depends on SH_QUOTES - help - Expand wildcards in argument names, ala "ls -l *.t?z" and - "rm subdir/{one,two,three}.txt". + bool "Wildcards ( ?*{,} )" + default n + depends on SH_QUOTES + help + Expand wildcards in argument names, ala "ls -l *.t?z" and + "rm subdir/{one,two,three}.txt". config SH_PROCARGS - bool "Executable arguments ( `` and $() )" - default n - depends on SH_QUOTES - help - Add support for executing arguments contianing $() and ``, using - the output of the command as the new argument value(s). + bool "Executable arguments ( `` and $() )" + default n + depends on SH_QUOTES + help + Add support for executing arguments contianing $() and ``, using + the output of the command as the new argument value(s). - (Bash calls this "command substitution".) + (Bash calls this "command substitution".) config SH_ENVVARS - bool "Environment variable support" - default n - depends on SH_QUOTES - help - Substitute environment variable values for $VARNAME or ${VARNAME}, - and enable the built-in command "export". + bool "Environment variable support" + default n + depends on SH_QUOTES + help + Substitute environment variable values for $VARNAME or ${VARNAME}, + and enable the built-in command "export". config SH_LOCALS - bool "Local variables" - default n - depends on SH_ENVVARS - help - Support for local variables, fancy prompts ($PS1), the "set" command, - and $?. + bool "Local variables" + default n + depends on SH_ENVVARS + help + Support for local variables, fancy prompts ($PS1), the "set" command, + and $?. config SH_ARRAYS - bool "Array variables" - default n - depends on SH_LOCALS - help - Support for ${blah[blah]} style array variables. + bool "Array variables" + default n + depends on SH_LOCALS + help + Support for ${blah[blah]} style array variables. config SH_PIPES - bool "Pipes and redirects ( | > >> < << & && | || () ; )" - default n - depends on SH - help - Support multiple commands on the same command line. This includes - | pipes, > >> < redirects, << here documents, || && conditional - execution, () subshells, ; sequential execution, and (with job - control) & background processes. + bool "Pipes and redirects ( | > >> < << & && | || () ; )" + default n + depends on SH + help + Support multiple commands on the same command line. This includes + | pipes, > >> < redirects, << here documents, || && conditional + execution, () subshells, ; sequential execution, and (with job + control) & background processes. config SH_BUILTINS - bool "Builtin commands" - default n - depends on SH - help - Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set, - unset, read, alias. + bool "Builtin commands" + default n + depends on SH + help + Adds the commands exec, fg, bg, help, jobs, pwd, export, source, set, + unset, read, alias. config EXIT - bool - default n - depends on SH - help - usage: exit [status] + bool + default n + depends on SH + help + usage: exit [status] - Exit shell. If no return value supplied on command line, use value - of most recent command, or 0 if none. + Exit shell. If no return value supplied on command line, use value + of most recent command, or 0 if none. config CD - bool - default n - depends on SH - help - usage: cd [path] + bool + default n + depends on SH + help + usage: cd [path] - Change current directory. With no arguments, go to $HOME. + Change current directory. With no arguments, go to $HOME. config CD_P - bool # "-P support for cd" - default n - depends on SH - help - usage: cd [-PL] - - -P Physical path: resolve symlinks in path. - -L Cancel previous -P and restore default behavior. + bool # "-P support for cd" + default n + depends on SH + help + usage: cd [-PL] + + -P Physical path: resolve symlinks in path. + -L Cancel previous -P and restore default behavior. */ #define FOR_sh #include "toys.h" GLOBALS( - char *command; + char *command; ) // A single executable, its arguments, and other information we know about it. @@ -195,20 +193,20 @@ GLOBALS( // What we know about a single process. struct command { - struct command *next; - int flags; // exit, suspend, && || - int pid; // pid (or exit code) - int argc; - char *argv[0]; + struct command *next; + int flags; // exit, suspend, && || + int pid; // pid (or exit code) + int argc; + char *argv[0]; }; // A collection of processes piped into/waiting on each other. struct pipeline { - struct pipeline *next; - int job_id; - struct command *cmd; - char *cmdline; // Unparsed line for display purposes - int cmdlinelen; // How long is cmdline? + struct pipeline *next; + int job_id; + struct command *cmd; + char *cmdline; // Unparsed line for display purposes + int cmdlinelen; // How long is cmdline? }; // Parse one word from the command line, appending one or more argv[] entries @@ -217,23 +215,23 @@ struct pipeline { // hit an ending token. static char *parse_word(char *start, struct command **cmd) { - char *end; + char *end; - // Detect end of line (and truncate line at comment) - if (CFG_SH_PIPES && strchr("><&|(;", *start)) return 0; + // Detect end of line (and truncate line at comment) + if (CFG_SH_PIPES && strchr("><&|(;", *start)) return 0; - // Grab next word. (Add dequote and envvar logic here) - end = start; - while (*end && !isspace(*end)) end++; - (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start); + // Grab next word. (Add dequote and envvar logic here) + end = start; + while (*end && !isspace(*end)) end++; + (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start); - // Allocate more space if there's no room for NULL terminator. + // Allocate more space if there's no room for NULL terminator. - if (!((*cmd)->argc & 7)) - *cmd=xrealloc(*cmd, - sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *)); - (*cmd)->argv[(*cmd)->argc] = 0; - return end; + if (!((*cmd)->argc & 7)) + *cmd=xrealloc(*cmd, + sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *)); + (*cmd)->argv[(*cmd)->argc] = 0; + return end; } // Parse a line of text into a pipeline. @@ -241,149 +239,149 @@ static char *parse_word(char *start, struct command **cmd) static char *parse_pipeline(char *cmdline, struct pipeline *line) { - struct command **cmd = &(line->cmd); - char *start = line->cmdline = cmdline; - - if (!cmdline) return 0; - - if (CFG_SH_JOBCTL) line->cmdline = cmdline; - - // Parse command into argv[] - for (;;) { - char *end; - - // Skip leading whitespace and detect end of line. - while (isspace(*start)) start++; - if (!*start || *start=='#') { - if (CFG_SH_JOBCTL) line->cmdlinelen = start-cmdline; - return 0; - } - - // Allocate next command structure if necessary - if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *)); - - // Parse next argument and add the results to argv[] - end = parse_word(start, cmd); - - // If we hit the end of this command, how did it end? - if (!end) { - if (CFG_SH_PIPES && *start) { - if (*start==';') { - start++; - break; - } - // handle | & < > >> << || && - } - break; - } - start = end; - } - - if (CFG_SH_JOBCTL) line->cmdlinelen = start-cmdline; - - return start; + struct command **cmd = &(line->cmd); + char *start = line->cmdline = cmdline; + + if (!cmdline) return 0; + + if (CFG_SH_JOBCTL) line->cmdline = cmdline; + + // Parse command into argv[] + for (;;) { + char *end; + + // Skip leading whitespace and detect end of line. + while (isspace(*start)) start++; + if (!*start || *start=='#') { + if (CFG_SH_JOBCTL) line->cmdlinelen = start-cmdline; + return 0; + } + + // Allocate next command structure if necessary + if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *)); + + // Parse next argument and add the results to argv[] + end = parse_word(start, cmd); + + // If we hit the end of this command, how did it end? + if (!end) { + if (CFG_SH_PIPES && *start) { + if (*start==';') { + start++; + break; + } + // handle | & < > >> << || && + } + break; + } + start = end; + } + + if (CFG_SH_JOBCTL) line->cmdlinelen = start-cmdline; + + return start; } // Execute the commands in a pipeline static void run_pipeline(struct pipeline *line) { - struct toy_list *tl; - struct command *cmd = line->cmd; - if (!cmd || !cmd->argc) return; - - tl = toy_find(cmd->argv[0]); - // Is this command a builtin that should run in this process? - if (tl && (tl->flags & TOYFLAG_NOFORK)) { - struct toy_context temp; - - // This fakes lots of what toybox_main() does. - memcpy(&temp, &toys, sizeof(struct toy_context)); - memset(&toys, 0, sizeof(struct toy_context)); - toy_init(tl, cmd->argv); - tl->toy_main(); - cmd->pid = toys.exitval; - free(toys.optargs); - if (toys.old_umask) umask(toys.old_umask); - memcpy(&toys, &temp, sizeof(struct toy_context)); - } else { - int status; - - cmd->pid = vfork(); - if (!cmd->pid) xexec(cmd->argv); - else waitpid(cmd->pid, &status, 0); - - if (CFG_SH_FLOWCTL || CFG_SH_PIPES) { - if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status); - if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status); - } - } - - return; + struct toy_list *tl; + struct command *cmd = line->cmd; + if (!cmd || !cmd->argc) return; + + tl = toy_find(cmd->argv[0]); + // Is this command a builtin that should run in this process? + if (tl && (tl->flags & TOYFLAG_NOFORK)) { + struct toy_context temp; + + // This fakes lots of what toybox_main() does. + memcpy(&temp, &toys, sizeof(struct toy_context)); + memset(&toys, 0, sizeof(struct toy_context)); + toy_init(tl, cmd->argv); + tl->toy_main(); + cmd->pid = toys.exitval; + free(toys.optargs); + if (toys.old_umask) umask(toys.old_umask); + memcpy(&toys, &temp, sizeof(struct toy_context)); + } else { + int status; + + cmd->pid = vfork(); + if (!cmd->pid) xexec(cmd->argv); + else waitpid(cmd->pid, &status, 0); + + if (CFG_SH_FLOWCTL || CFG_SH_PIPES) { + if (WIFEXITED(status)) cmd->pid = WEXITSTATUS(status); + if (WIFSIGNALED(status)) cmd->pid = WTERMSIG(status); + } + } + + return; } // Free the contents of a command structure static void free_cmd(void *data) { - struct command *cmd=(struct command *)data; + struct command *cmd=(struct command *)data; - while(cmd->argc) free(cmd->argv[--cmd->argc]); + while(cmd->argc) free(cmd->argv[--cmd->argc]); } // Parse a command line and do what it says to do. static void handle(char *command) { - struct pipeline line; - char *start = command; + struct pipeline line; + char *start = command; - // Loop through commands in this line + // Loop through commands in this line - for (;;) { + for (;;) { - // Parse a group of connected commands + // Parse a group of connected commands - memset(&line,0,sizeof(struct pipeline)); - start = parse_pipeline(start, &line); - if (!line.cmd) break; + memset(&line,0,sizeof(struct pipeline)); + start = parse_pipeline(start, &line); + if (!line.cmd) break; - // Run those commands + // Run those commands - run_pipeline(&line); - llist_traverse(line.cmd, free_cmd); - } + run_pipeline(&line); + llist_traverse(line.cmd, free_cmd); + } } void cd_main(void) { - char *dest = *toys.optargs ? *toys.optargs : getenv("HOME"); - xchdir(dest); + char *dest = *toys.optargs ? *toys.optargs : getenv("HOME"); + xchdir(dest); } void exit_main(void) { - exit(*toys.optargs ? atoi(*toys.optargs) : 0); + exit(*toys.optargs ? atoi(*toys.optargs) : 0); } void sh_main(void) { - FILE *f; - - // Set up signal handlers and grab control of this tty. - if (CFG_SH_TTY) { - if (isatty(0)) toys.optflags |= 1; - } - f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL; - if (TT.command) handle(TT.command); - else { - size_t cmdlen = 0; - for (;;) { - char *command = 0; - if (!f) xputc('$'); - if (1 > getline(&command, &cmdlen, f ? f : stdin)) break; - handle(command); - free(command); - } - } - - toys.exitval = 1; + FILE *f; + + // Set up signal handlers and grab control of this tty. + if (CFG_SH_TTY) { + if (isatty(0)) toys.optflags |= 1; + } + f = *toys.optargs ? xfopen(*toys.optargs, "r") : NULL; + if (TT.command) handle(TT.command); + else { + size_t cmdlen = 0; + for (;;) { + char *command = 0; + if (!f) xputc('$'); + if (1 > getline(&command, &cmdlen, f ? f : stdin)) break; + handle(command); + free(command); + } + } + + toys.exitval = 1; } diff --git a/toys/posix/sleep.c b/toys/posix/sleep.c index c544e0ac..a83f1e56 100644 --- a/toys/posix/sleep.c +++ b/toys/posix/sleep.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * sleep.c - Wait for a number of seconds. +/* sleep.c - Wait for a number of seconds. * * Copyright 2007 Rob Landley <rob@landley.net> * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> @@ -10,20 +8,20 @@ USE_SLEEP(NEWTOY(sleep, "<1", TOYFLAG_BIN)) config SLEEP - bool "sleep" - default y - help - usage: sleep SECONDS + bool "sleep" + default y + help + usage: sleep SECONDS - Wait before exiting. + Wait before exiting. config SLEEP_FLOAT - bool - default y - depends on SLEEP && TOYBOX_FLOAT - help - The delay can be a decimal fraction. An optional suffix can be "m" - (minutes), "h" (hours), "d" (days), or "s" (seconds, the default). + bool + default y + depends on SLEEP && TOYBOX_FLOAT + help + The delay can be a decimal fraction. An optional suffix can be "m" + (minutes), "h" (hours), "d" (days), or "s" (seconds, the default). */ #include "toys.h" @@ -31,21 +29,21 @@ config SLEEP_FLOAT void sleep_main(void) { - if (!CFG_TOYBOX_FLOAT) toys.exitval = sleep(atol(*toys.optargs)); - else { - char *arg; - double d = strtod(*toys.optargs, &arg); - struct timespec tv; - - // Parse suffix - if (*arg) { - int ismhd[]={1,60,3600,86400}; - char *smhd = "smhd", *c = strchr(smhd, *arg); - if (!c) error_exit("Unknown suffix '%c'", *arg); - d *= ismhd[c-smhd]; - } - - tv.tv_nsec=1000000000*(d-(tv.tv_sec = (unsigned long)d)); - toys.exitval = !!nanosleep(&tv, NULL); - } + if (!CFG_TOYBOX_FLOAT) toys.exitval = sleep(atol(*toys.optargs)); + else { + char *arg; + double d = strtod(*toys.optargs, &arg); + struct timespec tv; + + // Parse suffix + if (*arg) { + int ismhd[]={1,60,3600,86400}; + char *smhd = "smhd", *c = strchr(smhd, *arg); + if (!c) error_exit("Unknown suffix '%c'", *arg); + d *= ismhd[c-smhd]; + } + + tv.tv_nsec=1000000000*(d-(tv.tv_sec = (unsigned long)d)); + toys.exitval = !!nanosleep(&tv, NULL); + } } diff --git a/toys/posix/sort.c b/toys/posix/sort.c index 8f26f5d3..41b020b9 100644 --- a/toys/posix/sort.c +++ b/toys/posix/sort.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * sort.c - put input lines into order +/* sort.c - put input lines into order * * Copyright 2004, 2008 Rob Landley <rob@landley.net> * @@ -9,54 +7,54 @@ USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")USE_SORT_BIG("S:T:m" "o:k*t:xbMcszdfi") "run", TOYFLAG_USR|TOYFLAG_BIN)) config SORT - bool "sort" - default y - help - usage: sort [-run] [FILE...] + bool "sort" + default y + help + usage: sort [-run] [FILE...] - Sort all lines of text from input files (or stdin) to stdout. + Sort all lines of text from input files (or stdin) to stdout. - -r reverse - -u unique lines only - -n numeric order (instead of alphabetical) + -r reverse + -u unique lines only + -n numeric order (instead of alphabetical) config SORT_BIG - bool "SuSv3 options (Support -ktcsbdfiozM)" - default y - depends on SORT - help - usage: sort [-bcdfiMsz] [-k#[,#[x]] [-t X]] [-o FILE] - - -b ignore leading blanks (or trailing blanks in second part of key) - -c check whether input is sorted - -d dictionary order (use alphanumeric and whitespace chars only) - -f force uppercase (case insensitive sort) - -i ignore nonprinting characters - -M month sort (jan, feb, etc). - -x Hexadecimal numerical sort - -s skip fallback sort (only sort with keys) - -z zero (null) terminated input - -k sort by "key" (see below) - -t use a key separator other than whitespace - -o output to FILE instead of stdout - - Sorting by key looks at a subset of the words on each line. -k2 - uses the second word to the end of the line, -k2,2 looks at only - the second word, -k2,4 looks from the start of the second to the end - of the fourth word. Specifying multiple keys uses the later keys as - tie breakers, in order. A type specifier appended to a sort key - (such as -2,2n) applies only to sorting that key. + bool "SuSv3 options (Support -ktcsbdfiozM)" + default y + depends on SORT + help + usage: sort [-bcdfiMsz] [-k#[,#[x]] [-t X]] [-o FILE] + + -b ignore leading blanks (or trailing blanks in second part of key) + -c check whether input is sorted + -d dictionary order (use alphanumeric and whitespace chars only) + -f force uppercase (case insensitive sort) + -i ignore nonprinting characters + -M month sort (jan, feb, etc). + -x Hexadecimal numerical sort + -s skip fallback sort (only sort with keys) + -z zero (null) terminated input + -k sort by "key" (see below) + -t use a key separator other than whitespace + -o output to FILE instead of stdout + + Sorting by key looks at a subset of the words on each line. -k2 + uses the second word to the end of the line, -k2,2 looks at only + the second word, -k2,4 looks from the start of the second to the end + of the fourth word. Specifying multiple keys uses the later keys as + tie breakers, in order. A type specifier appended to a sort key + (such as -2,2n) applies only to sorting that key. config SORT_FLOAT - bool "Floating point (-g)" - default y - depends on SORT_BIG - help - usage: sort [-g] + bool "Floating point (-g)" + default y + depends on SORT_BIG + help + usage: sort [-g] - This version of sort requires floating point. + This version of sort requires floating point. - -g general numeric sort (double precision with nan and inf) + -g general numeric sort (double precision with nan and inf) */ @@ -64,14 +62,14 @@ config SORT_FLOAT #include "toys.h" GLOBALS( - char *key_separator; - struct arg_list *raw_keys; - char *outfile; - char *ignore1, ignore2; // GNU compatability NOPs for -S and -T. - - void *key_list; - int linecount; - char **lines; + char *key_separator; + struct arg_list *raw_keys; + char *outfile; + char *ignore1, ignore2; // GNU compatability NOPs for -S and -T. + + void *key_list; + int linecount; + char **lines; ) // The sort types are n, g, and M. @@ -83,321 +81,320 @@ GLOBALS( struct sort_key { - struct sort_key *next_key; // linked list - unsigned range[4]; // start word, start char, end word, end char - int flags; + struct sort_key *next_key; // linked list + unsigned range[4]; // start word, start char, end word, end char + int flags; }; // Copy of the part of this string corresponding to a key/flags. static char *get_key_data(char *str, struct sort_key *key, int flags) { - int start=0, end, len, i, j; + int start=0, end, len, i, j; - // Special case whole string, so we don't have to make a copy + // Special case whole string, so we don't have to make a copy - if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] - && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str; + if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3] + && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str; - // Find start of key on first pass, end on second pass + // Find start of key on first pass, end on second pass - len = strlen(str); - for (j=0; j<2; j++) { - if (!key->range[2*j]) end=len; + len = strlen(str); + for (j=0; j<2; j++) { + if (!key->range[2*j]) end=len; - // Loop through fields - else { - end=0; - for (i=1; i < key->range[2*j]+j; i++) { + // Loop through fields + else { + end=0; + for (i=1; i < key->range[2*j]+j; i++) { - // Skip leading blanks - if (str[end] && !TT.key_separator) - while (isspace(str[end])) end++; + // Skip leading blanks + if (str[end] && !TT.key_separator) + while (isspace(str[end])) end++; - // Skip body of key - for (; str[end]; end++) { - if (TT.key_separator) { - if (str[end]==*TT.key_separator) break; - } else if (isspace(str[end])) break; - } - } + // Skip body of key + for (; str[end]; end++) { + if (TT.key_separator) { + if (str[end]==*TT.key_separator) break; + } else if (isspace(str[end])) break; } - if (!j) start=end; - } - - // Key with explicit separator starts after the separator - if (TT.key_separator && str[start]==*TT.key_separator) start++; - - // Strip leading and trailing whitespace if necessary - if (flags&FLAG_b) while (isspace(str[start])) start++; - if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--; - - // Handle offsets on start and end - if (key->range[3]) { - end += key->range[3]-1; - if (end>len) end=len; - } - if (key->range[1]) { - start += key->range[1]-1; - if (start>len) start=len; - } - - // Make the copy - if (end<start) end=start; - str = xstrndup(str+start, end-start); - - // Handle -d - if (flags&FLAG_d) { - for (start = end = 0; str[end]; end++) - if (isspace(str[end]) || isalnum(str[end])) str[start++] = str[end]; - str[start] = 0; - } - - // Handle -i - if (flags&FLAG_i) { - for (start = end = 0; str[end]; end++) - if (isprint(str[end])) str[start++] = str[end]; - str[start] = 0; + } } - - // Handle -f - if (flags*FLAG_f) for(i=0; str[i]; i++) str[i] = toupper(str[i]); - - return str; + if (!j) start=end; + } + + // Key with explicit separator starts after the separator + if (TT.key_separator && str[start]==*TT.key_separator) start++; + + // Strip leading and trailing whitespace if necessary + if (flags&FLAG_b) while (isspace(str[start])) start++; + if (flags&FLAG_bb) while (end>start && isspace(str[end-1])) end--; + + // Handle offsets on start and end + if (key->range[3]) { + end += key->range[3]-1; + if (end>len) end=len; + } + if (key->range[1]) { + start += key->range[1]-1; + if (start>len) start=len; + } + + // Make the copy + if (end<start) end=start; + str = xstrndup(str+start, end-start); + + // Handle -d + if (flags&FLAG_d) { + for (start = end = 0; str[end]; end++) + if (isspace(str[end]) || isalnum(str[end])) str[start++] = str[end]; + str[start] = 0; + } + + // Handle -i + if (flags&FLAG_i) { + for (start = end = 0; str[end]; end++) + if (isprint(str[end])) str[start++] = str[end]; + str[start] = 0; + } + + // Handle -f + if (flags*FLAG_f) for(i=0; str[i]; i++) str[i] = toupper(str[i]); + + return str; } // append a sort_key to key_list. static struct sort_key *add_key(void) { - void **stupid_compiler = &TT.key_list; - struct sort_key **pkey = (struct sort_key **)stupid_compiler; + void **stupid_compiler = &TT.key_list; + struct sort_key **pkey = (struct sort_key **)stupid_compiler; - while (*pkey) pkey = &((*pkey)->next_key); - return *pkey = xzalloc(sizeof(struct sort_key)); + while (*pkey) pkey = &((*pkey)->next_key); + return *pkey = xzalloc(sizeof(struct sort_key)); } // Perform actual comparison static int compare_values(int flags, char *x, char *y) { - int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x); - - // Ascii sort - if (!ff) return strcmp(x, y); + int ff = flags & (FLAG_n|FLAG_g|FLAG_M|FLAG_x); - if (CFG_SORT_FLOAT && ff == FLAG_g) { - char *xx,*yy; - double dx = strtod(x,&xx), dy = strtod(y,&yy); - int xinf, yinf; + // Ascii sort + if (!ff) return strcmp(x, y); - // not numbers < NaN < -infinity < numbers < +infinity + if (CFG_SORT_FLOAT && ff == FLAG_g) { + char *xx,*yy; + double dx = strtod(x,&xx), dy = strtod(y,&yy); + int xinf, yinf; - if (x==xx) return y==yy ? 0 : -1; - if (y==yy) return 1; + // not numbers < NaN < -infinity < numbers < +infinity - // Check for isnan - if (dx!=dx) return (dy!=dy) ? 0 : -1; - if (dy!=dy) return 1; + if (x==xx) return y==yy ? 0 : -1; + if (y==yy) return 1; - // Check for infinity. (Could underflow, but avoids needing libm.) - xinf = (1.0/dx == 0.0); - yinf = (1.0/dy == 0.0); - if (xinf) { - if(dx<0) return (yinf && dy<0) ? 0 : -1; - return (yinf && dy>0) ? 0 : 1; - } - if (yinf) return dy<0 ? 1 : -1; - - return dx>dy ? 1 : (dx<dy ? -1 : 0); - } else if (CFG_SORT_BIG && ff == FLAG_M) { - struct tm thyme; - int dx; - char *xx,*yy; - - xx = strptime(x,"%b",&thyme); - dx = thyme.tm_mon; - yy = strptime(y,"%b",&thyme); - if (!xx) return !yy ? 0 : -1; - else if (!yy) return 1; - else return dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon; - - } else if (CFG_SORT_BIG && ff == FLAG_x) { - return strtol(x, NULL, 16)-strtol(y, NULL, 16); - // This has to be ff == FLAG_n - } else { - // Full floating point version of -n - if (CFG_SORT_FLOAT) { - double dx = atof(x), dy = atof(y); + // Check for isnan + if (dx!=dx) return (dy!=dy) ? 0 : -1; + if (dy!=dy) return 1; - return dx>dy ? 1 : (dx<dy ? -1 : 0); - // Integer version of -n for tiny systems - } else return atoi(x)-atoi(y); + // Check for infinity. (Could underflow, but avoids needing libm.) + xinf = (1.0/dx == 0.0); + yinf = (1.0/dy == 0.0); + if (xinf) { + if(dx<0) return (yinf && dy<0) ? 0 : -1; + return (yinf && dy>0) ? 0 : 1; } + if (yinf) return dy<0 ? 1 : -1; + + return dx>dy ? 1 : (dx<dy ? -1 : 0); + } else if (CFG_SORT_BIG && ff == FLAG_M) { + struct tm thyme; + int dx; + char *xx,*yy; + + xx = strptime(x,"%b",&thyme); + dx = thyme.tm_mon; + yy = strptime(y,"%b",&thyme); + if (!xx) return !yy ? 0 : -1; + else if (!yy) return 1; + else return dx==thyme.tm_mon ? 0 : dx-thyme.tm_mon; + + } else if (CFG_SORT_BIG && ff == FLAG_x) { + return strtol(x, NULL, 16)-strtol(y, NULL, 16); + // This has to be ff == FLAG_n + } else { + // Full floating point version of -n + if (CFG_SORT_FLOAT) { + double dx = atof(x), dy = atof(y); + + return dx>dy ? 1 : (dx<dy ? -1 : 0); + // Integer version of -n for tiny systems + } else return atoi(x)-atoi(y); + } } - // Callback from qsort(): Iterate through key_list and perform comparisons. static int compare_keys(const void *xarg, const void *yarg) { - int flags = toys.optflags, retval = 0; - char *x, *y, *xx = *(char **)xarg, *yy = *(char **)yarg; - struct sort_key *key; - - if (CFG_SORT_BIG) { - for (key=(struct sort_key *)TT.key_list; !retval && key; - key = key->next_key) - { - flags = key->flags ? key->flags : toys.optflags; + int flags = toys.optflags, retval = 0; + char *x, *y, *xx = *(char **)xarg, *yy = *(char **)yarg; + struct sort_key *key; - // Chop out and modify key chunks, handling -dfib + if (CFG_SORT_BIG) { + for (key=(struct sort_key *)TT.key_list; !retval && key; + key = key->next_key) + { + flags = key->flags ? key->flags : toys.optflags; - x = get_key_data(xx, key, flags); - y = get_key_data(yy, key, flags); + // Chop out and modify key chunks, handling -dfib - retval = compare_values(flags, x, y); + x = get_key_data(xx, key, flags); + y = get_key_data(yy, key, flags); - // Free the copies get_key_data() made. + retval = compare_values(flags, x, y); - if (x != xx) free(x); - if (y != yy) free(y); + // Free the copies get_key_data() made. - if (retval) break; - } - } else retval = compare_values(flags, xx, yy); + if (x != xx) free(x); + if (y != yy) free(y); - // Perform fallback sort if necessary - if (!retval && !(CFG_SORT_BIG && (toys.optflags&FLAG_s))) { - retval = strcmp(xx, yy); - flags = toys.optflags; + if (retval) break; } + } else retval = compare_values(flags, xx, yy); + + // Perform fallback sort if necessary + if (!retval && !(CFG_SORT_BIG && (toys.optflags&FLAG_s))) { + retval = strcmp(xx, yy); + flags = toys.optflags; + } - return retval * ((flags&FLAG_r) ? -1 : 1); + return retval * ((flags&FLAG_r) ? -1 : 1); } // Callback from loopfiles to handle input files. static void sort_read(int fd, char *name) { - // Read each line from file, appending to a big array. - - for (;;) { - char * line = (CFG_SORT_BIG && (toys.optflags&FLAG_z)) - ? get_rawline(fd, NULL, 0) : get_line(fd); - - if (!line) break; - - // handle -c here so we don't allocate more memory than necessary. - if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) { - int j = (toys.optflags&FLAG_u) ? -1 : 0; - - if (TT.lines && compare_keys((void *)&TT.lines, &line)>j) - error_exit("%s: Check line %d\n", name, TT.linecount); - free(TT.lines); - TT.lines = (char **)line; - } else { - if (!(TT.linecount&63)) - TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64)); - TT.lines[TT.linecount] = line; - } - TT.linecount++; + // Read each line from file, appending to a big array. + + for (;;) { + char * line = (CFG_SORT_BIG && (toys.optflags&FLAG_z)) + ? get_rawline(fd, NULL, 0) : get_line(fd); + + if (!line) break; + + // handle -c here so we don't allocate more memory than necessary. + if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) { + int j = (toys.optflags&FLAG_u) ? -1 : 0; + + if (TT.lines && compare_keys((void *)&TT.lines, &line)>j) + error_exit("%s: Check line %d\n", name, TT.linecount); + free(TT.lines); + TT.lines = (char **)line; + } else { + if (!(TT.linecount&63)) + TT.lines = xrealloc(TT.lines, sizeof(char *)*(TT.linecount+64)); + TT.lines[TT.linecount] = line; } + TT.linecount++; + } } void sort_main(void) { - int idx, fd = 1; - - // Open output file if necessary. - if (CFG_SORT_BIG && TT.outfile) - fd = xcreate(TT.outfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); - - // Parse -k sort keys. - if (CFG_SORT_BIG && TT.raw_keys) { - struct arg_list *arg; - - for (arg = TT.raw_keys; arg; arg = arg->next) { - struct sort_key *key = add_key(); - char *temp; - int flag; - - idx = 0; - temp = arg->arg; - while (*temp) { - // Start of range - key->range[2*idx] = (unsigned)strtol(temp, &temp, 10); - if (*temp=='.') - key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10); - - // Handle flags appended to a key type. - for (;*temp;temp++) { - char *temp2, *optlist; - - // Note that a second comma becomes an "Unknown key" error. - - if (*temp==',' && !idx++) { - temp++; - break; - } - - // Which flag is this? - - optlist = toys.which->options; - temp2 = strchr(optlist, *temp); - flag = (1<<(optlist-temp2+strlen(optlist)-1)); - - // Was it a flag that can apply to a key? - - if (!temp2 || flag>FLAG_b - || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) - { - error_exit("Unknown key option."); - } - // b after , means strip _trailing_ space, not leading. - if (idx && flag==FLAG_b) flag = FLAG_bb; - key->flags |= flag; - } - } + int idx, fd = 1; + + // Open output file if necessary. + if (CFG_SORT_BIG && TT.outfile) + fd = xcreate(TT.outfile, O_CREAT|O_TRUNC|O_WRONLY, 0666); + + // Parse -k sort keys. + if (CFG_SORT_BIG && TT.raw_keys) { + struct arg_list *arg; + + for (arg = TT.raw_keys; arg; arg = arg->next) { + struct sort_key *key = add_key(); + char *temp; + int flag; + + idx = 0; + temp = arg->arg; + while (*temp) { + // Start of range + key->range[2*idx] = (unsigned)strtol(temp, &temp, 10); + if (*temp=='.') + key->range[(2*idx)+1] = (unsigned)strtol(temp+1, &temp, 10); + + // Handle flags appended to a key type. + for (;*temp;temp++) { + char *temp2, *optlist; + + // Note that a second comma becomes an "Unknown key" error. + + if (*temp==',' && !idx++) { + temp++; + break; + } + + // Which flag is this? + + optlist = toys.which->options; + temp2 = strchr(optlist, *temp); + flag = (1<<(optlist-temp2+strlen(optlist)-1)); + + // Was it a flag that can apply to a key? + + if (!temp2 || flag>FLAG_b + || (flag&(FLAG_u|FLAG_c|FLAG_s|FLAG_z))) + { + error_exit("Unknown key option."); + } + // b after , means strip _trailing_ space, not leading. + if (idx && flag==FLAG_b) flag = FLAG_bb; + key->flags |= flag; } + } } + } - // global b flag strips both leading and trailing spaces - if (toys.optflags&FLAG_b) toys.optflags |= FLAG_bb; + // global b flag strips both leading and trailing spaces + if (toys.optflags&FLAG_b) toys.optflags |= FLAG_bb; - // If no keys, perform alphabetic sort over the whole line. - if (CFG_SORT_BIG && !TT.key_list) add_key()->range[0] = 1; + // If no keys, perform alphabetic sort over the whole line. + if (CFG_SORT_BIG && !TT.key_list) add_key()->range[0] = 1; - // Open input files and read data, populating TT.lines[TT.linecount] - loopfiles(toys.optargs, sort_read); + // Open input files and read data, populating TT.lines[TT.linecount] + loopfiles(toys.optargs, sort_read); - // The compare (-c) logic was handled in sort_read(), - // so if we got here, we're done. - if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) goto exit_now; + // The compare (-c) logic was handled in sort_read(), + // so if we got here, we're done. + if (CFG_SORT_BIG && (toys.optflags&FLAG_c)) goto exit_now; - // Perform the actual sort - qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys); + // Perform the actual sort + qsort(TT.lines, TT.linecount, sizeof(char *), compare_keys); - // handle unique (-u) - if (toys.optflags&FLAG_u) { - int jdx; + // handle unique (-u) + if (toys.optflags&FLAG_u) { + int jdx; - for (jdx=0, idx=1; idx<TT.linecount; idx++) { - if (!compare_keys(&TT.lines[jdx], &TT.lines[idx])) - free(TT.lines[idx]); - else TT.lines[++jdx] = TT.lines[idx]; - } - if (TT.linecount) TT.linecount = jdx+1; + for (jdx=0, idx=1; idx<TT.linecount; idx++) { + if (!compare_keys(&TT.lines[jdx], &TT.lines[idx])) + free(TT.lines[idx]); + else TT.lines[++jdx] = TT.lines[idx]; } + if (TT.linecount) TT.linecount = jdx+1; + } - // Output result - for (idx = 0; idx<TT.linecount; idx++) { - char *s = TT.lines[idx]; - xwrite(fd, s, strlen(s)); - if (CFG_TOYBOX_FREE) free(s); - xwrite(fd, "\n", 1); - } + // Output result + for (idx = 0; idx<TT.linecount; idx++) { + char *s = TT.lines[idx]; + xwrite(fd, s, strlen(s)); + if (CFG_TOYBOX_FREE) free(s); + xwrite(fd, "\n", 1); + } exit_now: - if (CFG_TOYBOX_FREE) { - if (fd != 1) close(fd); - free(TT.lines); - } + if (CFG_TOYBOX_FREE) { + if (fd != 1) close(fd); + free(TT.lines); + } } diff --git a/toys/posix/tail.c b/toys/posix/tail.c index d0711c0c..bdbbfb30 100644 --- a/toys/posix/tail.c +++ b/toys/posix/tail.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * tail.c - copy last lines from input to stdout. +/* tail.c - copy last lines from input to stdout. * * Copyright 2012 Timothy Elliott <tle@holymonkey.com> * @@ -9,62 +7,62 @@ USE_TAIL(NEWTOY(tail, "fc-n-", TOYFLAG_BIN)) config TAIL - bool "tail" - default y - help - usage: tail [-n|c number] [-f] [file...] + bool "tail" + default y + help + usage: tail [-n|c number] [-f] [file...] - Copy last lines from files to stdout. If no files listed, copy from - stdin. Filename "-" is a synonym for stdin. + Copy last lines from files to stdout. If no files listed, copy from + stdin. Filename "-" is a synonym for stdin. - -n output the last X lines (default 10), +X counts from start. - -c output the last X bytes, +X counts from start - -f follow file, waiting for more data to be appended + -n output the last X lines (default 10), +X counts from start. + -c output the last X bytes, +X counts from start + -f follow file, waiting for more data to be appended config TAIL_SEEK - bool "tail seek support" - default y - depends on TAIL - help - This version uses lseek, which is faster on large files. + bool "tail seek support" + default y + depends on TAIL + help + This version uses lseek, which is faster on large files. */ #define FOR_tail #include "toys.h" GLOBALS( - long lines; - long bytes; + long lines; + long bytes; - int file_no; + int file_no; ) struct line_list { - struct line_list *next, *prev; - char *data; - int len; + struct line_list *next, *prev; + char *data; + int len; }; static struct line_list *get_chunk(int fd, int len) { - struct line_list *line = xmalloc(sizeof(struct line_list)+len); + struct line_list *line = xmalloc(sizeof(struct line_list)+len); - line->data = ((char *)line) + sizeof(struct line_list); - line->len = readall(fd, line->data, len); + line->data = ((char *)line) + sizeof(struct line_list); + line->len = readall(fd, line->data, len); - if (line->len < 1) { - free(line); - return 0; - } + if (line->len < 1) { + free(line); + return 0; + } - return line; + return line; } static void dump_chunk(void *ptr) { - struct line_list *list = ptr; - xwrite(1, list->data, list->len); - free(list); + struct line_list *list = ptr; + xwrite(1, list->data, list->len); + free(list); } // Reading through very large files is slow. Using lseek can speed things @@ -72,156 +70,156 @@ static void dump_chunk(void *ptr) // Note: bytes and lines are negative here. static int try_lseek(int fd, long bytes, long lines) { - struct line_list *list = 0, *temp; - int flag = 0, chunk = sizeof(toybuf); - ssize_t pos = lseek(fd, 0, SEEK_END); - - // If lseek() doesn't work on this stream, return now. - if (pos<0) return 0; - - // Seek to the right spot, output data from there. - if (bytes) { - if (lseek(fd, bytes, SEEK_END)<0) lseek(fd, 0, SEEK_SET); - xsendfile(fd, 1); - return 1; - } - - // Read from end to find enough lines, then output them. - - bytes = pos; - while (lines && pos) { - int offset; - - // Read in next chunk from end of file - if (chunk>pos) chunk = pos; - pos -= chunk; - if (pos != lseek(fd, pos, SEEK_SET)) { - perror_msg("seek failed"); - break; - } - if (!(temp = get_chunk(fd, chunk))) break; - if (list) list->next = temp; - list = temp; - - // Count newlines in this chunk. - offset = list->len; - while (offset--) { - // If the last line ends with a newline, that one doesn't count. - if (!flag) { - flag++; - - continue; - } - - // Start outputting data right after newline - if (list->data[offset] == '\n' && !++lines) { - offset++; - list->data += offset; - list->len -= offset; - - break; - } - } - } - - // Output stored data - llist_traverse(list, dump_chunk); - - // In case of -f - lseek(fd, bytes, SEEK_SET); - return 1; + struct line_list *list = 0, *temp; + int flag = 0, chunk = sizeof(toybuf); + ssize_t pos = lseek(fd, 0, SEEK_END); + + // If lseek() doesn't work on this stream, return now. + if (pos<0) return 0; + + // Seek to the right spot, output data from there. + if (bytes) { + if (lseek(fd, bytes, SEEK_END)<0) lseek(fd, 0, SEEK_SET); + xsendfile(fd, 1); + return 1; + } + + // Read from end to find enough lines, then output them. + + bytes = pos; + while (lines && pos) { + int offset; + + // Read in next chunk from end of file + if (chunk>pos) chunk = pos; + pos -= chunk; + if (pos != lseek(fd, pos, SEEK_SET)) { + perror_msg("seek failed"); + break; + } + if (!(temp = get_chunk(fd, chunk))) break; + if (list) list->next = temp; + list = temp; + + // Count newlines in this chunk. + offset = list->len; + while (offset--) { + // If the last line ends with a newline, that one doesn't count. + if (!flag) { + flag++; + + continue; + } + + // Start outputting data right after newline + if (list->data[offset] == '\n' && !++lines) { + offset++; + list->data += offset; + list->len -= offset; + + break; + } + } + } + + // Output stored data + llist_traverse(list, dump_chunk); + + // In case of -f + lseek(fd, bytes, SEEK_SET); + return 1; } // Called for each file listed on command line, and/or stdin static void do_tail(int fd, char *name) { - long bytes = TT.bytes, lines = TT.lines; - - if (toys.optc > 1) { - if (TT.file_no++) xputc('\n'); - xprintf("==> %s <==\n", name); - } - - // Are we measuring from the end of the file? - - if (bytes<0 || lines<0) { - struct line_list *list = 0, *new; - - // The slow codepath is always needed, and can handle all input, - // so make lseek support optional. - if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)); - - // Read data until we run out, keep a trailing buffer - else for (;;) { - int len, count; - char *try; - - if (!(new = get_chunk(fd, sizeof(toybuf)))) break; - // append in order - dlist_add_nomalloc((struct double_list **)&list, - (struct double_list *)new); - - // Measure new chunk, discarding extra data from buffer - len = new->len; - try = new->data; - for (count=0; count<len; count++) { - if ((toys.optflags & FLAG_c) && bytes) { - bytes++; - continue; - } - - if (lines) { - if(try[count] != '\n' && count != len-1) continue; - if (lines<0) { - if (!++lines) ++lines; - continue; - } - } - - // Time to discard data; given that bytes and lines were - // nonzero coming in, we can't discard too much if we're - // measuring right. - do { - char c = *(list->data++); - if (!(--list->len)) { - struct line_list *next = list->next; - list->prev->next = next; - list->next->prev = list->prev; - free(list); - list = next; - } - if (c == '\n') break; - } while (lines); - } - } - - // Output/free the buffer. - llist_traverse(list, dump_chunk); - - // Measuring from the beginning of the file. - } else for (;;) { - int len, offset = 0; - - // Error while reading does not exit. Error writing does. - len = read(fd, toybuf, sizeof(toybuf)); - if (len<1) break; - while (bytes > 1 || lines > 1) { - bytes--; - if (toybuf[offset++] == '\n') lines--; - if (offset >= len) break; - } - if (offset<len) xwrite(1, toybuf+offset, len-offset); - } - - // -f support: cache name/descriptor + long bytes = TT.bytes, lines = TT.lines; + + if (toys.optc > 1) { + if (TT.file_no++) xputc('\n'); + xprintf("==> %s <==\n", name); + } + + // Are we measuring from the end of the file? + + if (bytes<0 || lines<0) { + struct line_list *list = 0, *new; + + // The slow codepath is always needed, and can handle all input, + // so make lseek support optional. + if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)); + + // Read data until we run out, keep a trailing buffer + else for (;;) { + int len, count; + char *try; + + if (!(new = get_chunk(fd, sizeof(toybuf)))) break; + // append in order + dlist_add_nomalloc((struct double_list **)&list, + (struct double_list *)new); + + // Measure new chunk, discarding extra data from buffer + len = new->len; + try = new->data; + for (count=0; count<len; count++) { + if ((toys.optflags & FLAG_c) && bytes) { + bytes++; + continue; + } + + if (lines) { + if(try[count] != '\n' && count != len-1) continue; + if (lines<0) { + if (!++lines) ++lines; + continue; + } + } + + // Time to discard data; given that bytes and lines were + // nonzero coming in, we can't discard too much if we're + // measuring right. + do { + char c = *(list->data++); + if (!(--list->len)) { + struct line_list *next = list->next; + list->prev->next = next; + list->next->prev = list->prev; + free(list); + list = next; + } + if (c == '\n') break; + } while (lines); + } + } + + // Output/free the buffer. + llist_traverse(list, dump_chunk); + + // Measuring from the beginning of the file. + } else for (;;) { + int len, offset = 0; + + // Error while reading does not exit. Error writing does. + len = read(fd, toybuf, sizeof(toybuf)); + if (len<1) break; + while (bytes > 1 || lines > 1) { + bytes--; + if (toybuf[offset++] == '\n') lines--; + if (offset >= len) break; + } + if (offset<len) xwrite(1, toybuf+offset, len-offset); + } + + // -f support: cache name/descriptor } void tail_main(void) { - // if nothing specified, default -n to -10 - if (!(toys.optflags&(FLAG_n|FLAG_c))) TT.lines = -10; + // if nothing specified, default -n to -10 + if (!(toys.optflags&(FLAG_n|FLAG_c))) TT.lines = -10; - loopfiles(toys.optargs, do_tail); + loopfiles(toys.optargs, do_tail); - // do -f stuff + // do -f stuff } diff --git a/toys/posix/tee.c b/toys/posix/tee.c index e6342f4c..03885109 100644 --- a/toys/posix/tee.c +++ b/toys/posix/tee.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * tee.c - cat to multiple outputs. +/* tee.c - cat to multiple outputs. * * Copyright 2008 Rob Landley <rob@landley.net> * @@ -9,66 +7,65 @@ USE_TEE(NEWTOY(tee, "ia", TOYFLAG_BIN)) config TEE - bool "tee" - default y - help - usage: tee [-ai] [file...] + bool "tee" + default y + help + usage: tee [-ai] [file...] - Copy stdin to each listed file, and also to stdout. - Filename "-" is a synonym for stdout. + Copy stdin to each listed file, and also to stdout. + Filename "-" is a synonym for stdout. - -a append to files. - -i ignore SIGINT. + -a append to files. + -i ignore SIGINT. */ #define FOR_tee #include "toys.h" GLOBALS( - void *outputs; + void *outputs; ) struct fd_list { - struct fd_list *next; - int fd; + struct fd_list *next; + int fd; }; // Open each output file, saving filehandles to a linked list. static void do_tee_open(int fd, char *name) { - struct fd_list *temp; + struct fd_list *temp; - temp = xmalloc(sizeof(struct fd_list)); - temp->next = TT.outputs; - temp->fd = fd; - TT.outputs = temp; + temp = xmalloc(sizeof(struct fd_list)); + temp->next = TT.outputs; + temp->fd = fd; + TT.outputs = temp; } void tee_main(void) { - if (toys.optflags & FLAG_i) signal(SIGINT, SIG_IGN); + if (toys.optflags & FLAG_i) signal(SIGINT, SIG_IGN); - // Open output files - loopfiles_rw(toys.optargs, - O_RDWR|O_CREAT|((toys.optflags & FLAG_a)?O_APPEND:O_TRUNC), - 0666, 0, do_tee_open); + // Open output files + loopfiles_rw(toys.optargs, + O_RDWR|O_CREAT|((toys.optflags & FLAG_a)?O_APPEND:O_TRUNC), + 0666, 0, do_tee_open); - for (;;) { - struct fd_list *fdl; - int len; + for (;;) { + struct fd_list *fdl; + int len; - // Read data from stdin - len = xread(0, toybuf, sizeof(toybuf)); - if (len<1) break; + // Read data from stdin + len = xread(0, toybuf, sizeof(toybuf)); + if (len<1) break; - // Write data to each output file, plus stdout. - fdl = TT.outputs; - for (;;) { - if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1; - if (!fdl) break; - fdl = fdl->next; - } + // Write data to each output file, plus stdout. + fdl = TT.outputs; + for (;;) { + if(len != writeall(fdl ? fdl->fd : 1, toybuf, len)) toys.exitval=1; + if (!fdl) break; + fdl = fdl->next; } - + } } diff --git a/toys/posix/true.c b/toys/posix/true.c index e2e7ea62..09e551c3 100644 --- a/toys/posix/true.c +++ b/toys/posix/true.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * true.c - Return zero. +/* true.c - Return zero. * * Copyright 2007 Rob Landley <rob@landley.net> * @@ -9,15 +7,15 @@ USE_TRUE(NEWTOY(true, NULL, TOYFLAG_BIN)) config TRUE - bool "true" - default y - help - Return zero. + bool "true" + default y + help + Return zero. */ #include "toys.h" void true_main(void) { - return; + return; } diff --git a/toys/posix/tty.c b/toys/posix/tty.c index 661e919a..578c9aff 100644 --- a/toys/posix/tty.c +++ b/toys/posix/tty.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * tty.c - Show stdin's terminal name +/* tty.c - Show stdin's terminal name * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,24 +7,24 @@ USE_TTY(NEWTOY(tty, "s", TOYFLAG_USR|TOYFLAG_BIN)) config TTY - bool "tty" - default y - help - Show filename of terminal connected to stdin. + bool "tty" + default y + help + Show filename of terminal connected to stdin. - Prints "not a tty" and exits with nonzero status if no terminal - is connected to stdin. + Prints "not a tty" and exits with nonzero status if no terminal + is connected to stdin. - -s silent mode + -s silent mode */ #include "toys.h" void tty_main(void) { - char *tty = ttyname(0); + char *tty = ttyname(0); - if (!toys.optflags) puts(tty ? tty : "not a tty"); + if (!toys.optflags) puts(tty ? tty : "not a tty"); - toys.exitval = !tty; + toys.exitval = !tty; } diff --git a/toys/posix/uname.c b/toys/posix/uname.c index fcc92a08..2c1a0504 100644 --- a/toys/posix/uname.c +++ b/toys/posix/uname.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * uname.c - return system name +/* uname.c - return system name * * Copyright 2008 Rob Landley <rob@landley.net> * @@ -9,19 +7,19 @@ USE_UNAME(NEWTOY(uname, "amvrns", TOYFLAG_BIN)) config UNAME - bool "uname" - default y - help - usage: uname [-asnrvmpio] + bool "uname" + default y + help + usage: uname [-asnrvmpio] - Print system information. + Print system information. - -s System name - -n Network (domain) name - -r Release number - -v Version (build date) - -m Machine (hardware) name - -a All of the above + -s System name + -n Network (domain) name + -r Release number + -v Version (build date) + -m Machine (hardware) name + -a All of the above */ #define FOR_uname @@ -42,34 +40,34 @@ config UNAME void uname_main(void) { - int i, flags = toys.optflags, needspace=0; + int i, flags = toys.optflags, needspace=0; - uname((void *)toybuf); + uname((void *)toybuf); - if (!flags) flags = FLAG_s; - for (i=0; i<5; i++) { - char *c = toybuf+(65*i); + if (!flags) flags = FLAG_s; + for (i=0; i<5; i++) { + char *c = toybuf+(65*i); - if (flags & ((1<<i)|FLAG_a)) { - int len = strlen(c); + if (flags & ((1<<i)|FLAG_a)) { + int len = strlen(c); - // This problem originates in autoconf, so of course the solution - // is horribly ugly. + // This problem originates in autoconf, so of course the solution + // is horribly ugly. #ifdef GROSS - if (i==4 && !strcmp(c,"x86_64")) { - printf(GROSS); - continue; - } + if (i==4 && !strcmp(c,"x86_64")) { + printf(GROSS); + continue; + } #endif - if (needspace++) { - // We can't decrement on the first entry, because - // needspace would be 0 - *(--c)=' '; - len++; - } - xwrite(1, c, len); - } - } - putchar('\n'); + if (needspace++) { + // We can't decrement on the first entry, because + // needspace would be 0 + *(--c)=' '; + len++; + } + xwrite(1, c, len); + } + } + putchar('\n'); } diff --git a/toys/posix/uniq.c b/toys/posix/uniq.c index f42b7293..bd41d4af 100644 --- a/toys/posix/uniq.c +++ b/toys/posix/uniq.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * uniq.c - report or filter out repeated lines in a file +/* uniq.c - report or filter out repeated lines in a file * * Copyright 2012 Georgi Chorbadzhiyski <georgi@unixsol.org> * @@ -9,116 +7,113 @@ USE_UNIQ(NEWTOY(uniq, "f#s#w#zicdu", TOYFLAG_BIN)) config UNIQ - bool "uniq" - default y - help - usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]] - - Report or filter out repeated lines in a file - - -c show counts before each line - -d show only lines that are repeated - -u show only lines that are unique - -i ignore case when comparing lines - -z lines end with \0 not \n - -w compare maximum X chars per line - -f ignore first X fields - -s ignore first X chars + bool "uniq" + default y + help + usage: uniq [-cduiz] [-w maxchars] [-f fields] [-s char] [input_file [output_file]] + + Report or filter out repeated lines in a file + + -c show counts before each line + -d show only lines that are repeated + -u show only lines that are unique + -i ignore case when comparing lines + -z lines end with \0 not \n + -w compare maximum X chars per line + -f ignore first X fields + -s ignore first X chars */ #define FOR_uniq #include "toys.h" GLOBALS( - long maxchars; - long nchars; - long nfields; - long repeats; + long maxchars; + long nchars; + long nfields; + long repeats; ) static char *skip(char *str) { - long nchars = TT.nchars, nfields; - - // Skip fields first - for (nfields = TT.nfields; nfields; str++) { - while (*str && isspace(*str)) str++; - while (*str && !isspace(*str)) str++; - nfields--; - } - // Skip chars - while (*str && nchars--) str++; - - return str; + long nchars = TT.nchars, nfields; + + // Skip fields first + for (nfields = TT.nfields; nfields; str++) { + while (*str && isspace(*str)) str++; + while (*str && !isspace(*str)) str++; + nfields--; + } + // Skip chars + while (*str && nchars--) str++; + + return str; } static void print_line(FILE *f, char *line) { - if (toys.optflags & (TT.repeats ? FLAG_u : FLAG_d)) return; - if (toys.optflags & FLAG_c) fprintf(f, "%7lu ", TT.repeats + 1); - fputs(line, f); - if (toys.optflags & FLAG_z) fputc(0, f); + if (toys.optflags & (TT.repeats ? FLAG_u : FLAG_d)) return; + if (toys.optflags & FLAG_c) fprintf(f, "%7lu ", TT.repeats + 1); + fputs(line, f); + if (toys.optflags & FLAG_z) fputc(0, f); } void uniq_main(void) { - FILE *infile = stdin, *outfile = stdout; - char *thisline = NULL, *prevline = NULL, *tmpline, eol = '\n'; - size_t thissize, prevsize = 0, tmpsize; - - if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r"); - if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w"); - - if (toys.optflags & FLAG_z) eol = 0; - - // If first line can't be read - if (getdelim(&prevline, &prevsize, eol, infile) < 0) - return; - - while (getdelim(&thisline, &thissize, eol, infile) > 0) { - int diff; - char *t1, *t2; - - // If requested get the chosen fields + character offsets. - if (TT.nfields || TT.nchars) { - t1 = skip(thisline); - t2 = skip(prevline); - } else { - t1 = thisline; - t2 = prevline; - } - - if (TT.maxchars == 0) { - diff = !(toys.optflags & FLAG_i) - ? strcmp(t1, t2) - : strcasecmp(t1, t2); - } else { - diff = !(toys.optflags & FLAG_i) - ? strncmp(t1, t2, TT.maxchars) - : strncasecmp(t1, t2, TT.maxchars); - } - - if (diff == 0) { // same - TT.repeats++; - } else { - print_line(outfile, prevline); - - TT.repeats = 0; - - tmpline = prevline; - prevline = thisline; - thisline = tmpline; - - tmpsize = prevsize; - prevsize = thissize; - thissize = tmpsize; - } - } - - print_line(outfile, prevline); - - if (CFG_TOYBOX_FREE) { - free(prevline); - free(thisline); - } + FILE *infile = stdin, *outfile = stdout; + char *thisline = NULL, *prevline = NULL, *tmpline, eol = '\n'; + size_t thissize, prevsize = 0, tmpsize; + + if (toys.optc >= 1) infile = xfopen(toys.optargs[0], "r"); + if (toys.optc >= 2) outfile = xfopen(toys.optargs[1], "w"); + + if (toys.optflags & FLAG_z) eol = 0; + + // If first line can't be read + if (getdelim(&prevline, &prevsize, eol, infile) < 0) + return; + + while (getdelim(&thisline, &thissize, eol, infile) > 0) { + int diff; + char *t1, *t2; + + // If requested get the chosen fields + character offsets. + if (TT.nfields || TT.nchars) { + t1 = skip(thisline); + t2 = skip(prevline); + } else { + t1 = thisline; + t2 = prevline; + } + + if (TT.maxchars == 0) { + diff = !(toys.optflags & FLAG_i) ? strcmp(t1, t2) : strcasecmp(t1, t2); + } else { + diff = !(toys.optflags & FLAG_i) ? strncmp(t1, t2, TT.maxchars) + : strncasecmp(t1, t2, TT.maxchars); + } + + if (diff == 0) { // same + TT.repeats++; + } else { + print_line(outfile, prevline); + + TT.repeats = 0; + + tmpline = prevline; + prevline = thisline; + thisline = tmpline; + + tmpsize = prevsize; + prevsize = thissize; + thissize = tmpsize; + } + } + + print_line(outfile, prevline); + + if (CFG_TOYBOX_FREE) { + free(prevline); + free(thisline); + } } diff --git a/toys/posix/unlink.c b/toys/posix/unlink.c index 19660c5d..4faef9dc 100644 --- a/toys/posix/unlink.c +++ b/toys/posix/unlink.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * unlink.c - delete one file +/* unlink.c - delete one file * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,18 +7,18 @@ USE_UNLINK(NEWTOY(unlink, "<1>1", TOYFLAG_USR|TOYFLAG_BIN)) config UNLINK - bool "unlink" - default y - help - usage: unlink FILE + bool "unlink" + default y + help + usage: unlink FILE - Deletes one file. + Deletes one file. */ #include "toys.h" void unlink_main(void) { - if (unlink(*toys.optargs)) - perror_exit("Couldn't unlink `%s'", *toys.optargs); + if (unlink(*toys.optargs)) + perror_exit("Couldn't unlink `%s'", *toys.optargs); } diff --git a/toys/posix/wc.c b/toys/posix/wc.c index 3896b73a..19ba4b8b 100644 --- a/toys/posix/wc.c +++ b/toys/posix/wc.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * wc.c - Word count +/* wc.c - Word count * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,90 +7,88 @@ USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN)) config WC - bool "wc" - default y - help - usage: wc -lwcm [FILE...] + bool "wc" + default y + help + usage: wc -lwcm [FILE...] - Count lines, words, and characters in input. + Count lines, words, and characters in input. - -l show lines - -w show words - -c show bytes - -m show characters + -l show lines + -w show words + -c show bytes + -m show characters - By default outputs lines, words, bytes, and filename for each - argument (or from stdin if none). Displays only either bytes - or characters. + By default outputs lines, words, bytes, and filename for each + argument (or from stdin if none). Displays only either bytes + or characters. */ #define FOR_wc #include "toys.h" GLOBALS( - unsigned long totals[3]; + unsigned long totals[3]; ) static void show_lengths(unsigned long *lengths, char *name) { - int i, nospace = 1; - for (i=0; i<3; i++) { - if (!toys.optflags || (toys.optflags&(1<<i))) { - xprintf(" %ld"+nospace, lengths[i]); - nospace = 0; - } - TT.totals[i] += lengths[i]; - } - if (*toys.optargs) xprintf(" %s", name); - xputc('\n'); + int i, nospace = 1; + for (i=0; i<3; i++) { + if (!toys.optflags || (toys.optflags&(1<<i))) { + xprintf(" %ld"+nospace, lengths[i]); + nospace = 0; + } + TT.totals[i] += lengths[i]; + } + if (*toys.optargs) xprintf(" %s", name); + xputc('\n'); } static void do_wc(int fd, char *name) { - int i, len, clen=1, space; - wchar_t wchar; - unsigned long word=0, lengths[]={0,0,0}; + int i, len, clen=1, space; + wchar_t wchar; + unsigned long word=0, lengths[]={0,0,0}; - for (;;) { - len = read(fd, toybuf, sizeof(toybuf)); - if (len<0) { - perror_msg("%s",name); - toys.exitval = EXIT_FAILURE; - } - if (len<1) break; - for (i=0; i<len; i+=clen) { - if(toys.optflags&8) { - clen = mbrtowc(&wchar, toybuf+i, len-i, 0); - if(clen==(size_t)(-1)) { - if(i!=len-1) { - clen = 1; - continue; - } - else break; - } - if(clen==(size_t)(-2)) break; - if(clen==0) clen=1; - space = iswspace(wchar); - } - else space = isspace(toybuf[i]); + for (;;) { + len = read(fd, toybuf, sizeof(toybuf)); + if (len<0) { + perror_msg("%s",name); + toys.exitval = EXIT_FAILURE; + } + if (len<1) break; + for (i=0; i<len; i+=clen) { + if(toys.optflags&8) { + clen = mbrtowc(&wchar, toybuf+i, len-i, 0); + if(clen==(size_t)(-1)) { + if(i!=len-1) { + clen = 1; + continue; + } else break; + } + if(clen==(size_t)(-2)) break; + if(clen==0) clen=1; + space = iswspace(wchar); + } else space = isspace(toybuf[i]); - if (toybuf[i]==10) lengths[0]++; - if (space) word=0; - else { - if (!word) lengths[1]++; - word=1; - } - lengths[2]++; - } - } + if (toybuf[i]==10) lengths[0]++; + if (space) word=0; + else { + if (!word) lengths[1]++; + word=1; + } + lengths[2]++; + } + } - show_lengths(lengths, name); + show_lengths(lengths, name); } void wc_main(void) { - setlocale(LC_ALL, ""); - toys.optflags |= (toys.optflags&8)>>1; - loopfiles(toys.optargs, do_wc); - if (toys.optc>1) show_lengths(TT.totals, "total"); + setlocale(LC_ALL, ""); + toys.optflags |= (toys.optflags&8)>>1; + loopfiles(toys.optargs, do_wc); + if (toys.optc>1) show_lengths(TT.totals, "total"); } diff --git a/toys/posix/who.c b/toys/posix/who.c index 5f888d71..d09a9325 100644 --- a/toys/posix/who.c +++ b/toys/posix/who.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * who.c - display who is on the system +/* who.c - display who is on the system * * Copyright 2012 ProFUSION Embedded Systems * @@ -11,36 +9,35 @@ USE_WHO(NEWTOY(who, NULL, TOYFLAG_BIN)) config WHO - bool "who" - default n - help - usage: who - - Print logged user information on system + bool "who" + default n + help + usage: who + Print logged user information on system */ #include "toys.h" void who_main(void) { - struct utmpx *entry; - - setutxent(); + struct utmpx *entry; - while ((entry = getutxent())) { - if (entry->ut_type == USER_PROCESS) { - time_t time; - int time_size; - char * times; + setutxent(); - time = entry->ut_tv.tv_sec; - times = ctime(&time); - time_size = strlen(times) - 2; - printf("%s\t%s\t%*.*s\t(%s)\n", entry->ut_user, entry->ut_line, time_size, time_size, ctime(&time), entry->ut_host); + while ((entry = getutxent())) { + if (entry->ut_type == USER_PROCESS) { + time_t time; + int time_size; + char * times; - } + time = entry->ut_tv.tv_sec; + times = ctime(&time); + time_size = strlen(times) - 2; + printf("%s\t%s\t%*.*s\t(%s)\n", entry->ut_user, entry->ut_line, + time_size, time_size, ctime(&time), entry->ut_host); } + } - endutxent(); + endutxent(); } diff --git a/toys/posix/xargs.c b/toys/posix/xargs.c index 8f19d07f..18b70f2e 100644 --- a/toys/posix/xargs.c +++ b/toys/posix/xargs.c @@ -1,6 +1,4 @@ -/* vi: set sw=4 ts=4: - * - * xargs.c - Run command with arguments taken from stdin. +/* xargs.c - Run command with arguments taken from stdin. * * Copyright 2011 Rob Landley <rob@landley.net> * @@ -9,42 +7,42 @@ USE_XARGS(NEWTOY(xargs, "^I:E:L#ptxrn#<1s#0", TOYFLAG_USR|TOYFLAG_BIN)) config XARGS - bool "xargs" - default y - help - usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND... - - Run command line one or more times, appending arguments from stdin. - - If command exits with 255, don't launch another even if arguments remain. - - -s Size in bytes per command line - -n Max number of arguments per command - -0 Each argument is NULL terminated, no whitespace or quote processing - #-p Prompt for y/n from tty before running each command - #-t Trace, print command line to stderr - #-x Exit if can't fit everything in one command - #-r Don't run command with empty input - #-L Max number of lines of input per command - -E stop at line matching string + bool "xargs" + default y + help + usage: xargs [-ptxr0] [-s NUM] [-n NUM] [-L NUM] [-E STR] COMMAND... + + Run command line one or more times, appending arguments from stdin. + + If command exits with 255, don't launch another even if arguments remain. + + -s Size in bytes per command line + -n Max number of arguments per command + -0 Each argument is NULL terminated, no whitespace or quote processing + #-p Prompt for y/n from tty before running each command + #-t Trace, print command line to stderr + #-x Exit if can't fit everything in one command + #-r Don't run command with empty input + #-L Max number of lines of input per command + -E stop at line matching string */ #define FOR_xargs #include "toys.h" GLOBALS( - long max_bytes; - long max_entries; - long L; - char *eofstr; - char *I; - - long entries, bytes; - char delim; + long max_bytes; + long max_entries; + long L; + char *eofstr; + char *I; + + long entries, bytes; + char delim; ) // If out==NULL count TT.bytes and TT.entries, stopping at max. -// Otherwise, fill out out[] +// Otherwise, fill out out[] // Returning NULL means need more data. // Returning char * means hit data limits, start of data left over @@ -53,135 +51,135 @@ GLOBALS( static char *handle_entries(char *data, char **entry) { - if (TT.delim) { - char *s = data; - - // Chop up whitespace delimited string into args - while (*s) { - char *save; - - while (isspace(*s)) { - if (entry) *s = 0; - s++; - } - - if (TT.max_entries && TT.entries >= TT.max_entries) - return *s ? s : (char *)1; - - if (!*s) break; - save = s; - - for (;;) { - if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save; - if (!*s || isspace(*s)) break; - s++; - } - if (TT.eofstr) { - int len = s-save; - if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len)) - return (char *)2; - } - if (entry) entry[TT.entries] = save; - ++TT.entries; - } - - // -0 support - } else { - TT.bytes += strlen(data)+1; - if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data; - if (TT.max_entries && TT.entries >= TT.max_entries) - return (char *)1; - if (entry) entry[TT.entries] = data; - TT.entries++; - } - - return NULL; + if (TT.delim) { + char *s = data; + + // Chop up whitespace delimited string into args + while (*s) { + char *save; + + while (isspace(*s)) { + if (entry) *s = 0; + s++; + } + + if (TT.max_entries && TT.entries >= TT.max_entries) + return *s ? s : (char *)1; + + if (!*s) break; + save = s; + + for (;;) { + if (++TT.bytes >= TT.max_bytes && TT.max_bytes) return save; + if (!*s || isspace(*s)) break; + s++; + } + if (TT.eofstr) { + int len = s-save; + if (len == strlen(TT.eofstr) && !strncmp(save, TT.eofstr, len)) + return (char *)2; + } + if (entry) entry[TT.entries] = save; + ++TT.entries; + } + + // -0 support + } else { + TT.bytes += strlen(data)+1; + if (TT.max_bytes && TT.bytes >= TT.max_bytes) return data; + if (TT.max_entries && TT.entries >= TT.max_entries) + return (char *)1; + if (entry) entry[TT.entries] = data; + TT.entries++; + } + + return NULL; } void xargs_main(void) { - struct double_list *dlist = NULL; - int entries, bytes, done = 0, status; - char *data = NULL; - - if (!(toys.optflags & FLAG_0)) TT.delim = '\n'; - - // If no optargs, call echo. - if (!toys.optc) { - free(toys.optargs); - *(toys.optargs = xzalloc(2*sizeof(char *)))="echo"; - toys.optc = 1; - } - - for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) - bytes += strlen(toys.optargs[entries]); - - // Loop through exec chunks. - while (data || !done) { - char **out; - - TT.entries = 0; - TT.bytes = bytes; - - // Loop reading input - for (;;) { - - // Read line - if (!data) { - ssize_t l = 0; - l = getdelim(&data, (size_t *)&l, TT.delim, stdin); - - if (l<0) { - data = 0; - done++; - break; - } - } - dlist_add(&dlist, data); - - // Count data used - data = handle_entries(data, NULL); - if (!data) continue; - if (data == (char *)2) done++; - if ((long)data <= 2) data = 0; - else data = xstrdup(data); - - break; - } - - // Accumulate cally thing - - if (data && !TT.entries) error_exit("argument too long"); - out = xzalloc((entries+TT.entries+1)*sizeof(char *)); - - if (dlist) { - struct double_list *dtemp; - - // Fill out command line to exec - memcpy(out, toys.optargs, entries*sizeof(char *)); - TT.entries = 0; - TT.bytes = bytes; - dlist->prev->next = 0; - for (dtemp = dlist; dtemp; dtemp = dtemp->next) - handle_entries(dtemp->data, out+entries); - } - pid_t pid=fork(); - if (!pid) { - xclose(0); - open("/dev/null", O_RDONLY); - xexec(out); - } - waitpid(pid, &status, 0); - status = WEXITSTATUS(status); - - // Abritrary number of execs, can't just leak memory each time... - while (dlist) { - struct double_list *dtemp = dlist->next; - - free(dlist->data); - free(dlist); - dlist = dtemp; - } - free(out); - } + struct double_list *dlist = NULL; + int entries, bytes, done = 0, status; + char *data = NULL; + + if (!(toys.optflags & FLAG_0)) TT.delim = '\n'; + + // If no optargs, call echo. + if (!toys.optc) { + free(toys.optargs); + *(toys.optargs = xzalloc(2*sizeof(char *)))="echo"; + toys.optc = 1; + } + + for (entries = 0, bytes = -1; entries < toys.optc; entries++, bytes++) + bytes += strlen(toys.optargs[entries]); + + // Loop through exec chunks. + while (data || !done) { + char **out; + + TT.entries = 0; + TT.bytes = bytes; + + // Loop reading input + for (;;) { + + // Read line + if (!data) { + ssize_t l = 0; + l = getdelim(&data, (size_t *)&l, TT.delim, stdin); + + if (l<0) { + data = 0; + done++; + break; + } + } + dlist_add(&dlist, data); + + // Count data used + data = handle_entries(data, NULL); + if (!data) continue; + if (data == (char *)2) done++; + if ((long)data <= 2) data = 0; + else data = xstrdup(data); + + break; + } + + // Accumulate cally thing + + if (data && !TT.entries) error_exit("argument too long"); + out = xzalloc((entries+TT.entries+1)*sizeof(char *)); + + if (dlist) { + struct double_list *dtemp; + + // Fill out command line to exec + memcpy(out, toys.optargs, entries*sizeof(char *)); + TT.entries = 0; + TT.bytes = bytes; + dlist->prev->next = 0; + for (dtemp = dlist; dtemp; dtemp = dtemp->next) + handle_entries(dtemp->data, out+entries); + } + pid_t pid=fork(); + if (!pid) { + xclose(0); + open("/dev/null", O_RDONLY); + xexec(out); + } + waitpid(pid, &status, 0); + status = WEXITSTATUS(status); + + // Abritrary number of execs, can't just leak memory each time... + while (dlist) { + struct double_list *dtemp = dlist->next; + + free(dlist->data); + free(dlist); + dlist = dtemp; + } + free(out); + } } |