Makefile didn't work. Nice.
This commit is contained in:
parent
facda46907
commit
5c5bb242dc
2
TODO
2
TODO
@ -1,3 +1,5 @@
|
||||
Write a function to return a dictionary containing key-value pairs
|
||||
describing command line parameters
|
||||
Write a Makefile. [done]
|
||||
Add octal escape support to echo.
|
||||
Rework yes(1) to buffer output. This achieves greater throughput per system call.
|
||||
|
38
doc/cat.1
Normal file
38
doc/cat.1
Normal file
@ -0,0 +1,38 @@
|
||||
.TH cat 1 2021-11-21 mp-utils Userland
|
||||
.SH NAME
|
||||
cat \- concatenate input
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
Concatenate input onto stdout.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
cat is a standard Unix utility that accepts an arbitrary number of input files,
|
||||
including stdin. It then concatenates (attached end to end) each bit of input,
|
||||
before printing it to stdout.
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
This implementation of cat accepts the following arguments:
|
||||
|
||||
-u: Unbuffered output. Print input as soon as possible.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
This implementation of cat requires a C89 compiler.
|
||||
.SH FILES
|
||||
/usr/src/mp-utils/src/cat.c
|
||||
.SH CONFORMING TO
|
||||
.PP
|
||||
.SM
|
||||
POSIX
|
||||
2017,
|
||||
.SM
|
||||
SUS
|
||||
3
|
||||
.SH NOTES
|
||||
.PP
|
||||
None.
|
||||
.SH BUGS
|
||||
.PP
|
||||
None known.
|
||||
.SH SEE ALSO
|
||||
cat(1p)
|
@ -1,5 +1,4 @@
|
||||
.TH echo 1 2021-11-21 mp-utils Userland
|
||||
|
||||
.SH NAME
|
||||
echo \- Print argv to stdout.
|
||||
.PP
|
||||
@ -49,6 +48,6 @@ Including the following backslash-escapes modifies echo's behavior.
|
||||
|
||||
.SH BUGS
|
||||
.PP
|
||||
Currently, \\0 (octal) escapes have not been implemented.
|
||||
Currently, \\0xxx (octal) escapes have not been implemented.
|
||||
.SH SEE ALSO
|
||||
echo(1p), printf(1)
|
||||
echo(1p), printf(1p), printf(1)
|
||||
|
34
doc/template
Normal file
34
doc/template
Normal file
@ -0,0 +1,34 @@
|
||||
.TH wc 1 2021-11-21 mp-utils Userland
|
||||
|
||||
.SH NAME
|
||||
wc \- print to stdout forever
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
Print the provided string to stdout forever.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Yes is a standard Unix tool that accepts input from the user and prints it to stdout repeatedly, or y when no input is provided.
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
This implementation of wc accepts no arguments.
|
||||
.SH ENVIRONMENT
|
||||
This implementation of wc requires a C89 compiler.
|
||||
.SH FILES
|
||||
/usr/src/mp-utils/src/wc.c
|
||||
.SH CONFORMING TO
|
||||
.PP
|
||||
.SM
|
||||
POSIX
|
||||
2017,
|
||||
.SM
|
||||
SUS
|
||||
3
|
||||
.SH NOTES
|
||||
.PP
|
||||
None.
|
||||
.SH BUGS
|
||||
.PP
|
||||
None known.
|
||||
.SH SEE ALSO
|
||||
wc(1p)
|
28
doc/wc.1
28
doc/wc.1
@ -1,17 +1,30 @@
|
||||
.TH wc 1 2021-11-21 mp-utils Userland
|
||||
|
||||
.SH NAME
|
||||
wc \- print to stdout forever
|
||||
wc \- count words, lines, bytes/characters
|
||||
.PP
|
||||
.SH SYNOPSIS
|
||||
.PP
|
||||
Print the provided string to stdout forever.
|
||||
wc [-c|-m] [-lw] [files...]
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Yes is a standard Unix tool that accepts input from the user and prints it to stdout repeatedly, or y when no input is provided.
|
||||
wc is a standard Unix tool that tallies up the number of words (series of
|
||||
non-blank bytes), lines (newlines), and bytes or characters in input.
|
||||
|
||||
Characters in the context of wc includes multi-byte character support; that
|
||||
bytes are called characters is an unfortunate notational happenstance.
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
This implementation of wc accepts no arguments.
|
||||
This implementation of wc accepts the following arguments:
|
||||
|
||||
.SM
|
||||
-c: Print the number of bytes.
|
||||
|
||||
-m: Print the number of characters.
|
||||
|
||||
-l: Print the number of lines.
|
||||
|
||||
-w: Print the number of words.
|
||||
|
||||
.SH ENVIRONMENT
|
||||
This implementation of wc requires a C89 compiler.
|
||||
.SH FILES
|
||||
@ -29,6 +42,7 @@ SUS
|
||||
None.
|
||||
.SH BUGS
|
||||
.PP
|
||||
None known.
|
||||
This implementation of wc does not currently treat characters any different than
|
||||
bytes.
|
||||
.SH SEE ALSO
|
||||
wc(1p)
|
||||
wc(1p)
|
||||
|
@ -1,5 +1,4 @@
|
||||
.TH yes 1 2021-11-21 mp-utils Userland
|
||||
|
||||
.SH NAME
|
||||
yes \- print to stdout forever
|
||||
.PP
|
||||
@ -8,7 +7,7 @@ yes \- print to stdout forever
|
||||
Print the provided string to stdout forever.
|
||||
.SH DESCRIPTION
|
||||
.PP
|
||||
Yes is a standard Unix tool that accepts input from the user and prints it to stdout repeatedly, or y when no input is provided.
|
||||
yes is a standard Unix tool that accepts input from the user and prints it to stdout repeatedly, or y when no input is provided.
|
||||
.SH OPTIONS
|
||||
.PP
|
||||
This implementation of yes accepts no arguments.
|
||||
@ -31,4 +30,4 @@ None.
|
||||
.PP
|
||||
None known.
|
||||
.SH SEE ALSO
|
||||
yes(1p)
|
||||
yes(1p)
|
||||
|
120
old/cat.c
Normal file
120
old/cat.c
Normal file
@ -0,0 +1,120 @@
|
||||
/* cat.c -- program to concatenate input and stdin onto stdout. */
|
||||
/* first version */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
|
||||
char *cat(FILE *fp, const int mode, long unsigned *bufsize)
|
||||
{
|
||||
char c;
|
||||
static long unsigned int i, finalbuflen, tmpbuflen;
|
||||
char *arr, *tmparr, *finalarr;
|
||||
tmpbuflen = 4096;
|
||||
|
||||
if(!mode)
|
||||
{
|
||||
arr = malloc(tmpbuflen);
|
||||
tmparr = finalarr = 0;
|
||||
|
||||
for(i = 0, finalbuflen = 0; (c = fgetc(fp)) != EOF; i++, finalbuflen++)
|
||||
{
|
||||
if(i >= tmpbuflen)
|
||||
{
|
||||
tmpbuflen *= 2;
|
||||
tmparr = malloc(tmpbuflen);
|
||||
memcpy(tmparr, arr, tmpbuflen/2);
|
||||
free(arr);
|
||||
arr = tmparr;
|
||||
}
|
||||
|
||||
arr[i] = c;
|
||||
}
|
||||
|
||||
finalarr = malloc(finalbuflen);
|
||||
memcpy(finalarr, arr, finalbuflen);
|
||||
free(arr);
|
||||
arr = finalarr;
|
||||
*bufsize = finalbuflen;
|
||||
return arr;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(;(c = fgetc(fp)) != EOF;)
|
||||
{
|
||||
putchar(c);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long unsigned int i, upresence, fppresence, buflen, newbuflen;
|
||||
char *buf, *newbuf, *tmpbuf;
|
||||
FILE *fp;
|
||||
|
||||
i = upresence = fppresence = buflen = newbuflen = 0;
|
||||
buf = newbuf = tmpbuf = 0;
|
||||
fp = 0;
|
||||
|
||||
|
||||
switch( (upresence = getopt(argc, argv, "u")))
|
||||
{
|
||||
case 'u': i++;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for(i++;argv[i] != NULL; i++)
|
||||
{
|
||||
if(!strcmp(argv[i], "-"))
|
||||
{
|
||||
fppresence++;
|
||||
newbuf = cat(fopen("/dev/stdin", "r"), upresence, &newbuflen);
|
||||
}
|
||||
else if((fp = fopen(argv[i], "r")) != NULL)
|
||||
{
|
||||
fppresence++;
|
||||
newbuf = cat(fp, upresence, &newbuflen);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: failed to open %s. Aborting.\n", argv[0], argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* This is where the actual magic happens. */
|
||||
if(!upresence)
|
||||
{
|
||||
/* Here, we copy buf and newbuf end-to-end into a new buffer of size buflen+newbuflen, then store that in buflen and */
|
||||
/* return a pointer to the new buffer. */
|
||||
tmpbuf = arrccat(buf, newbuf, &buflen, newbuflen);
|
||||
free(buf);
|
||||
buf = tmpbuf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!fppresence)
|
||||
{
|
||||
buf = cat(fopen("/dev/stdin", "r"), upresence, &buflen);
|
||||
}
|
||||
|
||||
if(!upresence)
|
||||
{
|
||||
for(i = 0; i < buflen; i++)
|
||||
{
|
||||
putchar(buf[i]);
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
@ -20,7 +20,7 @@ false: true
|
||||
ln -s true false
|
||||
|
||||
install: all
|
||||
mkdir -p ${DESTDIR}/${PREFIX}
|
||||
mkdir -p ${DESTDIR}/${PREFIX}/bin
|
||||
install -Dm0755 ${BIN} ${DESTDIR}/${PREFIX}/bin/
|
||||
|
||||
clean:
|
||||
|
160
src/cat.c
160
src/cat.c
@ -1,112 +1,108 @@
|
||||
/* cat.c -- program to concatenate named files and/or stdin onto stdout */
|
||||
/* version 2 */
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "support.h"
|
||||
|
||||
|
||||
char *cat(FILE *fp, const int mode, long unsigned *bufsize)
|
||||
/* parameters */
|
||||
enum
|
||||
{
|
||||
char c;
|
||||
static long unsigned int i, finalbuflen, tmpbuflen;
|
||||
char *arr, *tmparr, *finalarr;
|
||||
tmpbuflen = 4096;
|
||||
U
|
||||
};
|
||||
|
||||
if(!mode)
|
||||
{
|
||||
arr = malloc(tmpbuflen);
|
||||
tmparr = finalarr = 0;
|
||||
|
||||
for(i = 0, finalbuflen = 0; (c = fgetc(fp)) != EOF; i++, finalbuflen++)
|
||||
{
|
||||
if(i >= tmpbuflen)
|
||||
{
|
||||
tmpbuflen *= 2;
|
||||
tmparr = malloc(tmpbuflen);
|
||||
memcpy(tmparr, arr, tmpbuflen/2);
|
||||
free(arr);
|
||||
arr = tmparr;
|
||||
}
|
||||
|
||||
arr[i] = c;
|
||||
}
|
||||
|
||||
finalarr = malloc(finalbuflen);
|
||||
memcpy(finalarr, arr, finalbuflen);
|
||||
free(arr);
|
||||
arr = finalarr;
|
||||
*bufsize = finalbuflen;
|
||||
return arr;
|
||||
}
|
||||
else
|
||||
/* concat - return a buffer of size new_size containing s1 and s2 concatenated. */
|
||||
char *concat(char *a1, char *a2, int a1_size, int a2_size)
|
||||
{
|
||||
char *newbuf;
|
||||
|
||||
newbuf = 0;
|
||||
|
||||
|
||||
if( !(newbuf = malloc(a1_size+a2_size)))
|
||||
{
|
||||
for(;(c = fgetc(fp)) != EOF;)
|
||||
{
|
||||
putchar(c);
|
||||
}
|
||||
throw(MALLOC_FAIL, "concat: couldn't create buffer");
|
||||
}
|
||||
|
||||
|
||||
return NULL;
|
||||
if(a1_size)
|
||||
{
|
||||
mid_mempcpy(newbuf, a1, a1_size, 0);
|
||||
}
|
||||
|
||||
if(a2_size)
|
||||
{
|
||||
mid_mempcpy(newbuf, a2, a2_size, a1_size);
|
||||
}
|
||||
|
||||
|
||||
return(newbuf);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
long unsigned int i, upresence, fppresence, buflen, newbuflen;
|
||||
char *buf, *newbuf, *tmpbuf;
|
||||
FILE *fp;
|
||||
|
||||
i = upresence = fppresence = buflen = newbuflen = 0;
|
||||
buf = newbuf = tmpbuf = 0;
|
||||
fp = 0;
|
||||
int i, c, bufsize, newbufsize;
|
||||
|
||||
|
||||
if((upresence = (getopt(argc, argv, ":u") == 'u')))
|
||||
char *buf, *newbuf;
|
||||
char pars[1] = {0};
|
||||
|
||||
FILE *fd;
|
||||
|
||||
i = c = bufsize = newbufsize = 0;
|
||||
|
||||
buf = newbuf = 0;
|
||||
|
||||
fd = 0;
|
||||
|
||||
|
||||
/* process our parameters */
|
||||
for(; (c = getopt(argc, argv, "u")) != -1; c = 0)
|
||||
{
|
||||
i++;
|
||||
switch(c)
|
||||
{
|
||||
case 'u': pars[U] = 1;
|
||||
break;
|
||||
case ':':
|
||||
case '?':
|
||||
default: throw(NEEDARG_FAIL, mastrcat(argv[0], " [-u] [file ...]"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for(i++;argv[i] != NULL; i++)
|
||||
{
|
||||
if(!strcmp(argv[i], "-"))
|
||||
{
|
||||
fppresence++;
|
||||
newbuf = cat(fopen("/dev/stdin", "r"), upresence, &newbuflen);
|
||||
}
|
||||
else if((fp = fopen(argv[i], "r")) != NULL)
|
||||
{
|
||||
fppresence++;
|
||||
newbuf = cat(fp, upresence, &newbuflen);
|
||||
fclose(fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "%s: failed to open %s. Aborting.\n", argv[0], argv[i]);
|
||||
exit(1);
|
||||
}
|
||||
i = optind;
|
||||
|
||||
/* This is where the actual magic happens. */
|
||||
if(!upresence)
|
||||
|
||||
/* i < argc is obvious; steps through all provided args. */
|
||||
/* !argc-optind && !newbuf is a little less so - it allows this loop to run once if the user provides no paths */
|
||||
for(i = optind; (i < argc) || (((argc - optind) == 0) && !newbuf); i++, newbufsize = 0)
|
||||
{
|
||||
if( !(fd = file_open(argv[i], "r")))
|
||||
{
|
||||
/* Here, we copy buf and newbuf end-to-end into a new buffer of size buflen+newbuflen, then store that in buflen and */
|
||||
/* return a pointer to the new buffer. */
|
||||
tmpbuf = arrccat(buf, newbuf, &buflen, newbuflen);
|
||||
free(buf);
|
||||
buf = tmpbuf;
|
||||
throw(FOPEN_FAIL, mastrcat(argv[0], mastrcat(": could not open file ", argv[i])));
|
||||
}
|
||||
|
||||
newbuf = file_read(fd, &newbufsize);
|
||||
if(pars[U])
|
||||
{
|
||||
fwrite(newbuf, sizeof(char), newbufsize, stdout);
|
||||
free(newbuf);
|
||||
continue;
|
||||
}
|
||||
buf = concat(buf, newbuf, bufsize, newbufsize);
|
||||
bufsize += newbufsize;
|
||||
free(newbuf);
|
||||
|
||||
}
|
||||
|
||||
if(!fppresence)
|
||||
if(!pars[U])
|
||||
{
|
||||
buf = cat(fopen("/dev/stdin", "r"), upresence, &buflen);
|
||||
}
|
||||
|
||||
if(!upresence)
|
||||
{
|
||||
for(i = 0; i < buflen; i++)
|
||||
{
|
||||
putchar(buf[i]);
|
||||
}
|
||||
fwrite(buf, sizeof(char), bufsize, stdout);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
|
138
src/support.h
138
src/support.h
@ -6,7 +6,9 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
enum {
|
||||
/* Error constants */
|
||||
enum
|
||||
{
|
||||
UNKNOWN_FAIL = 1,
|
||||
MALLOC_FAIL,
|
||||
NEEDARG_FAIL,
|
||||
@ -16,30 +18,33 @@ enum {
|
||||
MISC_FAIL
|
||||
};
|
||||
|
||||
|
||||
/* arrccat -- function to copy arr2len bytes from arr2 to the arr1len'th position of arr1. returns *newarr, and stores the length */
|
||||
/* of newarr[] in arr1len (that's why it needs to be a pointer to arr1len and not just a long unsigned integer). */
|
||||
char *arrccat(char *arr1, char *arr2, size_t *arr1len, size_t arr2len)
|
||||
/* Standard data identifiers for nodes */
|
||||
enum
|
||||
{
|
||||
char *newarr;
|
||||
unsigned int i, i2;
|
||||
newarr = malloc(*arr1len+arr2len);
|
||||
i = i2 = 0;
|
||||
CHAR = 1,
|
||||
INT,
|
||||
LONG,
|
||||
DOUBLE,
|
||||
CHARP,
|
||||
INTP,
|
||||
LONGP,
|
||||
DOUBLEP,
|
||||
NODEP
|
||||
};
|
||||
|
||||
for(i = 0; i < *arr1len; i++)
|
||||
{
|
||||
newarr[i] = arr1[i];
|
||||
}
|
||||
/* node - node type suitable for being a member in a linked list. */
|
||||
/* name - the name of the data in this node */
|
||||
/* data - pointer to arbitrary data */
|
||||
/* type - implementation-defined identifier for what kind of data this node holds */
|
||||
typedef struct LNODE
|
||||
{
|
||||
struct LNODE *previous;
|
||||
char *name;
|
||||
void *data;
|
||||
int type;
|
||||
struct LNODE *next;
|
||||
} node;
|
||||
|
||||
for(i2 = 0; i2 < arr2len; i2++, i++)
|
||||
{
|
||||
newarr[i] = arr2[i2];
|
||||
}
|
||||
|
||||
*arr1len = *arr1len+arr2len;
|
||||
|
||||
return newarr;
|
||||
}
|
||||
|
||||
/* Condition should be one of the above enum'd strings. Info is optional; it can just be NULL when irrelevant. */
|
||||
void throw(long unsigned int condition, void *info)
|
||||
@ -65,6 +70,46 @@ void throw(long unsigned int condition, void *info)
|
||||
}
|
||||
}
|
||||
|
||||
/* mid_mempcpy -- copy n bytes from s2 to s1 starting at position p */
|
||||
int mid_mempcpy(char *s1, char *s2, int n, int p)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
|
||||
for(i = 0; i <= n; i++, p++)
|
||||
{
|
||||
s1[p] = s2[i];
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* arrccat -- function to copy arr2len bytes from arr2 to the arr1len'th position of arr1. returns *newarr, and stores the length */
|
||||
/* of newarr[] in arr1len (that's why it needs to be a pointer to arr1len and not just a long unsigned integer). */
|
||||
char *arrccat(char *arr1, char *arr2, size_t *arr1len, size_t arr2len)
|
||||
{
|
||||
char *newarr;
|
||||
unsigned int i, i2;
|
||||
newarr = malloc(*arr1len+arr2len);
|
||||
i = i2 = 0;
|
||||
|
||||
for(i = 0; i < *arr1len; i++)
|
||||
{
|
||||
newarr[i] = arr1[i];
|
||||
}
|
||||
|
||||
for(i2 = 0; i2 < arr2len; i2++, i++)
|
||||
{
|
||||
newarr[i] = arr2[i2];
|
||||
}
|
||||
|
||||
*arr1len = *arr1len+arr2len;
|
||||
|
||||
return newarr;
|
||||
}
|
||||
|
||||
/* mastrcat -- improved string concat function. returns a pointer to the first element in a buffer containing the strings str1 */
|
||||
/* and str2 joined end-to-end. */
|
||||
char *mastrcat(char *str1, char *str2)
|
||||
@ -86,7 +131,7 @@ char *mastrcat(char *str1, char *str2)
|
||||
}
|
||||
|
||||
return nbuf;
|
||||
}
|
||||
}
|
||||
|
||||
/* open stdin if path is null */
|
||||
FILE *file_open(char *path, char *mode)
|
||||
@ -98,7 +143,7 @@ FILE *file_open(char *path, char *mode)
|
||||
|
||||
if(!mode)
|
||||
{
|
||||
throw(MISC_FAIL, "file_open: mode is null. Terminating.");
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if(path == NULL || !strcmp(path, "-"))
|
||||
@ -112,10 +157,53 @@ FILE *file_open(char *path, char *mode)
|
||||
|
||||
if(!fd)
|
||||
{
|
||||
throw(FOPEN_FAIL, mastrcat("file_open: couldn't open ", mastrcat(path, mastrcat(" using mode ", mode))));
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
||||
return(fd);
|
||||
}
|
||||
|
||||
|
||||
/* return a buffer containing the contents of fd, or NULL if failure. Store the size of the new buffer in newsize; -1 on fail. */
|
||||
char *file_read(FILE *fd, int *newsize)
|
||||
{
|
||||
int bufsize, c, i;
|
||||
|
||||
char *buf, *tmpbuf;
|
||||
|
||||
/* bufsize is arbitrary */
|
||||
bufsize = 4096;
|
||||
c = i = 0;
|
||||
|
||||
buf = tmpbuf = 0;
|
||||
|
||||
|
||||
if( !(buf = malloc(bufsize)))
|
||||
{
|
||||
*newsize = -1;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
for(i = 0; (c = fgetc(fd)) != EOF; i++)
|
||||
{
|
||||
if(i >= bufsize)
|
||||
{
|
||||
if( !(tmpbuf = malloc(bufsize *= 2)))
|
||||
{
|
||||
*newsize = -1;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
memcpy(tmpbuf, buf, i-1);
|
||||
free(buf);
|
||||
buf = tmpbuf;
|
||||
}
|
||||
|
||||
buf[i] = c;
|
||||
}
|
||||
|
||||
|
||||
*newsize = i;
|
||||
return(buf);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user