From a164619397cf7149b0c5a1ad9d0700479ec435b0 Mon Sep 17 00:00:00 2001 From: DTB Date: Mon, 15 Jan 2024 13:24:52 -0700 Subject: [PATCH] mm(1) --- Wip/mm/Makefile | 1 + Wip/mm/mm.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 327 insertions(+) create mode 100644 Wip/mm/Makefile create mode 100644 Wip/mm/mm.c diff --git a/Wip/mm/Makefile b/Wip/mm/Makefile new file mode 100644 index 0000000..b63ca83 --- /dev/null +++ b/Wip/mm/Makefile @@ -0,0 +1 @@ +mm: mm.c diff --git a/Wip/mm/mm.c b/Wip/mm/mm.c new file mode 100644 index 0000000..64276cb --- /dev/null +++ b/Wip/mm/mm.c @@ -0,0 +1,326 @@ +#include /* errno */ +#include /* fclose(3), fopen(3), fprintf(3), getc(3), putc(3), + * setvbuf(3), size_t, _IONBF, NULL */ +#include /* free(3), realloc(3) */ +#include /* strerror(3) */ +#include /* getopt(3) */ +#if !defined EX_OK || !defined EX_USAGE +# include +#endif + +struct Io_ex{ + size_t s; + FILE **files; + char **names; +}; + +struct Io{ + size_t s; + FILE *files[10]; + char *names[10]; + char *fmode; + struct Io_ex *ex; +}; + +static char *program_name = ""; +static char *stdin_name = ""; +static char *stdout_name = ""; +static char *stderr_name = ""; +static char *rmode = "rb"; +static char *wmode = "rb+"; +static char *wharsh = "wb"; + +#define terminate(io) do{ \ + Io_destruct(&(io)[0]); \ + Io_destruct(&(io)[1]); }while(0) + +static struct Io * +Io_construct(struct Io *io){ + + io->s = 0; + io->ex->s = 0; + io->ex->files = NULL; + io->ex->names = NULL; + + return io; +} + +static struct Io * +Io_destruct(struct Io *io){ + size_t i; + + for(i = 0; i < io->s; ++i) + fclose(io->files[i]); + + for(i = 0; i < io->ex->s; ++i) + fclose(io->ex->files[i]); + free(io->ex->files); + free(io->ex->names); + + return Io_construct(io); /* counter-intuitive but NULLs and 0s */ +} + +static FILE * +Io_fappend(struct Io *io, FILE *f, char *s){ + + if(io->s == -1) + io->s = 0; + + if(io->s < (sizeof (io->files)) / (sizeof *(io->files))){ + io->names[io->s] = s; + return io->files[io->s++] = f; + }else{ + io->ex->files = realloc(io->ex->files, + (sizeof *(io->ex->files)) * ++io->ex->s); + io->ex->names = realloc(io->ex->names, + (sizeof *(io->ex->names)) * io->ex->s); + io->ex->names[io->ex->s] = s; + return io->ex->files[io->ex->s++] = f; + } +} + +static int +Io_fileindex(struct Io *io, FILE *f){ + size_t i; + + for(i = 0; i < io->s; ++i) + if(io->files[i] == f) + return i; + + for(i = 0; i < io->ex->s; ++i) + if(io->ex->files[i] == f) + return i + io->s; + + return -1; +} + +static char * +Io_filename(struct Io *io, FILE *f){ + int i; + + if((i = Io_fileindex(io, f)) == -1) + return NULL; + else if(i < io->s - 1) + return io->names[i]; + else + return io->ex->names[i - io->s]; +} + +static FILE * +Io_fopen(struct Io *io, char *s){ + FILE *f; + + if((f = fopen(s, io->fmode)) == NULL) + return NULL; + else + return Io_fappend(io, f, s); +} + +static struct Io *Io_fremove(struct Io *io, FILE *f); +static FILE *Io_nextfile(struct Io *io, FILE *f); + +static int +Io_fputc(struct Io *io, int c){ + FILE *f; + FILE *lf; + char *ln; + + f = NULL; + lf = NULL; + while((f = Io_nextfile(io, f)) != NULL){ + if(lf != NULL){ + if(fclose(lf) == EOF) + fprintf(stderr, "%s: %s: %s\n", + program_name, ln, strerror(errno)); + Io_fremove(io, lf); + if(io->s == 0) + return EOF; + lf = NULL; + } + if(putc(c, f) == EOF){ + lf = f; + ln = Io_filename(io, lf); + } + } + + return c; +} + +static struct Io * +Io_fremove(struct Io *io, FILE *f){ + size_t i; + + for(i = 0; i < io->s && io->files[i] != f; ++i); + if(io->files[i] == f){ + for( ; i < io->s - 1; ++i){ + io->files[i] = io->files[i + 1]; + io->names[i] = io->names[i + 1]; + } + if(io->ex->s > 0){ + io->files[io->s] = io->ex->files[0]; + io->names[io->s] = io->ex->names[0]; + }else{ + --io->s; + return io; + } + i = 0; + }else{ + for(i = 0; i < io->ex->s && io->ex->files[i] != f; ++i); + if(io->ex->files[i] != f) + return NULL; + } + + for( ; i < io->ex->s - 1; ++i){ + io->ex->files[i] = io->ex->files[i + 1]; + io->ex->names[i] = io->ex->names[i + 1]; + } + --io->ex->s; + + return io; +} + +static FILE * +Io_nextfile(struct Io *io, FILE *f){ + size_t i; + + if(f == NULL) + return io->files[0]; + + for(i = 0; i < io->s; ++i) + if(io->files[i] == f){ + if(i == io->s - 1 && io->ex->s == 0) + return NULL; + else if(i == io->s - 1) + return io->ex->files[0]; + else + return io->files[i + 1]; + } + for(i = 0; i < io->ex->s; ++i) + if(io->ex->files[i] == f){ + if(i == io->ex->s - 1) + break; + else + return io->ex->files[i + 1]; + } + + return NULL; +} + +static struct Io * +Io_unbuffer(struct Io *io){ + size_t i; + + for(i = 0; i < io->s; ++i) + setvbuf(io->files[i], NULL, _IONBF, 0); + + for(i = 0; i < io->ex->s; ++i) + setvbuf(io->ex->files[i], NULL, _IONBF, 0); + + return io; +} + +static int +oserr(char *s, char *r){ + + fprintf(stderr, "%s: %s: %s\n", s, r, strerror(errno)); + + return EX_OSERR; +} + +static int +usage(char *s){ + + fprintf(stderr, "Usage: %s (-ehu) (-i [input])... (-o [output])...\n", + s); + + return EX_USAGE; +} + +int main(int argc, char *argv[]){ + int c; + FILE *f; + size_t i; + struct Io io[2]; /* {read, write, error} */ + struct Io_ex io_ex[2]; + FILE *lf; + char *ln; + char unbuffered; + + if(argc < 2){ /* simple invocation */ + while((c = getc(stdin)) != EOF) + if(putc(c, stdout) == EOF) + break; + return EX_OK; + } + + io[0].ex = &io_ex[0]; + io[1].ex = &io_ex[1]; + Io_construct(&io[0]); + Io_construct(&io[1]); + io[0].fmode = rmode; + io[1].fmode = wmode; + + Io_fappend(&io[0], stdin, stdin_name); + Io_fappend(&io[1], stdout, stdout_name); + io[0].s = -1; + io[1].s = -1; + + unbuffered = 0; + + while((c = getopt(argc, argv, "ehi:o:u")) != -1) + switch(c){ + case 'e': + Io_fappend(&io[1], stderr, stderr_name); + break; + case 'i': case 'o': + if(optarg[0] == '-' && optarg[1] == '\0'){ + /* "-" */ + Io_fappend(&io[c == 'o'], + c == 'i' ? stdin : stdout, + c == 'i' ? stdin_name : stdout_name); + break; + }else if(Io_fopen(&io[c == 'o'], optarg) + != NULL) + break; + /* does not exist, so try to create it */ + if(c == 'o' && errno == ENOENT){ + io[1].fmode = wharsh; + if(Io_fopen(&io[1], optarg) != NULL){ + io[1].fmode = wmode; + break; + } + } + terminate(io); + return oserr(argv[0], optarg);; + case 'u': + unbuffered = 1; + break; + default: + terminate(io); + return usage(argv[0]); + } + + if(unbuffered){ + Io_unbuffer(&io[0]); + Io_unbuffer(&io[1]); + } + + if(io[0].s == -1) + io[0].s = 1; + if(io[1].s == -1) + io[1].s = 1; + + lf = NULL; + + for(i = 0; i < io[0].s; ++i){ + while((c = getc(io[0].files[i])) != EOF) + if(Io_fputc(&io[1], c) == EOF){ /* notebook's full */ + terminate(io); + return EX_OK; + } + } + + terminate(io); + + return EX_OK; +}