From 02d288d89683e99fd18fe9f54d4e731a6c474a4f Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Thu, 12 Apr 2012 01:38:35 -0400 Subject: initial check-in --- src/basename.c | 33 +++++++++++++++ src/cat.c | 82 +++++++++++++++++++++++++++++++++++ src/dirname.c | 28 ++++++++++++ src/false.c | 4 ++ src/fold.c | 123 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/iconv.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ src/link.c | 23 ++++++++++ src/ls.c | 80 ++++++++++++++++++++++++++++++++++ src/pwd.c | 90 +++++++++++++++++++++++++++++++++++++++ src/strings.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tr.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/true.c | 4 ++ src/wc.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++ 13 files changed, 943 insertions(+) create mode 100644 src/basename.c create mode 100644 src/cat.c create mode 100644 src/dirname.c create mode 100644 src/false.c create mode 100644 src/fold.c create mode 100644 src/iconv.c create mode 100644 src/link.c create mode 100644 src/ls.c create mode 100644 src/pwd.c create mode 100644 src/strings.c create mode 100644 src/tr.c create mode 100644 src/true.c create mode 100644 src/wc.c (limited to 'src') diff --git a/src/basename.c b/src/basename.c new file mode 100644 index 0000000..25b8b24 --- /dev/null +++ b/src/basename.c @@ -0,0 +1,33 @@ +#include +#include +#include + +static int my_write(int fd, const char *s, size_t l) +{ + if (!l) l = strlen(s); + while (l) { + ssize_t n = write(fd, s, l); + if (n<0) return -1; + s += n; l -= n; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char *s; + if ((unsigned)argc - 2 > 1) { + my_write(2, argv[0], 0); + my_write(2, ": missing operand\n", 0); + return 1; + } + s = basename(argv[1]); + if (argc > 2) { + size_t k = strlen(s); + size_t l = strlen(argv[2]); + if (k>l && !strcmp(s+(k-l), argv[2])) s[k-l]=0; + } + if (my_write(1, s, 0)<0 || my_write(1, "\n", 1)<0) + return 1; + return 0; +} diff --git a/src/cat.c b/src/cat.c new file mode 100644 index 0000000..7901a89 --- /dev/null +++ b/src/cat.c @@ -0,0 +1,82 @@ +/* + * cat.c + * Implementation of SUSv3 XCU cat utility + * Copyright © 2007 Rich Felker + * Licensed under the terms of the GNU General Public License, v2 or later + */ + +#include +#include +#include +#include +#include +#include + +static int my_write(int fd, const char *s, size_t l) +{ + while (l) { + ssize_t n = write(fd, s, l); + if (n<0) return -1; + s += n; l -= n; + } + return 0; +} + +static void my_perror(char *prog, char *msg) +{ + char *err = strerror(errno); + write(2, prog, strlen(prog)); + write(2, ": ", 2); + write(2, msg, strlen(msg)); + write(2, ": ", 2); + write(2, err, strlen(err)); + write(2, "\n", 1); +} + +int main(int argc, char *argv[]) +{ + char buf[4096]; + char **v = argv+1; + int n = argc-1; + ssize_t i, k, l; + int err = 0; + int fd; + + signal(SIGPIPE, SIG_IGN); + + for (; n && v[0][0] == '-' && v[0][1]; v++, n--) { + if (v[0][1]=='-' && !v[0][2]) { /* -- */ + v++; n--; + break; + } + if (v[0][1]!='u' || v[0][2]) { /* not -u */ + errno = EINVAL; + my_perror(argv[0], v[0]); + exit(1); + } + } + if (!n) { + n = 1; + v = (char *[]){ "-", NULL }; + } + for (; n; v++, n--) { + if (v[0][0] == '-' && !v[0][1]) fd = 0; + else if ((fd = open(v[0], O_RDONLY)) < 0) { + my_perror(argv[0], v[0]); + err = 1; + continue; + } + while ((l = read(fd, buf, sizeof buf)) > 0) { + if (my_write(1, buf, l) < 0) { + my_perror(argv[0], "write error"); + exit(1); + } + } + if (l) { + my_perror(argv[0], v[0]); + err = 1; + } + if (fd) close(fd); + } + return err; +} diff --git a/src/dirname.c b/src/dirname.c new file mode 100644 index 0000000..982606a --- /dev/null +++ b/src/dirname.c @@ -0,0 +1,28 @@ +#include +#include +#include + +static int my_write(int fd, const char *s, size_t l) +{ + if (!l) l = strlen(s); + while (l) { + ssize_t n = write(fd, s, l); + if (n<0) return -1; + s += n; l -= n; + } + return 0; +} + +int main(int argc, char *argv[]) +{ + char *s; + if (argc != 2) { + my_write(2, argv[0], 0); + my_write(2, ": missing operand\n", 0); + return 1; + } + s = dirname(argv[1]); + if (my_write(1, s, 0)<0 || my_write(1, "\n", 1)<0) + return 1; + return 0; +} diff --git a/src/false.c b/src/false.c new file mode 100644 index 0000000..f37cfc4 --- /dev/null +++ b/src/false.c @@ -0,0 +1,4 @@ +int main() +{ + return 1; +} diff --git a/src/fold.c b/src/fold.c new file mode 100644 index 0000000..64e4534 --- /dev/null +++ b/src/fold.c @@ -0,0 +1,123 @@ +/* + * fold.c + * Implementation of SUSv3 XCU fold utility + * Copyright © 2007 Rich Felker + * Licensed under the terms of the GNU General Public License, v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void my_perror(char *prog, char *msg) +{ + char *err = strerror(errno); + write(2, prog, strlen(prog)); + write(2, ": ", 2); + write(2, msg, strlen(msg)); + write(2, ": ", 2); + write(2, err, strlen(err)); + write(2, "\n", 1); +} + +int main(int argc, char *argv[]) +{ + int b; + char *name; + char dummy[MB_LEN_MAX]; + size_t i, j, len=127; + wchar_t wc, *buf = malloc(sizeof wc * len); + long col, out_col, width=80; + int w; + int splitable; + int byte=0, space=0; + FILE *f; + + if (!setlocale(LC_CTYPE, "")) + my_perror(argv[0], "setlocale"); + + while ((b = getopt(argc, argv, "bsw:")) != EOF) switch(b) { + case 'b': byte=1; break; + case 's': space=1; break; + case 'w': + width=strtoul(optarg, NULL, 10); + break; + default: + return 1; + } + + if (optind == argc) { + f = stdin; + name = "-"; + goto nofiles; + } + + while (optind < argc) { + f = fopen(name=argv[optind++], "rb"); + if (!f) { + my_perror(argv[0], name); + continue; + } +nofiles: + i = col = out_col = 0; + splitable = -1; + while ((wc = getwc(f))>=0) { + if (i == len) { + buf = realloc(buf, sizeof wc * (len=len<<1|1)); + if (!buf) { + my_perror(argv[0], "realloc"); + return 1; + } + } + buf[i++] = wc; + + if (wc == '\n') { + col = 0; + splitable = -1; + goto output; + } + else if (byte) w = wctomb(dummy, wc); + else if (wc == '\t') { + w = 8-(col&7); + if (w > width - col) w = 8; + } + else if (wc == '\r') col = w = 0; + else if (wc == '\b') { + if (col) col--; + w = 0; + } + else w = wcwidth(wc); + + if (col && w > width - col) { + if (putwchar('\n')==WEOF) goto werr; + col -= out_col; + splitable = -1; + } + col += w; + + if (space && iswblank(wc)) + splitable = 1; + if (splitable) { +output: + for (j=0; j>= 1; + } + } + if (ferror(f)) my_perror(argv[0], name); + if (f != stdin) fclose(f); + } + return 0; +werr: + my_perror(argv[0], "write error"); + return 1; +} diff --git a/src/iconv.c b/src/iconv.c new file mode 100644 index 0000000..a0938d6 --- /dev/null +++ b/src/iconv.c @@ -0,0 +1,110 @@ +/* + * iconv.c + * Implementation of SUSv4 XCU iconv utility + * Copyright © 2011 Rich Felker + * Licensed under the terms of the GNU General Public License, v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char **argv) +{ + const char *from=0, *to=0; + int b; + iconv_t cd; + char buf[BUFSIZ]; + char outbuf[BUFSIZ*4]; + char *in, *out; + size_t inb; + size_t l; + size_t unitsize=0; + int err=0; + FILE *f; + + while ((b = getopt(argc, argv, "f:t:csl")) != EOF) switch(b) { + case 'l': + puts("UTF-8, UTF-16BE, UTF-16LE, UTF-32BE, UTF32-LE, UCS-2BE, UCS-2LE, WCHAR_T,\n" + "US_ASCII, ISO8859-1, ISO8859-2, ISO8859-3, ISO8859-4, ISO8859-5,\n" + "ISO8859-6, ISO8859-7, ..."); + exit(0); + case 'c': case 's': break; + case 'f': from=optarg; break; + case 't': to=optarg; break; + default: exit(1); + } + + if (!from || !to) { + setlocale(LC_CTYPE, ""); + if (!to) to = nl_langinfo(CODESET); + if (!from) from = nl_langinfo(CODESET); + } + cd = iconv_open(to, from); + if (cd == (iconv_t)-1) { + if (iconv_open(to, "WCHAR_T") == (iconv_t)-1) + fprintf(stderr, "iconv: destination charset %s", to); + else + fprintf(stderr, "iconv: source charset %s", from); + perror(""); + exit(1); + } + if (optind == argc) argv[argc++] = "-"; + + for (; optind < argc; optind++) { + if (argv[optind][0]=='-' && !argv[optind][1]) { + f = stdin; + argv[optind] = "(stdin)"; + } else if (!(f = fopen(argv[optind], "rb"))) { + fprintf(stderr, "iconv: %s", argv[optind]); + perror(""); + err = 1; + continue; + } + inb = 0; + for (;;) { + in = buf; + out = outbuf; + l = fread(buf+inb, 1, sizeof(buf)-inb, f); + inb += l; + if (!inb) break; + if (iconv(cd, &in, &inb, &out, (size_t [1]){sizeof outbuf})==-1 + && errno == EILSEQ) { + if (!unitsize) { + wchar_t wc='0'; + char dummy[4], *dummyp=dummy; + iconv_t cd2 = iconv_open(from, "WCHAR_T"); + if (cd == (iconv_t)-1) { + unitsize = 1; + } else { + iconv(cd2, + (char *[1]){(char *)&wc}, + (size_t[1]){1}, + &dummyp, (size_t[1]){4}); + unitsize = dummyp-dummy; + if (!unitsize) unitsize=1; + } + } + inb-=unitsize; + in+=unitsize; + } + if (inb && !l && errno==EINVAL) break; + if (out>outbuf && !fwrite(outbuf, out-outbuf, 1, stdout)) { + perror("iconv: write error"); + exit(1); + } + if (inb) memmove(buf, in, inb); + } + if (ferror(f)) { + fprintf(stderr, "iconv: %s", argv[optind]); + perror(""); + err = 1; + } + } + return err; +} diff --git a/src/link.c b/src/link.c new file mode 100644 index 0000000..fd00ae0 --- /dev/null +++ b/src/link.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include + +#define CSTR(s) (s), sizeof(s)-1 + +int main(int argc, char *argv[]) +{ + if (argc != 3) { + write(2, argv[0], strlen(argv[0])); + write(2, CSTR(": incorrect usage\n")); + exit(1); + } + if (link(argv[1], argv[2])) { + write(2, argv[0], strlen(argv[0])); + write(2, CSTR(": ")); + write(2, strerror(errno), strlen(strerror(errno))); + write(2, CSTR("\n")); + exit(1); + } + return 0; +} diff --git a/src/ls.c b/src/ls.c new file mode 100644 index 0000000..defee1e --- /dev/null +++ b/src/ls.c @@ -0,0 +1,80 @@ +/* + * ls.c + * Implementation of SUSv3 XCU ls utility + * Copyright © 2007 Rich Felker + * Licensed under the terms of the GNU General Public License, v2 or later + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static size_t mbswidth(const char *s) +{ + size_t l, w=0; + int v; + wchar_t wc; + mbstate_t mbs = { 0 }; + for (w=0; *s; s+=l, w+=v) + if ((l=mbrtowc(&wc, s, MB_LEN_MAX, &mbs))+2<2 + || (v=wcwidth(wc)) < 0) + return -1; + return w; +} + +static void my_perror(char *prog, char *msg) +{ + char *err = strerror(errno); + write(2, prog, strlen(prog)); + write(2, ": ", 2); + write(2, msg, strlen(msg)); + write(2, ": ", 2); + write(2, err, strlen(err)); + write(2, "\n", 1); +} + +static int cmp(const void *a, const void *b) +{ + return strcoll(*(const char **)a, *(const char **)b); +} + +int main(int argc, char *argv[]) +{ + struct stat st; + int (*xstat)(const char *, struct stat *) = stat; + + if (!setlocale(LC_ALL, "")) + my_perror(argv[0], "setlocale"); + + while ((b=getopt(argc,argv,"CFHLRacdfgilmnoprstux1"))!=EOF) switch(b) { + default: + return 1; + } + + if (optind == argc) { + } + + for (i=optind; i +#include +#include +#include +#include +#include + +static int my_write(int fd, const char *s, size_t l) +{ + if (!l) l = strlen(s); + while (l) { + ssize_t n = write(fd, s, l); + if (n<0) return -1; + s += n; l -= n; + } + return 0; +} + +static void my_perror(char *prog, char *msg) +{ + char *err = strerror(errno); + write(2, prog, strlen(prog)); + write(2, ": ", 2); + write(2, msg, strlen(msg)); + write(2, ": ", 2); + write(2, err, strlen(err)); + write(2, "\n", 1); +} + +static int is_rel(const char *s) +{ + unsigned dots=0, slash=1; + if (*s++ != '/') return 1; + for (; *s; s++) { + if (*s == '/') { + if (dots-1<2) return 1; + dots=0; + } + else slash=1; + if (slash && *s == '.') dots++; + else dots=slash=0; + } + return dots-1<2; +} + +int main(int argc, char *argv[]) +{ + int i, j; + int p=0; + char buf[PATH_MAX+2]; + struct stat st1, st2; + char *pwd; + + for (i=1; i +#include +#include +#include +#include +#include +#include +#include +#include + +static int my_mbrtowc(wchar_t *wc, int b, mbstate_t *st) +{ + char c = b; + int retry = 1; +retry: + switch ((int)mbrtowc(wc, &c, 1, st)) { + case -2: + return -2; + case -1: + memset(st, 0, sizeof(mbstate_t)); + if (retry--) goto retry; + return retry; /* yes this is lame */ + } + return 1; +} + +int main(int argc, char *argv[]) +{ + mbstate_t st; + wchar_t *buf; + size_t i, min = 4; + int b; + off_t start, ofs; + int l; + char fmtbuf[] = "%ll? ", *fmt=fmtbuf+5; + int ret = 0; + int in_str; + FILE *f = stdin; + char *name = "(stdin)"; + + if (!setlocale(LC_CTYPE, "")) { + fprintf(stderr, "%s: warning: cannot set LC_CTYPE", argv[0]); + perror(""); + } + + while ((b = getopt(argc, argv, "an:t:")) != EOF) switch(b) { + case 'a': + /* no-op: we always search entire file */ + break; + case 'n': + min = strtoul(optarg, NULL, 10); + if (min < 1 || min >= SIZE_MAX) { + fprintf(stderr, "%s: invalid argument to -%c: %s\n", + argv[0], b, optarg); + exit(1); + } + break; + case 't': + if (!strchr("dox", optarg[0]) || optarg[1]) { + fprintf(stderr, "%s: invalid argument to -%c: %s\n", + argv[0], b, optarg); + exit(1); + } + fmt = fmtbuf; + fmt[3] = optarg[0]; + break; + default: + exit(1); + } + + /* min+1 does not overflow because of above check */ + if (!(buf = calloc(sizeof(wchar_t), min+1))) { + fprintf(stderr, "%s: ", argv[0]); + perror("calloc failed"); + exit(1); + } + + if (optind < argc) goto nextfile; +begin: + memset(&st, 0, sizeof(mbstate_t)); + start = ofs = i = in_str = 0; + while ((b=getc(f)) >= 0) { + ofs++; + l = my_mbrtowc(buf+i, b, &st); + if (l == -2) continue; + if (l == -1 || !iswprint(buf[i])) { + if (in_str) putchar('\n'); + in_str = 0; + i = 0; + start = ofs; + continue; + } + if (i +#include +#include +#include +#include + + +int index_of(wchar_t c, char *s) +{ + mbstate_t mbst, mbst_init = { }; + int i=0; + char *z; + + while (*s) { + if (s[0] == '[' && s[1] == ':') { + wctype_t type; + char typename[32]; + z = strchr(s, ':'); + if (!z || z[1] != ']' || z-s >= sizeof typename) { + ERROR; + } + memcpy(typename, s, z-s); + typename[z-s] = 0; + type = wctype(typename); + if (!type) + ERROR; + if (iswctype(c, type)) + return i; + } + + if (mbrtowc(&wc, s, MB_LEN_MAX, &mbst) >= (size_t)-2) + return ERROR; + } +} + + +char *parse_repl(char *s1, char *s2) +{ + struct map *head, *tail; + int i; + for (i=j=0; s1[i]; i++) { + tail->next = malloc(sizeof(struct map)); + tail = tail->next; + + if (!strncmp(s1, "[:upper:]", 9) + && !strncmp(s2, "[:lower:]", 9)) { + tail->from = tail->to = 0; + s1 += 9; s2 += 9; + } + if (!strncmp(s1, "[:lower:]", 9) + && !strncmp(s2, "[:upper:]", 9)) { + tail->from = tail->to = 1; + s1 += 9; s2 += 9; + } + } +} + + +int main(int argc, char *argv[]) +{ + int o; + int cmpl = 0, del = 0, sqez = 0, repl = 1; + wchar_t ch, pv = WEOF; + char b[MB_LEN_MAX]; + int i, j; + mbstate_t mbst, mbst_init = { }; + + setlocale(LC_CTYPE, ""); + + while ((o = getopt(argc, argv, "Ccds")) != EOF) + { + switch (o) + { + case 'C': + case 'c': + cmpl = 1; + break; + case 'd': + del = 1; + break; + case 's': + sqez = 1; + break; + default: + return 1; + } + } + string1 = argc-optind >= 1 ? argv[optind] : ""; + string2 = argc-optind >= 2 ? argv[optind+1] : ""; + if (!string2 || del) repl = 0; + + i=0; + while (b[i] = getchar() != EOF) { +retry: + switch (mbrtowc(&wc, b+i, 1, &mbst)) { + case -1: + if (!i) { + putchar(b[0]); + mbst = mbst_init; + continue; + } + for (j=0; j +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int my_mbrtowc(wchar_t *wc, int b, mbstate_t *st) +{ + char c = b; + int retry = 1; +retry: + switch ((int)mbrtowc(wc, &c, 1, st)) { + case -2: + return -2; + case -1: + memset(st, 0, sizeof(mbstate_t)); + if (retry--) goto retry; + return retry; /* yes this is lame */ + } + return 1; +} + +int main(int argc, char *argv[]) +{ + int b; + int pc=0, pm=0, pw=0, pl=0; + unsigned long long c, m, w, l; + unsigned long long tc=0, tm=0, tw=0, tl=0; + int sp; + mbstate_t st; + wchar_t wc; + char *file; + FILE *f; + int err = 0; + int totals = 0, noname = 0; + + setlocale(LC_CTYPE, ""); + + while ((b = getopt(argc, argv, "cmwl")) != EOF) switch(b) { + case 'c': pc=1; break; + case 'm': pm=1; break; + case 'w': pw=1; break; + case 'l': pl=1; break; + default: exit(1); + } + if (!(pc|pm|pw|pl)) pc=pw=pl=1; + if (pc&pm) { + fprintf(stderr, "%s: -c and -m are not valid together\n", + argv[0]); + exit(1); + } + if (optind == argc) { + file = "(stdin)"; + f = stdin; + noname = 1; + goto use_stdin; + } else if (argc-optind > 1) totals=1; + for (; optind < argc; optind++) { + file = argv[optind]; + f = fopen(file, "rb"); + if (!f) { + fprintf(stderr, "%s: %s: ", argv[0], file); + perror(""); + err = 1; + continue; + } +use_stdin: + memset(&st, 0, sizeof st); + for (sp=1, c=m=w=l=0; (b=getc(f)) >= 0; c++) { + if ((pm|pw) && my_mbrtowc(&wc, b, &st) >= 0) { + m++; + if (iswspace(wc)) sp=1; + else if (sp) sp=0, w++; + } + if (b == '\n') l++; + } + if (ferror(f)) { + fprintf(stderr, "%s: %s: ", argv[0], file); + perror(""); + err = 1; + } + tl += l; tw += w; tm += m; tc += c; +totals: + if (pl) printf("%7llu", l); + if (pl&pw) putchar(' '); + if (pw) printf("%7llu", w); + if ((pl|pw)&(pc|pm)) putchar(' '); + if (pc|pm) printf("%7llu", pm?m:c); + if (!noname) printf(" %s", file); + putchar('\n'); + fclose(f); + } + if (totals) { + l = tl; + w = tw; + m = tm; + c = tc; + file = "total"; + f = stdin; + totals = 0; + goto totals; + } + return err; +} -- cgit v1.2.1