Compare commits
5 commits
0fa85040b3
...
d91b47b1e2
Author | SHA1 | Date | |
---|---|---|---|
d91b47b1e2 | |||
a9e7490a87 | |||
4025416fd1 | |||
4bee47593e | |||
354a52e1fd |
12 changed files with 243 additions and 97 deletions
34
asa.c
34
asa.c
|
@ -9,25 +9,42 @@ int main(int argc, char ** argv) {
|
|||
char c, c_temp;
|
||||
|
||||
for(i = 1; i < argc; i++) {
|
||||
if(argv[i][0] == '-' && argv[i][1] == '\0')
|
||||
/* If - is passed as an argument, set the input file to stdin */
|
||||
if(argv[i][0] == '-' && argv[i][1] == '\0') {
|
||||
in_file = stdin;
|
||||
}
|
||||
else {
|
||||
/* Open the file given */
|
||||
in_file = fopen(argv[i], "r");
|
||||
if(in_file == NULL) {
|
||||
/* If it can't open, set that we encountered an error */
|
||||
/*
|
||||
TODO: this should probably check errno instead of
|
||||
assuming that we can't find the file
|
||||
*/
|
||||
fprintf(stderr, "Cannot find file %s\n", argv[i]);
|
||||
error = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Loop through the file line by line, applying transformations based on
|
||||
the first character of the line, as given by the POSIX spec.
|
||||
*/
|
||||
eof_reached = 0;
|
||||
while(!eof_reached) {
|
||||
c = fgetc(in_file);
|
||||
/*
|
||||
Get the first character of the line and print the right thing
|
||||
*/
|
||||
switch(c) {
|
||||
case '1': printf("\f"); break;
|
||||
case '0': printf("\n"); break;
|
||||
case '+': printf("\r"); break;
|
||||
case EOF: eof_reached = 1; continue;
|
||||
case '1': printf("\f"); break; /* Form feed on 1 */
|
||||
case '0': printf("\n"); break; /* New line on 0 */
|
||||
case '+': printf("\r"); break; /* Carriage return on + */
|
||||
case EOF: eof_reached = 1; continue; /* Leave on EOF */
|
||||
/* Anything else, don't do anything */
|
||||
}
|
||||
/* Print out the rest of the line unless we hit an EOF, where we quit. */
|
||||
for(c_temp = fgetc(in_file); c_temp != '\n'; c_temp = fgetc(in_file)) {
|
||||
if(c_temp == EOF) {
|
||||
eof_reached = 1;
|
||||
|
@ -40,8 +57,11 @@ int main(int argc, char ** argv) {
|
|||
printf("\n");
|
||||
}
|
||||
|
||||
if(error)
|
||||
/* If we ever hit an error, return 1. */
|
||||
if(error) {
|
||||
return 1;
|
||||
else
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
|
40
basename.c
40
basename.c
|
@ -10,6 +10,15 @@ int main(int argc, char ** argv) {
|
|||
int basename_length = 0, last_slash = 0;
|
||||
int suffix_length = 0;
|
||||
|
||||
/*
|
||||
Basename takes two arguments, one for the path itself and an optional
|
||||
one for a suffix to remove (e.g. ".c" to remove the C file extension).
|
||||
Here, we check for that second argument to determine if we need to
|
||||
remove an extension.
|
||||
|
||||
If there aren't multiple arguments, check if a path was even given. If
|
||||
not, the POSIX spec says to just return a newline.
|
||||
*/
|
||||
if(argc > 2) {
|
||||
suffix_present = 1;
|
||||
}
|
||||
|
@ -18,6 +27,9 @@ int main(int argc, char ** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
If the path is just //, the POSIX spec also says to return newline
|
||||
*/
|
||||
if(strcmp(argv[1], "//") == 0) {
|
||||
printf("\n");
|
||||
return 0;
|
||||
|
@ -25,16 +37,25 @@ int main(int argc, char ** argv) {
|
|||
|
||||
i = 0;
|
||||
|
||||
/*
|
||||
Find the end of the path (probably could've just used strlen)
|
||||
*/
|
||||
for(c = argv[1][i]; c != '\0'; c = argv[1][i]) {
|
||||
i++;
|
||||
}
|
||||
|
||||
/*
|
||||
If the last character of the path is /, then remove it
|
||||
*/
|
||||
if(argv[1][i-1] == '/') {
|
||||
argv[1][i-1] = '\0';
|
||||
}
|
||||
|
||||
i = 0;
|
||||
|
||||
/*
|
||||
Find the last slash in the path
|
||||
*/
|
||||
for(c = argv[1][i]; c != '\0'; c = argv[1][i]) {
|
||||
if(c == '/') {
|
||||
last_slash = i;
|
||||
|
@ -44,10 +65,16 @@ int main(int argc, char ** argv) {
|
|||
|
||||
i = last_slash + 1;
|
||||
|
||||
/*
|
||||
Figure out how long the basename is
|
||||
*/
|
||||
for(c = argv[1][i]; c != '\0'; c = argv[1][i]) {
|
||||
basename_length++; i++;
|
||||
}
|
||||
|
||||
/*
|
||||
Allocate memory for the basename; fail out if we can't
|
||||
*/
|
||||
basename = calloc(basename_length + 1, sizeof(*basename));
|
||||
if(basename == NULL) {
|
||||
fprintf(stderr, "%s: Could not allocate sufficient memory\n", argv[0]);
|
||||
|
@ -56,13 +83,21 @@ int main(int argc, char ** argv) {
|
|||
|
||||
i = last_slash + 1;
|
||||
|
||||
/*
|
||||
Transfer the basename to the array
|
||||
*/
|
||||
for(c = argv[1][i]; c != '\0'; c = argv[1][i]) {
|
||||
basename[i - (last_slash + 1)] = c;
|
||||
i++;
|
||||
}
|
||||
|
||||
basename[basename_length] = '\0';
|
||||
basename[basename_length] = '\0'; /* don't forget the null! */
|
||||
|
||||
/*
|
||||
If we need to remove a suffix, check if the end of the string is
|
||||
actually equal to the suffix and, if it is, replace the first character
|
||||
of the suffix with a null character.
|
||||
*/
|
||||
if(suffix_present && strcmp(basename, argv[2]) != 0) {
|
||||
i = 0;
|
||||
for(c = argv[2][i]; c != '\0'; c = argv[2][i]) {
|
||||
|
@ -84,6 +119,9 @@ int main(int argc, char ** argv) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Print the basename, free the memory, and quit!
|
||||
*/
|
||||
printf("%s\n", basename);
|
||||
|
||||
free(basename);
|
||||
|
|
15
cat.c
15
cat.c
|
@ -12,17 +12,28 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
int error_occurred;
|
||||
|
||||
/*
|
||||
Check for -u and use unbuffered output if present
|
||||
*/
|
||||
while((c = getopt(argc, argv, "u")) != -1) {
|
||||
if(c == 'u') {
|
||||
using_unbuffered_output = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Set unbuffered output. We do this for both stdin and stdout, let setvbuf
|
||||
allocate the buffer (that we don't need), _IONBF tells it to not buffer,
|
||||
and we just say 15 character buffer because, well, eh, who cares?
|
||||
*/
|
||||
if(using_unbuffered_output) {
|
||||
setvbuf(stdin, NULL, _IONBF, 15);
|
||||
setvbuf(stdout, NULL, _IONBF, 15);
|
||||
}
|
||||
|
||||
/*
|
||||
If no input files were given, just open up stdin
|
||||
*/
|
||||
if(argc == 1 || optind == argc) {
|
||||
cur_in_file = stdin;
|
||||
for(c = fgetc(cur_in_file); c != EOF; c = fgetc(cur_in_file)) {
|
||||
|
@ -31,6 +42,10 @@ int main(int argc, char *argv[]) {
|
|||
fclose(cur_in_file);
|
||||
}
|
||||
|
||||
/*
|
||||
Open up each file given (or stdin if - was given), print it to stdout,
|
||||
then close it and move to the next while there are still files
|
||||
*/
|
||||
for(i = optind; i < argc; i++) {
|
||||
if(argv[i][0] == '-' && argv[i][1] == '\0') {
|
||||
cur_in_file = stdin;
|
||||
|
|
24
cksum.c
24
cksum.c
|
@ -6,6 +6,10 @@
|
|||
unsigned int crc32(FILE * in_file);
|
||||
int count_octets(FILE * in_file);
|
||||
|
||||
/*
|
||||
I think this can technically be computed (don't quote me on that), but it's
|
||||
easier and faster to implement it as a lookup table.
|
||||
*/
|
||||
unsigned int crc32_table[256] = {
|
||||
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
||||
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
||||
|
@ -77,14 +81,20 @@ int main(int argc, char ** argv) {
|
|||
int i, error = 0;
|
||||
FILE *in_file;
|
||||
|
||||
/*
|
||||
Open each file (set that we encountered an error if we couldn't) then
|
||||
print the CRC32 checksum and number of octets in the file.
|
||||
*/
|
||||
for(i = 1; i < argc; i++) {
|
||||
in_file = fopen(argv[i], "r");
|
||||
if(in_file == NULL) {
|
||||
error = 1;
|
||||
fprintf(stderr, "Cannot find file %s\n", argv[i]);
|
||||
}
|
||||
else
|
||||
else {
|
||||
printf("%u %d %s\n", crc32(in_file), count_octets(in_file), argv[i]);
|
||||
fclose(in_file);
|
||||
}
|
||||
}
|
||||
|
||||
if(error)
|
||||
|
@ -95,27 +105,37 @@ int main(int argc, char ** argv) {
|
|||
|
||||
/* Based off the CRC-32 psuedocode implementation on the Wikipedia article for CRC */
|
||||
unsigned int crc32(FILE * in_file) {
|
||||
/* the CRC starts off as 0xFFFFFFFF */
|
||||
unsigned int crc = 0xffffffff;
|
||||
int nLookupIndex;
|
||||
char c;
|
||||
|
||||
/* Make sure we're at the start of the file */
|
||||
fseek(in_file, 0, SEEK_SET);
|
||||
|
||||
/*
|
||||
For each character, set nLookupIndex to CRC XOR that character ANDed with
|
||||
256, then set the CRC to a new value by right-shifting it 8 and XORing with
|
||||
the appropriate value from the lookup table
|
||||
*/
|
||||
for(c = fgetc(in_file); c != EOF; c = fgetc(in_file)) {
|
||||
nLookupIndex = (crc ^ c) & 0xff;
|
||||
crc = (crc >> 8) ^ crc32_table[nLookupIndex];
|
||||
}
|
||||
|
||||
/* When all's said and done, invert all the bits and return. */
|
||||
crc ^= 0xffffffff;
|
||||
return crc;
|
||||
}
|
||||
|
||||
int count_octets(FILE * in_file) {
|
||||
int total_octets = 0;
|
||||
char c;
|
||||
char c; /* I may be assuming 8-bit character...uh... */
|
||||
|
||||
/* Ensure we're at the start */
|
||||
fseek(in_file, 0, SEEK_SET);
|
||||
|
||||
/* Count the octets, one by one. There may be an easier way, but eh. */
|
||||
for(c = fgetc(in_file); c != EOF; c = fgetc(in_file))
|
||||
total_octets++;
|
||||
|
||||
|
|
|
@ -6,41 +6,50 @@
|
|||
int main(int argc, char ** argv) {
|
||||
int i, last_slash = -1, length;
|
||||
|
||||
/* If no path given, print / per the POSIX spec */
|
||||
if(argc == 1) {
|
||||
printf("/\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Same if // is given */
|
||||
if(strcmp(argv[1], "//") == 0) {
|
||||
printf("/\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Oh, look, we use strlen here. */
|
||||
length = strlen(argv[1]);
|
||||
|
||||
/* Replace terminal slash (if present) with null */
|
||||
if(argv[1][length - 1] == '/') {
|
||||
argv[1][length - 1] = '\0';
|
||||
}
|
||||
|
||||
/* Find last slash */
|
||||
for(i = 0; i < length; i++) {
|
||||
if(argv[1][i] == '/') {
|
||||
last_slash = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we didn't find a slash, assume PWD per POSIX spec */
|
||||
if(last_slash == -1) {
|
||||
printf(".\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Replace last slash with null to truncate basename */
|
||||
argv[1][last_slash] = '\0';
|
||||
|
||||
/* If the dirname is //, /, or blank, print a single slash. */
|
||||
if(strcmp(argv[1], "//") == 0 || strcmp(argv[1], "") == 0 ||
|
||||
strcmp(argv[1], "/") == 0) {
|
||||
printf("/\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove any trailing slashes from the dirname */
|
||||
for(i = last_slash - 1; argv[1][i] == '/'; i--) {
|
||||
argv[1][i] = '\0';
|
||||
}
|
||||
|
|
51
echo.c
51
echo.c
|
@ -2,35 +2,51 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
int ctoi(char c);
|
||||
int ctoi(char c); /* A bit of a helper function */
|
||||
|
||||
int main(int argc, char ** argv) {
|
||||
int i, j, oct_temp;
|
||||
char char_temp;
|
||||
int trailing_newline = 1; //1 if true, 0 if \c present
|
||||
/*
|
||||
If /c is present in the text, we're not supposed to print a trailing
|
||||
newline at the end. Otherwise, we do. Hence, we start with 1 (true)
|
||||
for printing this and switch it to 0 if \c shows up
|
||||
*/
|
||||
int trailing_newline = 1;
|
||||
|
||||
/*
|
||||
Outer loop handles each word passed in,
|
||||
inner loop handles characters within each word.
|
||||
*/
|
||||
for(i = 1; i < argc; i++) {
|
||||
for(j = 0; argv[i][j] != '\0'; j++) {
|
||||
/* We need to handle escape sequences ourself. */
|
||||
if(argv[i][j] == '\\') {
|
||||
j++;
|
||||
switch(argv[i][j]) {
|
||||
case 'a': printf("\a"); break;
|
||||
case 'b': printf("\b"); break;
|
||||
case 'c': trailing_newline = 0; break;
|
||||
case 'f': printf("\f"); break;
|
||||
case 'n': printf("\n"); break;
|
||||
case 'r': printf("\r"); break;
|
||||
case 't': printf("\t"); break;
|
||||
case 'v': printf("\v"); break;
|
||||
case '\\': printf("\\"); break;
|
||||
case 'a': printf("\a"); break; /* alert */
|
||||
case 'b': printf("\b"); break; /* backspace */
|
||||
case 'c': trailing_newline = 0; break; /* suppress trailing newline */
|
||||
case 'f': printf("\f"); break; /* form feed */
|
||||
case 'n': printf("\n"); break; /* new line */
|
||||
case 'r': printf("\r"); break; /* carriage return */
|
||||
case 't': printf("\t"); break; /* horizontal tab */
|
||||
case 'v': printf("\v"); break; /* vertical tab */
|
||||
case '\\': printf("\\"); break; /* just print a backslash */
|
||||
/* Octal sequences */
|
||||
case '0': {
|
||||
j++;
|
||||
oct_temp = ctoi(argv[i][j]);
|
||||
oct_temp = ctoi(argv[i][j]); /* 1 digit escape (e.g. 08) */
|
||||
j++;
|
||||
/* 2 digit escape (e.g. 063) */
|
||||
if(ctoi(argv[i][j] != -1)) {
|
||||
oct_temp *= 8;
|
||||
oct_temp += ctoi(argv[i][j]);
|
||||
j++;
|
||||
/*
|
||||
3 digit escape (e.g. 0127)
|
||||
This is all the POSIX spec allows.
|
||||
*/
|
||||
if(ctoi(argv[i][j] != -1)) {
|
||||
oct_temp *= 8;
|
||||
oct_temp += ctoi(argv[i][j]);
|
||||
|
@ -45,16 +61,18 @@ int main(int argc, char ** argv) {
|
|||
printf("%c", (char)oct_temp);
|
||||
}
|
||||
break;
|
||||
/* On unrecognized escape, just print it literal */
|
||||
default: printf("\\%c", argv[i][j]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("%c", argv[i][j]);
|
||||
printf("%c", argv[i][j]); /* Not a backslash? Print the character */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print trailing newline */
|
||||
if(trailing_newline) {
|
||||
printf("\n");
|
||||
}
|
||||
|
@ -62,6 +80,13 @@ int main(int argc, char ** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
I'm really not sure whether writing a ctoi function was ideal here.
|
||||
Maybe I should have just used atoi? I dunno. But, at this point, I'm
|
||||
just gonna leave it as is.
|
||||
|
||||
- Kat
|
||||
*/
|
||||
int ctoi(char c) {
|
||||
switch(c) {
|
||||
case '0': return 0;
|
||||
|
|
4
link.c
4
link.c
|
@ -5,6 +5,9 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
/*
|
||||
link(3) takes 2 arguments, no more, no less.
|
||||
*/
|
||||
if(argc < 3) {
|
||||
fprintf(stderr, "%s: missing file operand\n", argv[0]);
|
||||
exit(1);
|
||||
|
@ -15,5 +18,6 @@ int main(int argc, char * argv[]) {
|
|||
exit(1);
|
||||
}
|
||||
|
||||
/* Yep, this just calls link(3) */
|
||||
return link(argv[1], argv[2]);
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
#include <errno.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
char * logname = getlogin();
|
||||
char * logname = getlogin(); /* get current user's name */
|
||||
|
||||
/* If we didn't get their name, find out why. */
|
||||
if(logname == NULL) {
|
||||
switch(errno) {
|
||||
case EMFILE: fprintf(stderr, "%s: all file descriptors open\n", argv[0]);
|
||||
|
@ -17,7 +18,7 @@ int main(int argc, char * argv[]) {
|
|||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("%s\n", logname);
|
||||
printf("%s\n", logname); /* Print their name */
|
||||
return 0;
|
||||
}
|
||||
}
|
10
pwd.c
10
pwd.c
|
@ -5,7 +5,15 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
int main(int argc, char * argv[]) {
|
||||
int mode = 01; /* 01: print PWD -L, 02: print physical path -P */
|
||||
/*
|
||||
The -L option prints the logical path, corresponding to the PWD envar.
|
||||
-P prints the physical path. The logical path includes any symbolic
|
||||
links followed to get there, where as the physical path doesn't. So,
|
||||
for example, if /lib links to /usr/lib, then if we cd /lib, pwd -L will
|
||||
print /lib, whereas pwd -P will print /usr/lib, even though cd .. will
|
||||
take us back to /
|
||||
*/
|
||||
int mode = 01; /* 01: -L, 02: -P */
|
||||
char c;
|
||||
|
||||
while((c = getopt(argc, argv, "LP")) != -1) {
|
||||
|
|
1
tty.c
1
tty.c
|
@ -5,6 +5,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
/* Check if we're in a tty and, if so, print the devfile for it. */
|
||||
if(isatty(fileno(stdin))) {
|
||||
printf("%s\n", ttyname(0));
|
||||
return 0;
|
||||
|
|
21
uname.c
21
uname.c
|
@ -15,16 +15,18 @@ int main(int argc, char * argv[]) {
|
|||
int stuff_printed = 0;
|
||||
char c;
|
||||
/*
|
||||
For stuff_print:
|
||||
01: -m
|
||||
02: -n
|
||||
04: -r
|
||||
010: -s
|
||||
020: -v
|
||||
037: -a
|
||||
This variable holds what all we need to print, corresponding
|
||||
to the following options:
|
||||
01: -m (Machine type)
|
||||
02: -n (Hostname)
|
||||
04: -r (Release)
|
||||
010: -s (Operating system)
|
||||
020: -v (Version)
|
||||
037: -a (Everything)
|
||||
*/
|
||||
int stuff_print = 0;
|
||||
|
||||
/* Get options */
|
||||
while((c = getopt(argc, argv, "amnrsv")) != -1) {
|
||||
switch(c) {
|
||||
case 'm': stuff_print |= 01; break;
|
||||
|
@ -34,20 +36,23 @@ int main(int argc, char * argv[]) {
|
|||
case 'v': stuff_print |= 020; break;
|
||||
case 'a': stuff_print |= 037; break;
|
||||
}
|
||||
/* If we saw -a, then just leave, we're done here. */
|
||||
if(c == 'a') { break; }
|
||||
}
|
||||
|
||||
/* If no options specified, print OS name */
|
||||
if(stuff_print == 0) {
|
||||
stuff_print = 010;
|
||||
}
|
||||
|
||||
int got_uname = 0;
|
||||
got_uname = uname(sys_name);
|
||||
got_uname = uname(sys_name); /* Try to get the utsname struct */
|
||||
if(got_uname == -1) {
|
||||
fprintf(stderr, "%s: could not get uname\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Print everything and trailing newline */
|
||||
if(stuff_print & 010) {
|
||||
printf("%s ", sys_name->sysname);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue