1
0

i think i fixed it

This commit is contained in:
dtb 2024-01-19 20:55:14 -07:00
parent cc943d045e
commit 0398d9ca94

248
mm/mm.c
View File

@ -20,7 +20,7 @@
#include <signal.h> /* signal(2), SIG_ERR, SIG_IGN, SIGINT */
#include <stdio.h> /* fclose(3), fopen(3), fprintf(3), getc(3), putc(3),
* setvbuf(3), size_t, _IONBF, NULL */
#include <stdlib.h> /* free(3), realloc(3) */
#include <stdlib.h> /* free(3), malloc(3), realloc(3) */
#include <string.h> /* strerror(3) */
#include <unistd.h> /* getopt(3) */
#if !defined EX_OSERR || !defined EX_USAGE
@ -55,152 +55,35 @@ static char *stderr_name = "<stderr>";
static char *(fmode[]) = { (char []){"rb"}, (char []){"rb+"} };
static char *wharsh = "wb";
/* Grows the files allocations by ALLOC_INCREMENT. */
#define Files_grow(files) (\
(files->files = realloc(files->files, \
(files->a += ALLOC_INCREMENT) \
* sizeof *(files->files))) == NULL \
|| (files->names = realloc(files->names, \
files->a * sizeof *(files->names))) == NULL \
? NULL \
: files \
)
/* Opens the file at the path p and puts it in the files struct, returning NULL
* if either the opening or the placement of the open FILE pointer fail. */
#define Files_fopen(files, p) \
Files_fappend((files), fopen((p), (files)->mode), (p))
/* Destructs the files[2] used by main. */
#define terminate(files) do{ \
Files_destruct(&(files)[0]); \
Files_destruct(&(files)[1]); }while(0)
static struct Files *Files_initialize(struct Files *files);
/* Destructs a files struct by closing its files and freeing its files and
* names arrays. Returns the destructed files. */
static struct Files *
Files_destruct(struct Files *files){
int i;
for(i = 0; i < files->s; fclose(files->files[i++]));
free(files->files);
free(files->names);
return Files_initialize(files);
}
#define Files_open(files, p) \
Files_append((files), fopen((p), (files)->mode), (p))
/* Adds the open FILE pointer for the file at the path s to the files struct,
* returning the FILE if successful and NULL if not. */
* returning the FILE if successful and NULL if not, allocating more memory in
* the files buffers as needed. */
static FILE *
Files_fappend(struct Files *files, FILE *file, char *name){
Files_append(struct Files *files, FILE *file, char *name){
if(files->s == -1)
files->s = 0;
if(file == NULL || Files_grow(files) == NULL)
if(file == NULL || (files->s == files->a
&& ((files->files = realloc(files->files,
(files->a += (files->a == 0)
? ALLOC_INITIAL
: ALLOC_INCREMENT)
* sizeof *(files->files))) == NULL
|| (files->names = realloc(files->names,
files->a * sizeof *(files->names)))
== NULL)))
return NULL;
files->names[files->s] = name;
return files->files[files->s++] = file;
}
/* Returns the first index within files->files of the given FILE pointer f. If
* f isn't within files->files, returns -1. */
static int
Files_fileindex(struct Files *files, FILE *f){
size_t i;
for(i = 0; i < files->s; ++i)
if(files->files[i] == f)
return i;
return -1;
}
/* Returns the corresponding file name in the files struct to the FILE pointer
* f, or NULL if f is NULL or isn't in files->files. */
static char *
Files_filename(struct Files *files, FILE *f){
int i;
return (f == NULL || (i = Files_fileindex(files, f)) == -1)
? NULL
: files->names[i];
}
static struct Files *Files_fremove(struct Files *files, FILE *f);
static FILE *Files_nextfile(struct Files *files, FILE *f);
/* Prints c to all files, returning c. If a stream can't be written, a
* message is printed to standard error and the stream is closed and removed
* from files. If no stream can be written, returns EOF. */
static int
Io_fputc(struct Files *files, int c){
FILE *f;
FILE *lf;
char *ln;
f = NULL;
lf = NULL;
for(f = NULL; (f = Files_nextfile(files, f)) != NULL;){
if(lf != NULL){
if(fclose(lf) == EOF)
fprintf(stderr, "%s: %s: %s\n",
program_name, ln, strerror(errno));
if(Files_fremove(files, lf)->s == 0)
return EOF;
lf = NULL;
}
if(putc(c, f) == EOF)
ln = Files_filename(files, lf = f);
}
return c;
}
/* Removes a given file pointer f from the given files struct, returning NULL
* if the file was already absent from files and otherwise files. */
static struct Files *
Files_fremove(struct Files *files, FILE *f){
size_t i;
if((i = Files_fileindex(files, f)) == -1)
return NULL;
for(; i < files->s - 1; ++i){
files->files[i] = files->files[i + 1];
files->names[i] = files->names[i + 1];
}
--files->s;
return files;
}
/* Initializes the members of the given files struct and returns files. */
static struct Files *
Files_initialize(struct Files *files){
files->a = 0;
files->s = 0;
files->files = NULL;
files->names = NULL;
return files;
}
/* Returns the first file in files if f is NULL, NULL if the file is the last
* in or absent from files, or the file after f in files. */
static FILE *
Files_nextfile(struct Files *files, FILE *f){
int i;
return (f == NULL)
? files->files[0]
: ((i = Files_fileindex(files, f)) == -1 || i == files->s - 1)
? NULL
: files->files[i + 1];
}
/* Prints a diagnostic message based on errno and returns an exit status
* appropriate for an OS error. */
static int
@ -211,6 +94,26 @@ oserr(char *s, char *r){
return EX_OSERR;
}
/* Destructs the files[2] struct used by main by closing its files and freeing
* its files and names arrays. Returns the destructed files. */
static struct Files *
terminate(struct Files *files){
size_t i;
size_t j;
for(i = 0; i < 2; ++i){
for(j = 0; j < files[i].s; ++j)
if(files[i].files[j] != stdin
&& files[i].files[j] != stdout
&& files[i].files[j] != stderr)
fclose(files[i].files[j]);
free(files[i].files);
free(files[i].names);
}
return files;
}
/* Prints a diagnostic message synopsizing usage and returns an exit status
* appropriate for a usage error. */
static int
@ -225,6 +128,8 @@ usage(char *s){
int main(int argc, char *argv[]){
int c;
size_t i;
size_t j;
size_t k;
struct Files files[2]; /* {read, write} */
int s; /* scratch variable */
@ -247,8 +152,12 @@ int main(int argc, char *argv[]){
* mm(1) equivalently to tee(1p), -o - will need to be specified before
* additional files to ensure standard output is still written. */
for(i = 0; i < 2; ++i){
Files_initialize(&files[i])->mode = fmode[i];
Files_fappend(&files[i], i == 0 ? stdin : stdout,
files[i].a = 0;
files[i].s = 0;
files[i].mode = fmode[i];
files[i].files = NULL;
files[i].names = NULL;
Files_append(&files[i], i == 0 ? stdin : stdout,
i == 0 ? stdin_name : stdout_name);
files[i].s = -1;
}
@ -262,29 +171,35 @@ int main(int argc, char *argv[]){
files[1].mode[2] = '\0';
break;
case 'e':
if(Files_fappend(&files[1], stderr, stderr_name)
if(Files_append(&files[1], stderr, stderr_name)
!= NULL)
break;
terminate(files);
return oserr(argv[0], "-e");
case 'i': case 'o':
case 'i':
if(optarg[0] == '-' && optarg[1] == '\0'){ /* "-" */
if(Files_append(&files[0], stdin, stdin_name)
!= NULL)
break;
else
optarg = stdin_name;
}else if(Files_open(&files[0], optarg) != NULL)
break;
terminate(files);
return oserr(argv[0], optarg);
case 'o':
if(optarg[0] == '-' && optarg[1] == '\0'){
/* "-" */
if(Files_fappend(&files[c == 'o'],
c == 'i' ? stdin : stdout,
c == 'i'
? stdin_name
: stdout_name) != NULL)
if(Files_append(&files[1], stdout,
stdout_name) != NULL)
break;
terminate(files);
return oserr(argv[0], optarg);
}else if(Files_fopen(&files[c == 'o'], optarg)
!= NULL)
optarg = stdout_name;
}else if(Files_open(&files[1], optarg) != NULL)
break;
/* does not exist, so try to create it */
if(c == 'o' && errno == ENOENT){
if(errno == ENOENT){
files[1].mode = wharsh;
if(Files_fopen(&files[1], optarg) != NULL){
if(Files_open(&files[1], optarg) != NULL){
files[1].mode = fmode[1];
break;
}
@ -318,22 +233,35 @@ int main(int argc, char *argv[]){
if(files[1].s == -1)
files[1].s = 1;
/* Refers to the amount of outputs prior to writing; Io_fputc will
* remove any to which it can't write. */
s = files[1].s;
/* Actual program loop. */
for(i = 0; i < files[0].s; ++i)
while((c = getc(files[0].files[i])) != EOF)
if(Io_fputc(&files[1], c) == EOF){
terminate(files); /* notebook's full */
return 1;
}
/* Reflects whether (s==0) or not (s==1) the full length of the inputs
* could be written to all outputs, which is the return value for main
* to maintain feature parity with tee(1p). */
s = files[1].s != s;
s = 0;
/* Actual program loop. */
for(i = 0; i < files[0].s; ++i) /* iterate ins */
while((c = getc(files[0].files[i])) != EOF) /* iterate chars */
for(j = 0; j < files[1].s; ++j) /* iterate outs */
/* notebook's full */
if(putc(c, files[1].files[j]) == EOF){
s = 1;
if(fclose(files[1].files[j]) == EOF)
fprintf(stderr, "%s: %s: %s\n",
program_name,
files[1].names[j],
strerror(errno));
/* massage out the tense muscle */
for(k = j; k < files[1].s - 1; ++k){
files[1].files[k]
= files[1].files[k+1];
files[1].names[k]
= files[1].names[k+1];
}
if(--files[i].s == 0){
terminate(files);
return 1;
}
}
terminate(files);