diff --git a/src/pr.c b/src/pr.c new file mode 100644 index 0000000..cec3aeb --- /dev/null +++ b/src/pr.c @@ -0,0 +1,136 @@ +/* $Id$ */ +/* Copyright (c) 2007 The DeforaOS Project */ + + + +#include +#include +#include +#include + +#define min(a, b) ((a) < (b)) ? (a) : (b) + + +/* pr */ +/* types */ +typedef struct _Prefs +{ + int flags; + int lines; + int width; +} Prefs; +#define PREFS_t 1 + +/* functions */ +static int _pr_error(char const * message, int ret); +static int _pr_do(Prefs * prefs, FILE * fp, char const * filename); + +static int _pr(Prefs * prefs, int filec, char * filev[]) +{ + int ret = 0; + int i; + FILE * fp; + + if(filec == 0) + return _pr_do(prefs, stdin, "Standard input"); + for(i = 0; i < filec; i++) + { + if(strcmp(filev[i], "-") == 0) + { + ret |= _pr_do(prefs, stdin, "Standard input"); + continue; + } + if((fp = fopen(filev[i], "r")) == NULL) + { + ret |= _pr_error(filev[i], 1); + continue; + } + ret |= _pr_do(prefs, fp, filev[i]); + if(fclose(fp) != 0) + ret |= _pr_error(filev[i], 1); + } + return ret; +} + +static int _pr_error(char const * message, int ret) +{ + fputs("pr: ", stderr); + perror(message); + return ret; +} + +static int _pr_do(Prefs * prefs, FILE * fp, char const * filename) +{ + char buf[513]; + size_t len; + int nb = 0; + + while(fgets(buf, min(prefs->width, sizeof(buf)), fp) != NULL) + { + if(nb == 0 && !(prefs->flags & PREFS_t)) + { + printf("\n\n%s\n\n\n", filename); + nb = 5; + } + if((len = strlen(buf)) > 0 && buf[len - 1] == '\n') + buf[len - 1] = '\0'; + fputs(buf, stdout); + fputc('\n', stdout); + if(nb++ == prefs->lines && !(prefs->flags & PREFS_t)) + { + fputs("\n\n\n\n\n\n", stdout); + nb = 0; + } + } + for(; nb != prefs->lines; nb++) + fputc('\n', stdout); + return 0; +} + + +/* usage */ +static int _usage(void) +{ + fputs("Usage: pr [+page][-column][-adFmrt][-e [char][ gap]]" + "[-h header][-i[char][gap]]\n" + "[-l lines][-n [char][width]][-o offset][-s[char]]" + "[-w width] file...\n", + stderr); + return 1; +} + + +/* main */ +int main(int argc, char * argv[]) +{ + Prefs prefs; + int o; + char * p; + + memset(&prefs, 0, sizeof(prefs)); + prefs.lines = 66; + prefs.width = 72; + while((o = getopt(argc, argv, "l:tw:")) != -1) + switch(o) + { + case 'l': + prefs.lines = strtol(optarg, &p, 10); + if(optarg[0] == '\0' || *p != '\0' + || prefs.lines <= 0) + return _usage(); + break; + case 't': + prefs.flags |= PREFS_t; + break; + case 'w': + prefs.width = strtol(optarg, &p, 10); + if(optarg[0] == '\0' || *p != '\0' + || prefs.width <= 0 + || prefs.width > 512) + return _usage(); + break; + default: + return _usage(); + } + return _pr(&prefs, argc - optind, &argv[optind]) == 0 ? 0 : 2; +} diff --git a/src/printf.c b/src/printf.c new file mode 100644 index 0000000..8b9298c --- /dev/null +++ b/src/printf.c @@ -0,0 +1,202 @@ +/* $Id$ */ +/* Copyright (c) 2007 The DeforaOS Project */ + + + +#include +#include +#include +#include + + +/* printf */ +static int _printf_error(char const * message, int ret); +static int _printf_unescape(char const ** p); +static int _printf_format(char const ** p, char const * arg); + +static int _printf(char const * format, int argc, char * argv[]) +{ + char const * p; + + if(argc < 0) + { + errno = EINVAL; + return _printf_error(format, 1); + } + for(p = format; *p != '\0'; p++) + { + if(*p == '\\') + { + p++; + if(_printf_unescape(&p) != 0) + break; + if(*p == '\0') + break; + } + else if(*p != '%') + putc(*p, stdout); + else if(*(p + 1) == '%') + putc(*++p, stdout); + else if(argc == 0) + { + errno = EINVAL; /* XXX find a better error message */ + return _printf_error(p, 1); + } + else + { + p++; + argc--; + if(_printf_format(&p, *(argv++)) != 0) + break; + if(*p == '\0') + break; + } + } + if(*p != '\0') + return 1; + if(argc != 0) + { + errno = E2BIG; + return _printf_error(format, 1); + } + return 0; +} + +static int _printf_error(char const * message, int ret) +{ + fputs("printf: ", stderr); + perror(message); + return ret; +} + +static int _printf_unescape(char const ** p) +{ + switch(**p) + { + case '\0': + break; + case 'a': + putc('\a', stdout); + break; + case 'b': + putc('\b', stdout); + break; + case 'e': + putc('\e', stdout); + break; + case 'f': + putc('\f', stdout); + break; + case 'n': + putc('\n', stdout); + break; + case 'r': + putc('\r', stdout); + break; + case 't': + putc('\t', stdout); + break; + case 'v': + putc('\v', stdout); + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'x': /* FIXME implement */ + errno = ENOSYS; + return _printf_error(*p, 1); + default: + putc(**p, stdout); + break; + } + return 0; +} + +static int _printf_format(char const ** p, char const * arg) +{ + long i; + unsigned long u; + + switch(**p) + { + case 'c': + if(fputc(arg[0], stdout) != arg[0]) + return _printf_error("stdout", 1); + break; + case 's': + if(fputs(arg, stdout) != 0) + return _printf_error("stdout", 1); + break; + case 'd': + case 'i': + i = atoi(arg); + printf("%ld", i); + break; + case 'u': + u = strtoul(arg, NULL, 10); + printf("%lu", u); + break; + case 'x': + u = strtoul(arg, NULL, 10); + printf("%lx", u); + break; + case 'X': + u = strtoul(arg, NULL, 10); + printf("%lX", u); + break; + case '-': + case '+': + case '#': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case 'e': + case 'E': + case 'f': + case 'g': + case 'G': + case 'o': + errno = ENOSYS; + return _printf_error(*p, 1); + default: + errno = EINVAL; + return _printf_error(*p, 1); + } + return 0; +} + + +/* usage */ +static int _usage(void) +{ + fputs("Usage: printf format [argument...]\n", stderr); + return 1; +} + + +/* main */ +int main(int argc, char * argv[]) +{ + int o; + + if((o = getopt(argc, argv, "")) != -1) + return _usage(); + if(optind == argc) + return _usage(); + return _printf(argv[optind], argc - optind - 1, &argv[optind + 1]) == 0 + ? 0 : 2; +}