utilities/src
This commit is contained in:
		
							parent
							
								
									7dcc2ecac8
								
							
						
					
					
						commit
						293436c5ad
					
				
							
								
								
									
										121
									
								
								src/calculate.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/calculate.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
				
			|||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "libstrnum.h"
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef long int pile_t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Stack{
 | 
				
			||||||
 | 
						size_t s;
 | 
				
			||||||
 | 
						size_t dot;
 | 
				
			||||||
 | 
						pile_t *pile;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* probably could be optimized */
 | 
				
			||||||
 | 
					pile_t
 | 
				
			||||||
 | 
					Stack_pop(struct Stack *s){
 | 
				
			||||||
 | 
						pile_t n;
 | 
				
			||||||
 | 
						n = s->pile[(s->dot)-1];
 | 
				
			||||||
 | 
						if(s->dot >= 0)
 | 
				
			||||||
 | 
							--(s->dot);
 | 
				
			||||||
 | 
						return n;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Stack *
 | 
				
			||||||
 | 
					Stack_push(pile_t n, struct Stack *s){
 | 
				
			||||||
 | 
						pile_t *new;
 | 
				
			||||||
 | 
						if(s->s == s->dot && (new = realloc(s->pile, sizeof(*(s->pile)) * ++(s->s))) == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						s->pile[(s->dot)++] = n;
 | 
				
			||||||
 | 
						return s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						char *argv0;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						//int ir, or; /* input radix, output radix */
 | 
				
			||||||
 | 
						int op;
 | 
				
			||||||
 | 
						struct Stack s;
 | 
				
			||||||
 | 
						pile_t x, y;
 | 
				
			||||||
 | 
						unsigned short int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						retval = EX_OK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* stack initialization */
 | 
				
			||||||
 | 
						if((s.pile = malloc(sizeof(pile_t))) == NULL)
 | 
				
			||||||
 | 
							return EX_OSERR;
 | 
				
			||||||
 | 
						*s.pile = 0;
 | 
				
			||||||
 | 
						s.dot = 0;
 | 
				
			||||||
 | 
						s.s = 1;
 | 
				
			||||||
 | 
						Stack_push(0, &s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argv0 = argv[0];
 | 
				
			||||||
 | 
						/* Most operations are 1 char, all are two max, so no sense using
 | 
				
			||||||
 | 
						 * strcmp or a dictionary */
 | 
				
			||||||
 | 
						while(*++argv != NULL){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* parse out operation */
 | 
				
			||||||
 | 
							op = '\0';
 | 
				
			||||||
 | 
							switch(**argv){
 | 
				
			||||||
 | 
							case '+': case '-': case '%': case '^': case '<': case '>':
 | 
				
			||||||
 | 
							case '=': case '!': case '?': case 'q': case 'x':
 | 
				
			||||||
 | 
								if((*argv)[1] == '\0')
 | 
				
			||||||
 | 
									op = **argv;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '*':
 | 
				
			||||||
 | 
								if((*argv)[1] == '\0')
 | 
				
			||||||
 | 
									op = **argv; /* "*" */
 | 
				
			||||||
 | 
								else if((*argv)[1] == **argv && (*argv)[2] == '\0')
 | 
				
			||||||
 | 
									op = '^'; /* "**" */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								op = 'a' + !stris(STRIS_TYPE_UINT, *argv) * ('h' - 'a');
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(op == '\0'){
 | 
				
			||||||
 | 
								retval = EX_SOFTWARE;
 | 
				
			||||||
 | 
								goto quit;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* conduct operation */
 | 
				
			||||||
 | 
							switch(op){
 | 
				
			||||||
 | 
							case 'a':
 | 
				
			||||||
 | 
								if(Stack_push(atoi(*argv), &s) == NULL){
 | 
				
			||||||
 | 
									retval = EX_OSERR;
 | 
				
			||||||
 | 
									goto quit;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'h':
 | 
				
			||||||
 | 
								goto usage;
 | 
				
			||||||
 | 
							case 'q': case 'x':
 | 
				
			||||||
 | 
								goto quit;
 | 
				
			||||||
 | 
							case '+':
 | 
				
			||||||
 | 
								Stack_push(Stack_pop(&s) + Stack_pop(&s), &s);
 | 
				
			||||||
 | 
								write(1,"0",1);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '-':
 | 
				
			||||||
 | 
								y = Stack_pop(&s);
 | 
				
			||||||
 | 
								x = Stack_pop(&s);
 | 
				
			||||||
 | 
								Stack_push(x - y, &s);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						printf("%li\n", s.pile[s.dot - 1]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						goto quit;
 | 
				
			||||||
 | 
					usage:
 | 
				
			||||||
 | 
						write(2, "Usage: ", 7);
 | 
				
			||||||
 | 
						for(i = 0; argv0[i] != '\0'; ++i);
 | 
				
			||||||
 | 
						write(2, argv0, i);
 | 
				
			||||||
 | 
						write(2, "(-C [program])|(program...)\n", 28);
 | 
				
			||||||
 | 
						retval = EX_USAGE;
 | 
				
			||||||
 | 
					quit:
 | 
				
			||||||
 | 
						free(s.pile);
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										67
									
								
								src/cut.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								src/cut.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,67 @@
 | 
				
			|||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern char *optarg; /* getopt(3); unistd.h */
 | 
				
			||||||
 | 
					extern int optind, opterr, optopt; /* getopt(3); unistd.h */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					occurrences(FILE *f, char *s){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stderr,
 | 
				
			||||||
 | 
							"Usage: %s (-b [list] (-n))"
 | 
				
			||||||
 | 
								"\t|(-c [list])"
 | 
				
			||||||
 | 
								"\t|(-f [list] (-d [delim]) (-s))"
 | 
				
			||||||
 | 
								"\t[file...]\n", name);
 | 
				
			||||||
 | 
						exit(EX_USAGE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
						char *delimiter;
 | 
				
			||||||
 | 
						char *list;
 | 
				
			||||||
 | 
						char mode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NOARGVZERO(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* perhaps mode could be specified after submodal stuff. this would
 | 
				
			||||||
 | 
						 * move checks to after argument parsing though which could take more
 | 
				
			||||||
 | 
						 * time. */
 | 
				
			||||||
 | 
						mode = 0;
 | 
				
			||||||
 | 
						submode = 0;
 | 
				
			||||||
 | 
						while((c = getopt(argc, argv, "b:c:d:f:ns")) != -1)
 | 
				
			||||||
 | 
							switch(c){
 | 
				
			||||||
 | 
								case 'b': case 'c': case 'f':
 | 
				
			||||||
 | 
									if(mode != 0)
 | 
				
			||||||
 | 
										usage(argv[0]);
 | 
				
			||||||
 | 
									mode = c;
 | 
				
			||||||
 | 
									list = optarg;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case 'd':
 | 
				
			||||||
 | 
									if(mode != 'f')
 | 
				
			||||||
 | 
										usage(argv[0]);
 | 
				
			||||||
 | 
									delimiter = optarg;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								case 'n': case 's':
 | 
				
			||||||
 | 
									if((c == 's' && mode != 'f')
 | 
				
			||||||
 | 
											|| (c == 'b' && mode != 'b'))
 | 
				
			||||||
 | 
										usage(argv[0]);
 | 
				
			||||||
 | 
									submode = c;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								default:
 | 
				
			||||||
 | 
									usage(argv[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return EX_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										20
									
								
								src/echo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/echo.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <stddef.h> /* NULL */
 | 
				
			||||||
 | 
					#include <unistd.h> /* write(2) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv){
 | 
				
			||||||
 | 
						int s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(*argv == NULL)
 | 
				
			||||||
 | 
							return EX_OSERR;
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						while(*++argv != NULL){
 | 
				
			||||||
 | 
							for(s = 0; *(*argv+s) != '\0'; ++s);
 | 
				
			||||||
 | 
							write(1, *argv, s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if(*(argv+1) != NULL)
 | 
				
			||||||
 | 
								write(1, " ", 1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						write(1, "\n", 1);
 | 
				
			||||||
 | 
						return EX_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										1
									
								
								src/false.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								src/false.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					int main() { return 1; }
 | 
				
			||||||
							
								
								
									
										12
									
								
								src/head.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								src/head.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* The philosophical bits - /should this be a shell script?/ -
 | 
				
			||||||
 | 
					 * are more complicated than the actual program. sed(1) is not currently a part
 | 
				
			||||||
 | 
					 * of this project so there shouldn't be reliance on it. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						char *argv0 = argv[0];
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						
 | 
				
			||||||
							
								
								
									
										66
									
								
								src/id.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/id.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					#include <limits.h> /* LOGIN_NAME_MAX */
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h> /* fprintf(3) */
 | 
				
			||||||
 | 
					#include <stdlib.h> /* stderr, stdout */
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h> /* getuid(2), geteuid(2), getopt(3) */
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
						char mode;
 | 
				
			||||||
 | 
						bool n;
 | 
				
			||||||
 | 
						char name[LOGIN_NAME_MAX];
 | 
				
			||||||
 | 
						bool r;
 | 
				
			||||||
 | 
						uid_t euid;
 | 
				
			||||||
 | 
						uid_t uid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						mode = 0;
 | 
				
			||||||
 | 
						n = false;
 | 
				
			||||||
 | 
						r = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while((c = getopt(argc, argv, "Gghnru")) != -1)
 | 
				
			||||||
 | 
							switch(c){
 | 
				
			||||||
 | 
							case 'G': case 'g': case 'u':
 | 
				
			||||||
 | 
								if(mode == 0){
 | 
				
			||||||
 | 
									mode = c;
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* FALLTHROUGH */
 | 
				
			||||||
 | 
							case 'h': default: usage:
 | 
				
			||||||
 | 
								fprintf(stderr, "Usage: %s [-G]|[-g]|[-u] (-rn) (user)\n", argv[0]);
 | 
				
			||||||
 | 
								return EX_USAGE;
 | 
				
			||||||
 | 
							case 'n':
 | 
				
			||||||
 | 
								n = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case 'r':
 | 
				
			||||||
 | 
								r = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						switch(mode){
 | 
				
			||||||
 | 
							case 0:
 | 
				
			||||||
 | 
								goto usage;
 | 
				
			||||||
 | 
							case 'G':
 | 
				
			||||||
 | 
							case 'g':
 | 
				
			||||||
 | 
								return EX_SOFTWARE;
 | 
				
			||||||
 | 
							case 'u':
 | 
				
			||||||
 | 
								euid = geteuid();
 | 
				
			||||||
 | 
								uid = getuid();
 | 
				
			||||||
 | 
								if(!n){
 | 
				
			||||||
 | 
									if(r || euid != uid)
 | 
				
			||||||
 | 
										fprintf(stdout, "%u\n", uid);
 | 
				
			||||||
 | 
									if(!r)
 | 
				
			||||||
 | 
										fprintf(stdout, "%u\n", euid);
 | 
				
			||||||
 | 
								}else
 | 
				
			||||||
 | 
									{}
 | 
				
			||||||
 | 
									/* Both busybox and GNU coreutils (according to straces) parse passwd(5)
 | 
				
			||||||
 | 
									 * for this. TODO. */
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							default:
 | 
				
			||||||
 | 
								return EX_SOFTWARE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return EX_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/levenshtein.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/levenshtein.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "putd.c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* this helped a LOT:
 | 
				
			||||||
 | 
					 * https://medium.com/@ethannam/understanding-the-levenshtein-distance-equation-for-beginners-c4285a5604f0
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					levenstein(char *a, char *b){
 | 
				
			||||||
 | 
						return 100;
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
						size_t j;
 | 
				
			||||||
 | 
						int *m;
 | 
				
			||||||
 | 
						size_t s_a;
 | 
				
			||||||
 | 
						size_t s_b;
 | 
				
			||||||
 | 
						for(s_a = 0; a[s_a] != '\0'; ++s_a);
 | 
				
			||||||
 | 
						for(s_b = 0; b[s_b] != '\0'; ++s_b);
 | 
				
			||||||
 | 
						/* Levenshtein formula using 2d matrix */
 | 
				
			||||||
 | 
						int m[s_a][s_b];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0; i < s_a; ++i) /* iterate over a */
 | 
				
			||||||
 | 
							for(j = 0; j < s_b; ++j) /* iterate over b */
 | 
				
			||||||
 | 
								//m[i][j]
 | 
				
			||||||
 | 
								;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc != 3){
 | 
				
			||||||
 | 
							write(1, "Usage: ", 7);
 | 
				
			||||||
 | 
							if(argv[0] != NULL){
 | 
				
			||||||
 | 
								for(i = 0; argv[0][i] != '\0'; ++i);
 | 
				
			||||||
 | 
								write(1, argv[0], i);
 | 
				
			||||||
 | 
							}else
 | 
				
			||||||
 | 
								write(1, "levenshtein", 11);
 | 
				
			||||||
 | 
							write(1, " [word] [word]\n", 15);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//	putd(levenstein(argv[1], argv[2]));
 | 
				
			||||||
 | 
						putd(10);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										73
									
								
								src/lowercase.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								src/lowercase.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,73 @@
 | 
				
			|||||||
 | 
					#include <ascii.h> /* ASCII_MAX_VALUE */
 | 
				
			||||||
 | 
					#include <stdbool.h> /* bool */
 | 
				
			||||||
 | 
					#include <stdio.h> /* fprintf(3), getc(3), putc(3), stderr, stdin, stdout */
 | 
				
			||||||
 | 
					#include <stdlib.h> /* exit(3) */
 | 
				
			||||||
 | 
					#include <sysexits.h> /* EX_OK, EX_USAGE, EX_SOFTWARE */
 | 
				
			||||||
 | 
					#include <unistd.h> /* getopt(3) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Enable Unicode support using official Unicode library. */
 | 
				
			||||||
 | 
					#ifdef    USE_ICU
 | 
				
			||||||
 | 
					#	include <unicode/uchar.h> /* UCHAR_MAX_VALUE, u_tolower(3) */
 | 
				
			||||||
 | 
					#	include <unicode/umachine.h> /* UChar32 */
 | 
				
			||||||
 | 
					#	include <unicode/ustdio.h> /* u_fgetc(3) */
 | 
				
			||||||
 | 
					#endif /* USE_ICU */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define PROGRAM_NAME "lowercase"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stderr, "Usage: %s (-f)\n", name);
 | 
				
			||||||
 | 
						exit(EX_USAGE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
					#ifdef USE_ICU
 | 
				
			||||||
 | 
						UChar32
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						int
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							c; /* iterating over character stream */
 | 
				
			||||||
 | 
						int d; /* iterating over getopt */
 | 
				
			||||||
 | 
						bool force;
 | 
				
			||||||
 | 
						force = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while((d = getopt(argc, argv, "f")) != -1)
 | 
				
			||||||
 | 
							switch(d){
 | 
				
			||||||
 | 
							case 'f':
 | 
				
			||||||
 | 
								force = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '?':
 | 
				
			||||||
 | 
								usage(argv[0] != NULL ? argv[0] : PROGRAM_NAME);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						if(argv[optind] != NULL) /* don't accept arguments */
 | 
				
			||||||
 | 
							usage(argv[0] != NULL ? argv[0] : PROGRAM_NAME);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef USE_ICU
 | 
				
			||||||
 | 
						while((c = u_fgetc(stdin)) != U_EOF){
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						while((c = getc(stdin)) != EOF){
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							if(c <= ASCII_MAX_VALUE)
 | 
				
			||||||
 | 
								c += ('a' - 'A') * (c >= 'A' && c <= 'Z');
 | 
				
			||||||
 | 
					#ifdef USE_ICU
 | 
				
			||||||
 | 
							else if(c <= UCHAR_MAX_VALUE)
 | 
				
			||||||
 | 
								c = u_tolower(c);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
							else if(!force){ /* past supported */
 | 
				
			||||||
 | 
								fprintf(
 | 
				
			||||||
 | 
									stderr,
 | 
				
			||||||
 | 
									"%s: Sorry, extra-ASCII characters are not yet"
 | 
				
			||||||
 | 
									" supported!\n",
 | 
				
			||||||
 | 
									argv[0] != NULL ? argv[0] : PROGRAM_NAME
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								return EX_SOFTWARE;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#ifdef USE_ICU
 | 
				
			||||||
 | 
							u_fputc(c, stdout);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
							putc(c, stdout);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return EX_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										95
									
								
								src/mm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								src/mm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,95 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include "libmm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define STDIN_NAME "<stdin>"
 | 
				
			||||||
 | 
					#define STDOUT_NAME "<stdout>"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum error{ /* possible errors */
 | 
				
			||||||
 | 
						FILE_ACCESS_ERROR,
 | 
				
			||||||
 | 
						REALLOC_ERROR
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					error(char *argv0, char *file_name, enum error errcode){
 | 
				
			||||||
 | 
						switch(errcode){
 | 
				
			||||||
 | 
						case FILE_ACCESS_ERROR:
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: %s: cannot open file\n", argv0, file_name);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						case REALLOC_ERROR:
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: error reallocating array\n", argv0);
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						char *file_name;
 | 
				
			||||||
 | 
						FILE **input = (FILE **)malloc(sizeof(FILE*));
 | 
				
			||||||
 | 
						FILE **output = (FILE **)malloc(sizeof(FILE*));
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						size_t inputc = 1;
 | 
				
			||||||
 | 
						size_t outputc = 1;
 | 
				
			||||||
 | 
						*input = NULL;
 | 
				
			||||||
 | 
						*output = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* messy argparsing, fix me to use POSIX getopt */
 | 
				
			||||||
 | 
						for(i = 1; i < argc; ++i){
 | 
				
			||||||
 | 
							if(!strcmp(argv[i++], "-i")){
 | 
				
			||||||
 | 
								if(i == argc){
 | 
				
			||||||
 | 
									fprintf(stderr, "%s: Missing option argument for \"-i\"\n", argv[0]);
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								file_name = argv[i];
 | 
				
			||||||
 | 
								input[inputc-1] = fopen(file_name, "r");
 | 
				
			||||||
 | 
								if(input[inputc-1] == NULL){
 | 
				
			||||||
 | 
									free(input);
 | 
				
			||||||
 | 
									free(output);
 | 
				
			||||||
 | 
									error(argv[0], file_name, FILE_ACCESS_ERROR);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								/* in one go, increment inputc, reallocate the input array, and set the new space in the array to NULL */
 | 
				
			||||||
 | 
								if((input = realloc(input, sizeof(FILE*) * (++inputc))) == NULL){
 | 
				
			||||||
 | 
									free(output);
 | 
				
			||||||
 | 
									error(argv[0], file_name, REALLOC_ERROR);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								input[inputc-1] = NULL;
 | 
				
			||||||
 | 
							}else if(!strcmp(argv[i++], "-o")){
 | 
				
			||||||
 | 
								if(i == argc){
 | 
				
			||||||
 | 
									fprintf(stderr, "%s: Missing option argument for \"-o\"\n", argv[0]);
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								file_name = argv[i];
 | 
				
			||||||
 | 
								output[outputc-1] = fopen(file_name, "r");
 | 
				
			||||||
 | 
								if(input[outputc-1] == NULL){
 | 
				
			||||||
 | 
									free(input);
 | 
				
			||||||
 | 
									free(output);
 | 
				
			||||||
 | 
									error(argv[0], file_name, FILE_ACCESS_ERROR);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								if((output = realloc(output, sizeof(FILE*) * (++outputc))) == NULL){
 | 
				
			||||||
 | 
									free(input);
 | 
				
			||||||
 | 
									error(argv[0], file_name, REALLOC_ERROR);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								output[outputc-1] = NULL;
 | 
				
			||||||
 | 
							}else{
 | 
				
			||||||
 | 
								fprintf(stderr, "%s: %s: Unrecognized option.\n", argv[0], argv[i]);
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* default to stdin/stdout */
 | 
				
			||||||
 | 
						if(*input == NULL){
 | 
				
			||||||
 | 
							*input = stdout;
 | 
				
			||||||
 | 
							++inputc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if(*output = NULL){
 | 
				
			||||||
 | 
							*output = stdout;
 | 
				
			||||||
 | 
							++outputc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0; i < inputc; ++i)
 | 
				
			||||||
 | 
							tee(input[inputc], output, outputc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										3
									
								
								src/nonzero.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								src/nonzero.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					int main(int argc, char **argv){
 | 
				
			||||||
 | 
						return !argc;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										52
									
								
								src/prioritize.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								src/prioritize.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,52 @@
 | 
				
			|||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* on some non-POSIX systems this may need to be "rb" */
 | 
				
			||||||
 | 
					#define READ_MODE "r"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const char *WHITESPACE = " \t\r\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* This function checks if the *****REST****** of the file is blank. It does
 | 
				
			||||||
 | 
					 * not rewind the file first. */
 | 
				
			||||||
 | 
					bool
 | 
				
			||||||
 | 
					file_is_blank(FILE *f){
 | 
				
			||||||
 | 
						int c;
 | 
				
			||||||
 | 
						while(strchr(WHITESPACE, (c = getc(f))) != NULL);
 | 
				
			||||||
 | 
						return c == EOF;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stderr, "Usage: %s <file...>\n", argv[0]);
 | 
				
			||||||
 | 
						exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv){
 | 
				
			||||||
 | 
						char *argv0;
 | 
				
			||||||
 | 
						FILE *fp[argc-1];
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						struct stat s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						argv0 = argv[0];
 | 
				
			||||||
 | 
						--argc; ++argv;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc < 2)
 | 
				
			||||||
 | 
							usage(argv0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0; i < argc; ++i){
 | 
				
			||||||
 | 
							if((fp[i] = fopen(argv[i], READ_MODE)) == NULL){
 | 
				
			||||||
 | 
								fprintf(stderr, 
 | 
				
			||||||
 | 
									"%s: %s: Error opening file for reading.\n",
 | 
				
			||||||
 | 
									argv0, argv[i]);
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* UNREACHABLE */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/retval.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/retval.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					#include <ascii.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include "libstr.h"
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argv[1] == NULL){
 | 
				
			||||||
 | 
							fprintf(stderr, "Usage: %s [exit code]\n", argv[0]);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(strint(argv[1], &retval, ASCII_DIGITS_DECIMAL_UPPER) == NULL){
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: %s: Not an integer\n", argv[0], argv[1]);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										120
									
								
								src/runlength.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										120
									
								
								src/runlength.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,120 @@
 | 
				
			|||||||
 | 
					#include <ctype.h> /* isdigit(3) */
 | 
				
			||||||
 | 
					#include <stdio.h> /* fprintf(3), getc(3), putc(3) */
 | 
				
			||||||
 | 
					#include <stdlib.h> /* stdin, stderr, stdout */
 | 
				
			||||||
 | 
					#include <sysexits.h> /* EX_DATAERR, EX_OK */
 | 
				
			||||||
 | 
					#include <unistd.h> /* for noargvzero.h */
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Unicode compatibility coming someday */
 | 
				
			||||||
 | 
					#define GETC getc
 | 
				
			||||||
 | 
					#define PUTC putc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NUMBER_TERMINATOR '*'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* syntax error if a decoding file ends with [char][char] */
 | 
				
			||||||
 | 
					/* if(STRICT) just print it out */
 | 
				
			||||||
 | 
					#define STRICT 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int decode(FILE *input, FILE *output){
 | 
				
			||||||
 | 
						int c[2];
 | 
				
			||||||
 | 
						unsigned int num;
 | 
				
			||||||
 | 
						enum{NUMBER_PARSING = 1} state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c[0] = EOF;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* reading -> (current char == prev char)> number parsing -> reading */
 | 
				
			||||||
 | 
						while((c[1] = GETC(input)) != EOF)
 | 
				
			||||||
 | 
							if(state == NUMBER_PARSING){
 | 
				
			||||||
 | 
								if(isdigit(c[1]))
 | 
				
			||||||
 | 
									num = num * 10 + c[1] - '0';
 | 
				
			||||||
 | 
								else if(c[1] == NUMBER_TERMINATOR){
 | 
				
			||||||
 | 
									for(; num > 0; --num)
 | 
				
			||||||
 | 
										PUTC(c[0], output);
 | 
				
			||||||
 | 
									c[0] = EOF; c[1] = EOF;
 | 
				
			||||||
 | 
									state = 0;
 | 
				
			||||||
 | 
								}else
 | 
				
			||||||
 | 
									return EX_DATAERR;
 | 
				
			||||||
 | 
							}else if(c[1] == c[0]){
 | 
				
			||||||
 | 
								num = 0;
 | 
				
			||||||
 | 
								state = NUMBER_PARSING;
 | 
				
			||||||
 | 
							}else{
 | 
				
			||||||
 | 
								if(c[0] != EOF)
 | 
				
			||||||
 | 
									PUTC(c[0], output);
 | 
				
			||||||
 | 
								c[0] = c[1];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(state == NUMBER_PARSING && !STRICT){
 | 
				
			||||||
 | 
							/* it doesn't make sense to put this in a loop */
 | 
				
			||||||
 | 
							PUTC(c[0], output); PUTC(c[0], output);
 | 
				
			||||||
 | 
						}else if(state == NUMBER_PARSING)
 | 
				
			||||||
 | 
							return EX_DATAERR;
 | 
				
			||||||
 | 
						else if(c[0] != EOF)
 | 
				
			||||||
 | 
							PUTC(c[0], output);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return EX_OK;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int encode(FILE *input, FILE *output){
 | 
				
			||||||
 | 
						int c[2];
 | 
				
			||||||
 | 
						unsigned int num;
 | 
				
			||||||
 | 
						enum{COUNTING = 1} state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* It was more fun to use gotos than to use sane structure. */
 | 
				
			||||||
 | 
						for(c[0] = EOF, num = 2, state = 0; ;)
 | 
				
			||||||
 | 
							if((c[1] = GETC(input)) == EOF){
 | 
				
			||||||
 | 
								if(state == COUNTING)
 | 
				
			||||||
 | 
									goto dump;
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
									goto place;
 | 
				
			||||||
 | 
							}else if(state == COUNTING){
 | 
				
			||||||
 | 
								if(c[1] != c[0]){
 | 
				
			||||||
 | 
					dump:				PUTC(c[0], output);
 | 
				
			||||||
 | 
									fprintf(output,
 | 
				
			||||||
 | 
										"%d%c",
 | 
				
			||||||
 | 
										num, NUMBER_TERMINATOR
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									num = 2;
 | 
				
			||||||
 | 
									state = 0;
 | 
				
			||||||
 | 
									goto next;
 | 
				
			||||||
 | 
								}else
 | 
				
			||||||
 | 
									++num;
 | 
				
			||||||
 | 
							}else if(c[1] == c[0])
 | 
				
			||||||
 | 
								state = COUNTING;
 | 
				
			||||||
 | 
							else{ /* c[1] != c[0] */
 | 
				
			||||||
 | 
								if(c[0] != EOF) /* c[0] will be EOF at first */
 | 
				
			||||||
 | 
					place:				PUTC(c[0], output);
 | 
				
			||||||
 | 
					next:			if(c[1] == EOF)
 | 
				
			||||||
 | 
									return EX_OK;
 | 
				
			||||||
 | 
								c[0] = c[1];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int (*procedures[2])(FILE *input, FILE *output) = {decode, encode};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* this is inelegant */
 | 
				
			||||||
 | 
					char procedure_names[2][7] = {"decode", "encode"};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						enum{DECODE = 0, ENCODE = 1, INVALID = 2} procedure;
 | 
				
			||||||
 | 
						procedure = 0;
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc != 2){
 | 
				
			||||||
 | 
					usage:		fprintf(stderr, "Usage: %s {decode,encode}\n", argv[0]);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* imperfect */
 | 
				
			||||||
 | 
						for(i = 0; argv[1][i] != '\0' || procedure_names[procedure][i] != '\0'; ++i)
 | 
				
			||||||
 | 
							if(argv[1][i] != procedure_names[procedure][i])
 | 
				
			||||||
 | 
								if(++procedure == INVALID)
 | 
				
			||||||
 | 
									goto usage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if((retval = procedures[procedure](stdin, stdout)) == EX_DATAERR)
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: syntax error.\n", argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/simexec.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/simexec.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					#include <stddef.h> /* NULL */
 | 
				
			||||||
 | 
					#include <sysexits.h> /* EX_USAGE */
 | 
				
			||||||
 | 
					#include <unistd.h> /* execv(3), write(2) */
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc < 2){
 | 
				
			||||||
 | 
							write(2, "Usage: ", 7);
 | 
				
			||||||
 | 
							for(i = 0; argv[0][i] != '\0'; ++i);
 | 
				
			||||||
 | 
							write(2, argv[0], i);
 | 
				
			||||||
 | 
							write(2, " [pathname], [argv...]\n", 23);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return execv(argv[1], argv+2);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/sleep.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/sleep.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,21 @@
 | 
				
			|||||||
 | 
					#include <stdlib.h> /* atoi(3) */
 | 
				
			||||||
 | 
					#include <sysexits.h> /* EX_USAGE */
 | 
				
			||||||
 | 
					#include <unistd.h> /* sleep(3) */
 | 
				
			||||||
 | 
					#include "libstris.h" /* stris(3) */
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv){
 | 
				
			||||||
 | 
						int s;
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
						if(argc != 2 || !stris(STRIS_TYPE_INT, argv[1])){
 | 
				
			||||||
 | 
							write(2, "Usage: ", 7);
 | 
				
			||||||
 | 
							for(s = 0; argv[0][s] != '\0'; ++s);
 | 
				
			||||||
 | 
							write(2, argv[0], s);
 | 
				
			||||||
 | 
							write(2, " [seconds]\n", 11);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						s = atoi(argv[1]);
 | 
				
			||||||
 | 
						while(s > 0)
 | 
				
			||||||
 | 
							s = sleep(s);
 | 
				
			||||||
 | 
						return s;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										25
									
								
								src/streq.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/streq.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "noargvzero.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int j;
 | 
				
			||||||
 | 
						NOARGVZERO(argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc < 3){
 | 
				
			||||||
 | 
							write(2, "Usage: ", 7);
 | 
				
			||||||
 | 
							for(i = 0; argv[0][i] != '\0'; ++i);
 | 
				
			||||||
 | 
							write(2, argv[0], i);
 | 
				
			||||||
 | 
							write(2, " [strings...]\n", 14);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* i is the arg index, j is the char index */
 | 
				
			||||||
 | 
						for(j = 0; argv[1][j] != '\0'; ++j)
 | 
				
			||||||
 | 
							for(i = 2; i < argc; ++i)
 | 
				
			||||||
 | 
								if(argv[i-1][j] != argv[i][j])
 | 
				
			||||||
 | 
									return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										50
									
								
								src/stris.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								src/stris.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,50 @@
 | 
				
			|||||||
 | 
					#include <stddef.h>
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "libstrnum.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int *typenames[] = {
 | 
				
			||||||
 | 
						(int []){ 'f','l','o','a','t', ASCII_US, STRIS_TYPE_FLOAT, '\0' },
 | 
				
			||||||
 | 
						(int []){ 'i','n','t', ASCII_US, STRIS_TYPE_INT, '\0' },
 | 
				
			||||||
 | 
						(int []){ 'u','i','n','t', ASCII_US, STRIS_TYPE_UINT, '\0' }
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					size_t typenames_s = 3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int j;
 | 
				
			||||||
 | 
						int k;
 | 
				
			||||||
 | 
						enum Strtype t;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(k = 0; argv[0][k] != '\0'; ++k);
 | 
				
			||||||
 | 
						if(argc < 3){
 | 
				
			||||||
 | 
							write(2, "Usage: ", 7);
 | 
				
			||||||
 | 
							write(2, argv[0], k);
 | 
				
			||||||
 | 
							write(2, " [type] [string...]\n", 20);
 | 
				
			||||||
 | 
							return EX_USAGE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						j = 0;
 | 
				
			||||||
 | 
						t = 0;
 | 
				
			||||||
 | 
						for(i = 0; argv[1][i] != '\0'; ++i)
 | 
				
			||||||
 | 
							if(typenames[j][i] != argv[1][i])
 | 
				
			||||||
 | 
								if(++j >= typenames_s){
 | 
				
			||||||
 | 
									write(2, argv[0], k);
 | 
				
			||||||
 | 
									write(2, ": ", 2);
 | 
				
			||||||
 | 
									for(k = 0; argv[1][k] != '\0'; ++k);
 | 
				
			||||||
 | 
									write(2, argv[1], k);
 | 
				
			||||||
 | 
									write(2, ": No such type\n", 15);
 | 
				
			||||||
 | 
									return EX_DATAERR;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argv[1][i] == '\0' && typenames[j][i] == ASCII_US)
 | 
				
			||||||
 | 
							t = typenames[j][i+1];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 2; i < argc; ++i)
 | 
				
			||||||
 | 
							if(!stris(t, argv[i]))
 | 
				
			||||||
 | 
								return 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/substitute.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/substitute.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "liberror.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					exhaust_buffer(char *b, size_t s){
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
						for(i = 0; i < s; ++i)
 | 
				
			||||||
 | 
							if(b[i] != 0)
 | 
				
			||||||
 | 
								putc(b[i], stdout);
 | 
				
			||||||
 | 
						free(b);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					print_stdin(void){
 | 
				
			||||||
 | 
						char c;
 | 
				
			||||||
 | 
						while((c = getc(stdin)) != EOF)
 | 
				
			||||||
 | 
							putc(c, stdout);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					substitute(char *phrase, char *substitution, bool exit_on_first, char *name){
 | 
				
			||||||
 | 
						char *b = (char *)calloc(strlen(phrase)+1, sizeof(char));
 | 
				
			||||||
 | 
						size_t i;
 | 
				
			||||||
 | 
						if(b == NULL)
 | 
				
			||||||
 | 
							error(name, ALLOCATION_ERROR);
 | 
				
			||||||
 | 
						while((b[strlen(phrase)-1] = getc(stdin)) != EOF){
 | 
				
			||||||
 | 
							for(i = 0;
 | 
				
			||||||
 | 
								b[i] == phrase[i]
 | 
				
			||||||
 | 
								&& b[i] != 0
 | 
				
			||||||
 | 
								&& phrase[i] != 0;
 | 
				
			||||||
 | 
							++i);
 | 
				
			||||||
 | 
							if(i == strlen(phrase)){
 | 
				
			||||||
 | 
								fputs(substitution, stdout);
 | 
				
			||||||
 | 
								for(i = 0; i < strlen(phrase);)
 | 
				
			||||||
 | 
									b[i++] = 0;
 | 
				
			||||||
 | 
								if(exit_on_first){
 | 
				
			||||||
 | 
									exhaust_buffer(b, strlen(phrase)+1);
 | 
				
			||||||
 | 
									print_stdin();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}else
 | 
				
			||||||
 | 
								putc(*b, stdout);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* There's a more efficient way to maintain a buffer here,
 | 
				
			||||||
 | 
							 * where I keep an unordered string of chars and form an
 | 
				
			||||||
 | 
							 * ordered string when I need to check against the phrase
 | 
				
			||||||
 | 
							 * to match. However it's math-intensive, which sucks not just
 | 
				
			||||||
 | 
							 * for a self-taught lamer but in general in regards to muh
 | 
				
			||||||
 | 
							 * simplicity, and the math undercuts the performance gain
 | 
				
			||||||
 | 
							 * from avoiding touching memory. Also, come on, you're never
 | 
				
			||||||
 | 
							 * gonna have a phrase longer than 100 bytes! Who cares?! */
 | 
				
			||||||
 | 
							for(i = 0; i < strlen(phrase); ++i)
 | 
				
			||||||
 | 
								b[i] = b[i+1];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						exhaust_buffer(b, strlen(phrase)+1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stdout, "Usage: %s (-fhr) [phrase] [substitution]\n", name);
 | 
				
			||||||
 | 
						exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						extern char *optarg;
 | 
				
			||||||
 | 
						extern int optind;
 | 
				
			||||||
 | 
						bool exit_on_first = 0;
 | 
				
			||||||
 | 
						char c;
 | 
				
			||||||
 | 
						char *argv0 = argv[0];
 | 
				
			||||||
 | 
						bool regex_mode = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while((c = getopt(argc, argv, "fhr")) != -1){
 | 
				
			||||||
 | 
							switch(c){
 | 
				
			||||||
 | 
							/* -f exists because there exist uses of `sed 's/foo/bar/'`
 | 
				
			||||||
 | 
							 * without the trailing `g` for global substitution that
 | 
				
			||||||
 | 
							 * would be borked if made global. Perhaps there are other ways
 | 
				
			||||||
 | 
							 * to do so that mean that this option doesn't need to be
 | 
				
			||||||
 | 
							 * implemented, but it's kind of easy to just add so
 | 
				
			||||||
 | 
							 * whatever. */
 | 
				
			||||||
 | 
							case 'f': exit_on_first = 1;
 | 
				
			||||||
 | 
							case 'h': usage(argv0);
 | 
				
			||||||
 | 
							/* By default regex is not parsed; this is because regular
 | 
				
			||||||
 | 
							 * expressions are not known to the GENERAL user. The kind of
 | 
				
			||||||
 | 
							 * user that uses this utility /does/ know regex, but the kind
 | 
				
			||||||
 | 
							 * of user this utility targets does not, so don't implement
 | 
				
			||||||
 | 
							 * potentially undesirable functionality by default.
 | 
				
			||||||
 | 
							 * If you know regex you know how to look up a manpage. */
 | 
				
			||||||
 | 
							case 'r':
 | 
				
			||||||
 | 
								regex_mode = 1;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case '?': default: usage(argv0);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						argc -= optind;
 | 
				
			||||||
 | 
						argv += optind;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc < 2 || argc > 3)
 | 
				
			||||||
 | 
							usage(argv0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(regex_mode == 0)
 | 
				
			||||||
 | 
							substitute(argv[0], argv[1], exit_on_first, argv0);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							{ printf("Not implemented.\n"); exit(1); }
 | 
				
			||||||
 | 
					//		substitute_regex(argv[0], argv[1], exit_on_first, argv0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										183
									
								
								src/sysexits.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/sysexits.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,183 @@
 | 
				
			|||||||
 | 
					#include <ascii.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "usefulmacros.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TAB_WIDTH 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Changing ENUM to DEFINE will make this output the traditional BSD header
 | 
				
			||||||
 | 
					 * verbatim, without copyright notice. I don't have any fucking idea if that's
 | 
				
			||||||
 | 
					 * a copyright violation, but let's keep this as ENUM to skirt by that little
 | 
				
			||||||
 | 
					 * technicality.
 | 
				
			||||||
 | 
					 * I implemented sysexits(3) in the enum method before reading the BSD 4.0
 | 
				
			||||||
 | 
					 * source to see how they did it. */
 | 
				
			||||||
 | 
					#define ENUM 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *program_name = "sysexits";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//static const char comment_prefix[] = "/* ";
 | 
				
			||||||
 | 
					static const char comment_prefix_ongoing[] = " * ";
 | 
				
			||||||
 | 
					static const char comment_suffix[] = " */\n";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char header_prefix[] =
 | 
				
			||||||
 | 
						"#ifndef _SYSEXITS_H\n"
 | 
				
			||||||
 | 
						"#\tdefine _SYSEXITS_H\n"
 | 
				
			||||||
 | 
						"enum{\n"
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* ASSUMPTIONS:
 | 
				
			||||||
 | 
					 * - This array is always organized.
 | 
				
			||||||
 | 
					 * - All characters in descriptions are one space wide.
 | 
				
			||||||
 | 
					 * - The only whitespace in descriptions is ASCII_SP. */
 | 
				
			||||||
 | 
					static const struct {
 | 
				
			||||||
 | 
						char *desc;
 | 
				
			||||||
 | 
						char *name;
 | 
				
			||||||
 | 
						int status;
 | 
				
			||||||
 | 
					}sysexits[] = {
 | 
				
			||||||
 | 
						/* sysexit descriptions copied from FreeBSD's sysexits(3). */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"All is well.", /* except this one */
 | 
				
			||||||
 | 
						"EX_OK", 0,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"The command was used incorrectly, e.g., with the wrong number of"
 | 
				
			||||||
 | 
						" arguments, a bad flag, a bad syntax in a parameter, or whatever.",
 | 
				
			||||||
 | 
						"EX_USAGE", 64,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"The input data was incorrect in some way. This should only be used"
 | 
				
			||||||
 | 
						" for user's data and not system files.",
 | 
				
			||||||
 | 
						"EX_DATAERR", 65,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"An input file (not a system file) did not exist or was not readable."
 | 
				
			||||||
 | 
						" This could also include errors like \"No message\" to a mailer (if it"
 | 
				
			||||||
 | 
						" cared to catch it).",
 | 
				
			||||||
 | 
						 "EX_NOINPUT", 66,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"The user specified did not exist. This might be used for mail"
 | 
				
			||||||
 | 
						" addresses or remote logins.",
 | 
				
			||||||
 | 
						 "EX_NOUSER", 67,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"The host specified did not exist. This is used in mail addresses or"
 | 
				
			||||||
 | 
						" network requests.",
 | 
				
			||||||
 | 
						 "EX_NOHOST", 68,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"A service is unavailable. This can occur if a support program or"
 | 
				
			||||||
 | 
						" file does not exist. This can also be used as a catchall message"
 | 
				
			||||||
 | 
						" when something you wanted to do does not work, but you do not know"
 | 
				
			||||||
 | 
						" why.",
 | 
				
			||||||
 | 
						"EX_UNAVAILABLE", 69,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"An internal software error has been detected. This should be limited"
 | 
				
			||||||
 | 
						" to non-operating system related errors as possible.",
 | 
				
			||||||
 | 
						"EX_SOFTWARE", 70,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"An operating system error has been detected. This is intended to be"
 | 
				
			||||||
 | 
						" used for such things as \"cannot fork\", \"cannot create pipe\", or"
 | 
				
			||||||
 | 
						" the like. It includes things like getuid returning a user that does"
 | 
				
			||||||
 | 
						" not exist in the passwd file.",
 | 
				
			||||||
 | 
						"EX_OSERR", 71,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"Some system file (e.g., /etc/passwd, /var/run/utx.active, etc.) does"
 | 
				
			||||||
 | 
						" not exist, cannot be opened, or has some sort of error (e.g., syntax"
 | 
				
			||||||
 | 
						" error).",
 | 
				
			||||||
 | 
						"EX_OSFILE", 72,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"A (user specified) output file cannot be created.",
 | 
				
			||||||
 | 
						"EX_CANTCREAT", 73,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"An error occurred while doing I/O on some file.",
 | 
				
			||||||
 | 
						"EX_IOERR", 74,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"Temporary failure, indicating something that is not really an error."
 | 
				
			||||||
 | 
						" In sendmail, this means that a mailer (e.g.) could not create a"
 | 
				
			||||||
 | 
						" connection, and the request should be reattempted later.",
 | 
				
			||||||
 | 
						"EX_TEMPFAIL", 75,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"The remote system returned something that was \"not possible\" during a"
 | 
				
			||||||
 | 
						" protocol exchange.",
 | 
				
			||||||
 | 
						"EX_PROTOCOL", 76,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"You did not have sufficient permission to perform the operation."
 | 
				
			||||||
 | 
						" This is not intended for file system problems, which should use"
 | 
				
			||||||
 | 
						" EX_NOINPUT or EX_CANTCREAT, but rather for higher level"
 | 
				
			||||||
 | 
						" permissions.",
 | 
				
			||||||
 | 
						"EX_NOPERM", 77,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"Something was found in an unconfigured or misconfigured state.",
 | 
				
			||||||
 | 
						"EX_CONFIG", 78
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char header_suffix[] =
 | 
				
			||||||
 | 
						"};\n"
 | 
				
			||||||
 | 
						"#endif /* ifndef _SYSEXITS_H */\n"
 | 
				
			||||||
 | 
					;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					static int findbyint(int status){
 | 
				
			||||||
 | 
						for(i = 0; i < ARRAYLEN(sysexits); ++i)
 | 
				
			||||||
 | 
							if(sysexits[i].status == status)
 | 
				
			||||||
 | 
								return i;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void output_comment(int fd, int indentation, int width, char *comment){
 | 
				
			||||||
 | 
						size_t word_start;
 | 
				
			||||||
 | 
						size_t line_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0, line_start = 0, word_start = 0; ; ++i)
 | 
				
			||||||
 | 
							switch(comment[i]){
 | 
				
			||||||
 | 
							case '\0':
 | 
				
			||||||
 | 
								while(		i - line_start 
 | 
				
			||||||
 | 
										+ ARRAYLEN(comment_suffix)
 | 
				
			||||||
 | 
										+ indentation * TAB_WIDTH
 | 
				
			||||||
 | 
										> width){
 | 
				
			||||||
 | 
									i = word_start - 2; /* - current char, - space */
 | 
				
			||||||
 | 
									write(
 | 
				
			||||||
 | 
										fd, comment_prefix_ongoing,
 | 
				
			||||||
 | 
										ARRAYLEN(comment_prefix_ongoing)
 | 
				
			||||||
 | 
									);
 | 
				
			||||||
 | 
									write(fd, comment + line_start, i - line_start);
 | 
				
			||||||
 | 
									i += 2; /* + space, + next word char */
 | 
				
			||||||
 | 
									write(fd, "\n", 1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								write(fd, comment + line_start, i - line_start);
 | 
				
			||||||
 | 
								write(fd, comment_suffix, ARRAYLEN(comment_suffix));
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void output_header(void){
 | 
				
			||||||
 | 
						write(1, header_prefix, ARRAYLEN(header_prefix) - 1);
 | 
				
			||||||
 | 
						for(i = 0; i < ARRAYLEN(sysexits); ++i){
 | 
				
			||||||
 | 
							output_comment(1, 1 * TAB_WIDTH, 80, sysexits[i].desc);
 | 
				
			||||||
 | 
							#ifdef ENUM
 | 
				
			||||||
 | 
							fprintf(stdout, "\t%s = %d%s",
 | 
				
			||||||
 | 
								sysexits[i].name,
 | 
				
			||||||
 | 
								sysexits[i].status,
 | 
				
			||||||
 | 
								i < ARRAYLEN(sysexits) - 1 ? ",\n" : "\n"
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							#endif /* ifdef ENUM */
 | 
				
			||||||
 | 
							#ifdef DEFINE
 | 
				
			||||||
 | 
							fprintf(stdout, "#\tdefine %s %d\n",
 | 
				
			||||||
 | 
								sysexits[i].name,
 | 
				
			||||||
 | 
								sysexits[i].status
 | 
				
			||||||
 | 
							);
 | 
				
			||||||
 | 
							#endif /* ifdef DEFINE */
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						write(1, header_suffix, ARRAYLEN(header_suffix) - 1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						if(argv[0] == NULL){
 | 
				
			||||||
 | 
							argv[0] = program_name;
 | 
				
			||||||
 | 
							++argc;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						output_header();
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										152
									
								
								src/tail.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								src/tail.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,152 @@
 | 
				
			|||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <limits.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include "args.h"
 | 
				
			||||||
 | 
					#include "libcharin.h"
 | 
				
			||||||
 | 
					#include "libstris.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define DEFAULT_LENGTH 10
 | 
				
			||||||
 | 
					#define OFLOW(STR) (STR[strlen(STR)-1] != '\n')
 | 
				
			||||||
 | 
					#ifndef PAGE_SIZE
 | 
				
			||||||
 | 
					#	ifndef PAGESIZE
 | 
				
			||||||
 | 
					#		define PAGE_SIZE 1024
 | 
				
			||||||
 | 
					#	else
 | 
				
			||||||
 | 
					#		define PAGE_SIZE PAGESIZE
 | 
				
			||||||
 | 
					#	endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
						TODO
 | 
				
			||||||
 | 
						* fix limits.h stuff; if limits.h isn't on the system define
 | 
				
			||||||
 | 
							reasonable limits in its place
 | 
				
			||||||
 | 
						* don't use unsafe string functions
 | 
				
			||||||
 | 
						* fix bugs
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					tail(FILE *input, FILE *output, int length){
 | 
				
			||||||
 | 
						bool loop = 1;
 | 
				
			||||||
 | 
						char *lines[length];
 | 
				
			||||||
 | 
						size_t ls[length];
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int filelines = 0;
 | 
				
			||||||
 | 
						size_t offset = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 0; i < length; i++){
 | 
				
			||||||
 | 
							ls[i] = PAGE_SIZE;
 | 
				
			||||||
 | 
							lines[i] = (char *)calloc(ls[i], sizeof(char));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while(fgets(lines[i] + offset, ls[i], input)){
 | 
				
			||||||
 | 
							if(OFLOW(lines[i])){
 | 
				
			||||||
 | 
								offset += ls[i] - 1;
 | 
				
			||||||
 | 
								ls[i] += PAGE_SIZE;
 | 
				
			||||||
 | 
								/* should be more resilient */
 | 
				
			||||||
 | 
								if(realloc(lines[i], ls[i]) == NULL){
 | 
				
			||||||
 | 
									fprintf(stderr, "tail: Couldn't re-allocate memory (%d bytes)\n", ls[i] * sizeof(char));
 | 
				
			||||||
 | 
									exit(1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							offset = 0;
 | 
				
			||||||
 | 
							++filelines;
 | 
				
			||||||
 | 
							i = (i + 1) % length;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = filelines % length; loop || i != filelines % length; i = (i + 1) % length){
 | 
				
			||||||
 | 
							if(loop && i == filelines % length)
 | 
				
			||||||
 | 
								loop = 0;
 | 
				
			||||||
 | 
							printf("%s", lines[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* glitch here when `tail`ing normal files */
 | 
				
			||||||
 | 
						for(i = 0; i < length; i++){
 | 
				
			||||||
 | 
							free(lines[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stderr, "Usage: %s [-ht] [-n integer] [file...]\n", name);
 | 
				
			||||||
 | 
						exit(1);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						char **argsv = getargsv(argc, argv);
 | 
				
			||||||
 | 
						char *flags = getflags(argc, argv);
 | 
				
			||||||
 | 
						char mode[3] = "rb";
 | 
				
			||||||
 | 
						char filepath[NAME_MAX+PATH_MAX];
 | 
				
			||||||
 | 
						char *lengthstr;
 | 
				
			||||||
 | 
						size_t fplen = NAME_MAX+PATH_MAX;
 | 
				
			||||||
 | 
						FILE *input;
 | 
				
			||||||
 | 
						FILE *output = stdout;
 | 
				
			||||||
 | 
						int argsc = getargsc(argc, argv);
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						int length = DEFAULT_LENGTH;
 | 
				
			||||||
 | 
						size_t s;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(charin(flags, 'h'))
 | 
				
			||||||
 | 
							usage(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(charin(flags, 'n')){
 | 
				
			||||||
 | 
							lengthstr = getflag(argc, argv, 'n');
 | 
				
			||||||
 | 
							if(!strisint(lengthstr) || *lengthstr == '\0')
 | 
				
			||||||
 | 
								usage(argv[0]);
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								length = atoi(lengthstr);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(charin(flags, 't'))
 | 
				
			||||||
 | 
							/* Explicitly open files as text rather than as binary.
 | 
				
			||||||
 | 
							 * this changes "rb" to "r". Should have no effect on
 | 
				
			||||||
 | 
							 * POSIX systems but may change CRLF to just LF with
 | 
				
			||||||
 | 
							 * MS Windows. I don't know why anyone would need this
 | 
				
			||||||
 | 
							 * but it's here for those that do. */
 | 
				
			||||||
 | 
							mode[1] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argsc == 0)
 | 
				
			||||||
 | 
							tail(stdin, output, length);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							for(i = 1; i < argsc; ++i){
 | 
				
			||||||
 | 
								if(i > 1)
 | 
				
			||||||
 | 
									fprintf(output, "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if(!strcmp(argv[i], "-")){
 | 
				
			||||||
 | 
									realpath(argv[i], filepath);
 | 
				
			||||||
 | 
									input = fopen(argv[i], "r");
 | 
				
			||||||
 | 
									if(input == NULL){
 | 
				
			||||||
 | 
										fprintf(stderr, "%s: %s: Could not open file for reading\n", argv[0], filepath);
 | 
				
			||||||
 | 
										exit(1);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}else{
 | 
				
			||||||
 | 
									input = stdin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									/* probably safe but could be vulnerable */
 | 
				
			||||||
 | 
									/* just making filepath[] = "<stdin>" */
 | 
				
			||||||
 | 
									s = strlen("<stdin>") + 1; /* minimum size for filepath */
 | 
				
			||||||
 | 
									if(fplen >= s)
 | 
				
			||||||
 | 
										strcpy(filepath, "<stdin>");
 | 
				
			||||||
 | 
									else if(realloc(filepath, s) == NULL)
 | 
				
			||||||
 | 
										fprintf(stderr, "%s: Failed to reallocate path string, using <stdin>\n", argv[0]);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								fprintf(output, "==> %s <==\n", filepath);
 | 
				
			||||||
 | 
								tail(input, output, length);
 | 
				
			||||||
 | 
								if(input != stdin && fclose(input) != 0){
 | 
				
			||||||
 | 
									fprintf(stderr, "%s: %s: Could not close file. Exiting...\n", argv[0], filepath);
 | 
				
			||||||
 | 
									exit(1);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										97
									
								
								src/which.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								src/which.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,97 @@
 | 
				
			|||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h> /* fprintf(3) */
 | 
				
			||||||
 | 
					#include <stdlib.h> /* exit(3) */
 | 
				
			||||||
 | 
					#include <sysexits.h>
 | 
				
			||||||
 | 
					#include <unistd.h> /* access(2), chdir(2) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "libshell.h" /* getpaths(3) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stderr, "Usage: %s (-a) [name]\n", name);
 | 
				
			||||||
 | 
						exit(EX_USAGE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int
 | 
				
			||||||
 | 
					which(char *program, char **paths, char *name, bool breakonfirst){
 | 
				
			||||||
 | 
						char **q;
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
						retval = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(q = paths; *q != NULL; ++q){
 | 
				
			||||||
 | 
							if(chdir(*q) != 0)
 | 
				
			||||||
 | 
								switch(retval = errno){
 | 
				
			||||||
 | 
								/* Non-issues in the context of this program */
 | 
				
			||||||
 | 
								case EACCES: /* Access denied */
 | 
				
			||||||
 | 
								case ELOOP:  /* Too many symlinks in path */
 | 
				
			||||||
 | 
								case ENAMETOOLONG: /* Name too long */
 | 
				
			||||||
 | 
								case ENOENT: /* Directory doesn't exist */
 | 
				
			||||||
 | 
								case ENOTDIR: /* Not a directory */
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								case EFAULT:
 | 
				
			||||||
 | 
									goto apology;
 | 
				
			||||||
 | 
								case EIO:
 | 
				
			||||||
 | 
									goto ioerr;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							/* Changed dir, now check for file in dir */
 | 
				
			||||||
 | 
							if(access(program, R_OK | X_OK) != 0)
 | 
				
			||||||
 | 
								switch(retval = errno){
 | 
				
			||||||
 | 
								case EACCES:
 | 
				
			||||||
 | 
								case ELOOP:
 | 
				
			||||||
 | 
								case ENAMETOOLONG:
 | 
				
			||||||
 | 
								case ENOENT:
 | 
				
			||||||
 | 
								case EROFS:
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								case EFAULT:
 | 
				
			||||||
 | 
									goto apology;
 | 
				
			||||||
 | 
								case EIO:
 | 
				
			||||||
 | 
									goto ioerr;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							else{
 | 
				
			||||||
 | 
								fprintf(stdout, "%s%s\n", *q, program);
 | 
				
			||||||
 | 
								if(breakonfirst != 0)
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					end:
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					apology:
 | 
				
			||||||
 | 
						fprintf(stderr,
 | 
				
			||||||
 | 
					/* EFAULT means the pointer passed to either chdir(2) or access(2) was outside
 | 
				
			||||||
 | 
					 * of the address space available to the program. This means something's Very
 | 
				
			||||||
 | 
					 * Wrong with getpaths(3) and libshell has to be fixed. That'd be a serious,
 | 
				
			||||||
 | 
					 * common error, so try to reassure the user and solicit a bug report. */
 | 
				
			||||||
 | 
					"%s: EFAULT\n"
 | 
				
			||||||
 | 
					"You the user did nothing to invoke this error message. This is an error in\n"
 | 
				
			||||||
 | 
					"which, a program you or another program executed. PLEASE e-mail the creator\n"
 | 
				
			||||||
 | 
					"of this program (the address can be found in the corresponding manual page)\n"
 | 
				
			||||||
 | 
					"and tell them you got this error and what you were doing when it happened.\n"
 | 
				
			||||||
 | 
					"Sorry!\n", name);
 | 
				
			||||||
 | 
						goto end;
 | 
				
			||||||
 | 
					ioerr:
 | 
				
			||||||
 | 
						fprintf(stderr, "%s: filesystem I/O error\n", name);
 | 
				
			||||||
 | 
						goto end;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						char **paths;
 | 
				
			||||||
 | 
						int retval;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if(argc <= 1)
 | 
				
			||||||
 | 
							usage(argv[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if((paths = getpaths()) == NULL){
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Could not get the value of $PATH\n", argv[0]);
 | 
				
			||||||
 | 
							exit(1);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for(i = 1; i < argc; ++i)
 | 
				
			||||||
 | 
							if((retval = which(argv[i], paths, argv[0], 1)) != 0)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(*paths);
 | 
				
			||||||
 | 
						free(paths);
 | 
				
			||||||
 | 
						return retval;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										113
									
								
								src/xml.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								src/xml.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					#include <ctype.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include "arraylen.h"
 | 
				
			||||||
 | 
					#include "bool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define TAGSTART '<'
 | 
				
			||||||
 | 
					#define TAGEND   '>'
 | 
				
			||||||
 | 
					#define ETAG     '/'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LF       '\n'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					  start-tag    end-tag
 | 
				
			||||||
 | 
					    |            |
 | 
				
			||||||
 | 
					    V            V
 | 
				
			||||||
 | 
					  <TAG>CONTENT</TAG>
 | 
				
			||||||
 | 
					  ^   ^        ^
 | 
				
			||||||
 | 
					  |   |        |
 | 
				
			||||||
 | 
					  |   TAGEND   ETAG
 | 
				
			||||||
 | 
					  |
 | 
				
			||||||
 | 
					  TAGSTART
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  empty-element tag
 | 
				
			||||||
 | 
					    |
 | 
				
			||||||
 | 
					    | optional whitespace
 | 
				
			||||||
 | 
					    | |
 | 
				
			||||||
 | 
					    | | TAGEND
 | 
				
			||||||
 | 
					    | | |
 | 
				
			||||||
 | 
					    V V V
 | 
				
			||||||
 | 
					  <TAG />
 | 
				
			||||||
 | 
					  ^    ^
 | 
				
			||||||
 | 
					  |    |
 | 
				
			||||||
 | 
					  |    ETAG
 | 
				
			||||||
 | 
					  |
 | 
				
			||||||
 | 
					  TAGSTART
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* a lot of this program's design is weird and kind of overengineered.
 | 
				
			||||||
 | 
					   this is to drastically limit the memory used. */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum state{
 | 
				
			||||||
 | 
						error = -1, /* for future use */
 | 
				
			||||||
 | 
						init = 0, /* waiting for a root tag */
 | 
				
			||||||
 | 
						starttagreading,
 | 
				
			||||||
 | 
						tagreading,
 | 
				
			||||||
 | 
						eetagreading, /* throw away everything until state change */
 | 
				
			||||||
 | 
						endtagreading,
 | 
				
			||||||
 | 
						contentreading /* printing */
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void
 | 
				
			||||||
 | 
					usage(char *name){
 | 
				
			||||||
 | 
						fprintf(stdout, "Usage: %s [tag...]\n", name);
 | 
				
			||||||
 | 
						return;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char *argv[]){
 | 
				
			||||||
 | 
						if(argc < 2){
 | 
				
			||||||
 | 
							usage(argv[0]);
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						bool enable = 0;
 | 
				
			||||||
 | 
						char c;
 | 
				
			||||||
 | 
						int linenumber = 0;
 | 
				
			||||||
 | 
						enum state s = init;
 | 
				
			||||||
 | 
						FILE *input = stdin;
 | 
				
			||||||
 | 
						FILE *output = stdout;
 | 
				
			||||||
 | 
						int level = 1; /* 1-indexed because args start at 1 */
 | 
				
			||||||
 | 
						size_t p = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						while(c = getc(input) != EOF){
 | 
				
			||||||
 | 
							if(c == LF){
 | 
				
			||||||
 | 
								++linenumber;
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							switch(s){
 | 
				
			||||||
 | 
							case init:
 | 
				
			||||||
 | 
								if(c == TAGSTART)
 | 
				
			||||||
 | 
									s = starttagreading;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case starttagreading:
 | 
				
			||||||
 | 
								if(c == ETAG)
 | 
				
			||||||
 | 
									s = endtagreading;
 | 
				
			||||||
 | 
								else if(!isblank(c))
 | 
				
			||||||
 | 
									s = tagreading;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case tagreading:
 | 
				
			||||||
 | 
								if(c == ETAG)
 | 
				
			||||||
 | 
									s = eetagreading;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							/* case eetagreading: */
 | 
				
			||||||
 | 
							case endtagreading:
 | 
				
			||||||
 | 
								if(c == ETAG)
 | 
				
			||||||
 | 
									fprintf(stderr, "%s:%d: Stray \'%c\' in an end tag?\n", argv[0], linenumber, ETAG);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							case contentreading:
 | 
				
			||||||
 | 
								if(enable)
 | 
				
			||||||
 | 
									putc(c, output);
 | 
				
			||||||
 | 
								else if(c == TAGSTART)
 | 
				
			||||||
 | 
								s = starttagreading;
 | 
				
			||||||
 | 
								else if(c == TAGEND)
 | 
				
			||||||
 | 
									fprintf(stderr, "%s:%d: Possible state error or XML syntax error; \'%c\' in mode contentreading\n", argv[0], linenumber, TAGEND);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user