initial commit
This commit is contained in:
		
							
								
								
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | MIT/X Consortium License | ||||||
|  |  | ||||||
|  | © 2011 Connor Lane Smith <cls@lubutu.com> | ||||||
|  |  | ||||||
|  | Permission is hereby granted, free of charge, to any person obtaining a | ||||||
|  | copy of this software and associated documentation files (the "Software"), | ||||||
|  | to deal in the Software without restriction, including without limitation | ||||||
|  | the rights to use, copy, modify, merge, publish, distribute, sublicense, | ||||||
|  | and/or sell copies of the Software, and to permit persons to whom the | ||||||
|  | Software is furnished to do so, subject to the following conditions: | ||||||
|  |  | ||||||
|  | The above copyright notice and this permission notice shall be included in | ||||||
|  | all copies or substantial portions of the Software. | ||||||
|  |  | ||||||
|  | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||||
|  | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||||
|  | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL | ||||||
|  | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||||
|  | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||||||
|  | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||||||
|  | DEALINGS IN THE SOFTWARE. | ||||||
							
								
								
									
										31
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | include config.mk | ||||||
|  |  | ||||||
|  | SRC = basename.c cat.c echo.c false.c grep.c tee.c touch.c true.c wc.c | ||||||
|  | OBJ = $(SRC:.c=.o) util.o | ||||||
|  | BIN = $(SRC:.c=) | ||||||
|  | MAN = $(SRC:.c=.1) | ||||||
|  |  | ||||||
|  | all: $(BIN) | ||||||
|  |  | ||||||
|  | $(OBJ): util.h | ||||||
|  | $(BIN): util.o | ||||||
|  |  | ||||||
|  | .o: | ||||||
|  | 	@echo CC -o $@ | ||||||
|  | 	@$(CC) -o $@ $< util.o $(LDFLAGS) | ||||||
|  |  | ||||||
|  | .c.o: | ||||||
|  | 	@echo CC -c $< | ||||||
|  | 	@$(CC) -c $< $(CFLAGS) | ||||||
|  |  | ||||||
|  | dist: clean | ||||||
|  | 	@echo creating dist tarball | ||||||
|  | 	@mkdir -p sbase-$(VERSION) | ||||||
|  | 	@cp LICENSE Makefile config.mk $(SRC) $(MAN) util.c util.h sbase-$(VERSION) | ||||||
|  | 	@tar -cf sbase-$(VERSION).tar sbase-$(VERSION) | ||||||
|  | 	@gzip sbase-$(VERSION).tar | ||||||
|  | 	@rm -rf sbase-$(VERSION) | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	@echo cleaning | ||||||
|  | 	@rm -f $(BIN) $(OBJ) | ||||||
							
								
								
									
										14
									
								
								basename.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								basename.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | .TH BASENAME 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | basename \- strip directory from filename | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B basename | ||||||
|  | .I string | ||||||
|  | .RI [ suffix ] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B basename | ||||||
|  | prints to stdout the | ||||||
|  | .I string | ||||||
|  | with any leading directory components, and the | ||||||
|  | .IR suffix , | ||||||
|  | removed. | ||||||
							
								
								
									
										30
									
								
								basename.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								basename.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	char *str = argv[1]; | ||||||
|  | 	size_t n, i = 0; | ||||||
|  |  | ||||||
|  | 	if(argc < 2) | ||||||
|  | 		eprintf("usage: %s string [suffix]\n", argv[0]); | ||||||
|  | 	if(str[0] != '\0') | ||||||
|  | 		for(i = strlen(str)-1; i > 0 && str[i] == '/'; i--) | ||||||
|  | 			str[i] = '\0'; | ||||||
|  | 	if(i == 0 || !(str = strrchr(argv[1], '/'))) | ||||||
|  | 		str = argv[1]; | ||||||
|  | 	else | ||||||
|  | 		str++; | ||||||
|  |  | ||||||
|  | 	if(argc > 2 && strlen(str) > strlen(argv[2])) { | ||||||
|  | 		n = strlen(str) - strlen(argv[2]); | ||||||
|  | 		if(!strcmp(&str[n], argv[2])) | ||||||
|  | 			str[n] = '\0'; | ||||||
|  | 	} | ||||||
|  | 	puts(str); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								cat.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								cat.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | .TH CAT 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | cat \- concatenate files | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B cat | ||||||
|  | .RI [ files ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B cat | ||||||
|  | reads each file in sequence and writes it to stdout.  If no file is given, cat | ||||||
|  | reads from stdin. | ||||||
							
								
								
									
										36
									
								
								cat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								cat.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | static void cat(FILE *, const char *); | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	FILE *fp; | ||||||
|  |  | ||||||
|  | 	if(argc == 1) | ||||||
|  | 		cat(stdin, "<stdin>"); | ||||||
|  | 	else for(i = 1; i < argc; i++) { | ||||||
|  | 		if(!(fp = fopen(argv[i], "r"))) | ||||||
|  | 			eprintf("fopen %s:", argv[i]); | ||||||
|  | 		cat(fp, argv[i]); | ||||||
|  | 		fclose(fp); | ||||||
|  | 	} | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | cat(FILE *fp, const char *str) | ||||||
|  | { | ||||||
|  | 	char buf[BUFSIZ]; | ||||||
|  | 	size_t n; | ||||||
|  |  | ||||||
|  | 	while((n = fread(buf, 1, sizeof buf, fp)) > 0) | ||||||
|  | 		if(fwrite(buf, 1, n, stdout) != n) | ||||||
|  | 			eprintf("<stdout>: write error:"); | ||||||
|  | 	if(ferror(fp)) | ||||||
|  | 		eprintf("%s: read error:", str); | ||||||
|  | } | ||||||
							
								
								
									
										9
									
								
								config.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								config.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | # sbase version | ||||||
|  | VERSION = 0.0 | ||||||
|  |  | ||||||
|  | CC = cc | ||||||
|  | #CC = musl-gcc | ||||||
|  |  | ||||||
|  | CPPFLAGS = -D_BSD_SOURCE | ||||||
|  | CFLAGS   = -Os -ansi -Wall -pedantic $(CPPFLAGS) | ||||||
|  | LDFLAGS  = -s -static | ||||||
							
								
								
									
										14
									
								
								echo.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								echo.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | .TH ECHO 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | echo \- print arguments | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B echo | ||||||
|  | .RB [ \-n ] | ||||||
|  | .RI [ string ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B echo | ||||||
|  | prints its arguments to stdout, separated by spaces and terminated by a newline. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-n | ||||||
|  | Do not print terminating newline. | ||||||
							
								
								
									
										23
									
								
								echo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								echo.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	bool nflag = false; | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	if(argc > 1 && !strcmp(argv[1], "-n")) | ||||||
|  | 		nflag = true; | ||||||
|  | 	for(i = nflag ? 2 : 1; i < argc; i++) { | ||||||
|  | 		fputs(argv[i], stdout); | ||||||
|  | 		if(i+1 < argc) | ||||||
|  | 			fputc(' ', stdout); | ||||||
|  | 	} | ||||||
|  | 	if(!nflag) | ||||||
|  | 		fputc('\n', stdout); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								false.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								false.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | .TH FALSE 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | false \- return failure | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B false | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B false | ||||||
|  | returns with a status code indicating failure. | ||||||
							
								
								
									
										8
									
								
								false.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								false.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(void) | ||||||
|  | { | ||||||
|  | 	return EXIT_FAILURE; | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								grep.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								grep.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | .TH GREP 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | grep \- search files for a pattern | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B grep | ||||||
|  | .RB [ \-c ] | ||||||
|  | .RB [ \-i ] | ||||||
|  | .RB [ \-l ] | ||||||
|  | .RB [ \-n ] | ||||||
|  | .RB [ \-q ] | ||||||
|  | .RB [ \-v ] | ||||||
|  | .I pattern | ||||||
|  | .RI [ file ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B grep | ||||||
|  | searches the input files for lines that match the pattern, a regular expression as defined in | ||||||
|  | .BR regex (7). | ||||||
|  | By default each matching line is printed to stdout.  If no file is given, grep | ||||||
|  | reads from stdin. | ||||||
|  | .P | ||||||
|  | The status code is 0 if any lines match, and 1 if not.  If an error occurred the | ||||||
|  | status code is 2. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-c | ||||||
|  | prints only a count of matching lines. | ||||||
|  | .TP | ||||||
|  | .B \-i | ||||||
|  | matches lines case insensitively. | ||||||
|  | .TP | ||||||
|  | .B \-l | ||||||
|  | prints only the names of files with matching lines. | ||||||
|  | .TP | ||||||
|  | .B \-n | ||||||
|  | prefixes each matching line with its line number in the input. | ||||||
|  | .TP | ||||||
|  | .B \-q | ||||||
|  | prints nothing, only returns status. | ||||||
|  | .TP | ||||||
|  | .B \-v | ||||||
|  | selects lines which do | ||||||
|  | .B not | ||||||
|  | match the pattern. | ||||||
							
								
								
									
										97
									
								
								grep.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								grep.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <regex.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  |  | ||||||
|  | static void grep(FILE *, const char *, regex_t *); | ||||||
|  |  | ||||||
|  | static bool iflag = false; | ||||||
|  | static bool vflag = false; | ||||||
|  | static bool many; | ||||||
|  | static bool match = false; | ||||||
|  | static char mode = 0; | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	int i, flags = 0; | ||||||
|  | 	regex_t preg; | ||||||
|  | 	FILE *fp; | ||||||
|  |  | ||||||
|  | 	for(i = 1; i < argc; i++) | ||||||
|  | 		if(!strcmp(argv[i], "-c")) | ||||||
|  | 			mode = 'c'; | ||||||
|  | 		else if(!strcmp(argv[i], "-i")) | ||||||
|  | 			iflag = true; | ||||||
|  | 		else if(!strcmp(argv[i], "-l")) | ||||||
|  | 			mode = 'l'; | ||||||
|  | 		else if(!strcmp(argv[i], "-n")) | ||||||
|  | 			mode = 'n'; | ||||||
|  | 		else if(!strcmp(argv[i], "-q")) | ||||||
|  | 			mode = 'q'; | ||||||
|  | 		else if(!strcmp(argv[i], "-v")) | ||||||
|  | 			vflag = true; | ||||||
|  | 		else | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 	if(i == argc) { | ||||||
|  | 		fprintf(stderr, "usage: %s [-c] [-i] [-l] [-n] [-v] pattern [files...]\n", argv[0]); | ||||||
|  | 		exit(2); | ||||||
|  | 	} | ||||||
|  | 	if(mode == 'c') | ||||||
|  | 		flags |= REG_NOSUB; | ||||||
|  | 	if(iflag) | ||||||
|  | 		flags |= REG_ICASE; | ||||||
|  | 	regcomp(&preg, argv[i++], flags); | ||||||
|  |  | ||||||
|  | 	many = (argc > i+1); | ||||||
|  | 	if(i == argc) | ||||||
|  | 		grep(stdin, "<stdin>", &preg); | ||||||
|  | 	else for(; i < argc; i++) { | ||||||
|  | 		if(!(fp = fopen(argv[i], "r"))) { | ||||||
|  | 			fprintf(stderr, "fopen %s: ", argv[i]); | ||||||
|  | 			perror(NULL); | ||||||
|  | 			exit(2); | ||||||
|  | 		} | ||||||
|  | 		grep(fp, argv[i], &preg); | ||||||
|  | 		fclose(fp); | ||||||
|  | 	} | ||||||
|  | 	return match ? 0 : 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | grep(FILE *fp, const char *str, regex_t *preg) | ||||||
|  | { | ||||||
|  | 	char buf[BUFSIZ]; | ||||||
|  | 	int n, c = 0; | ||||||
|  |  | ||||||
|  | 	for(n = 1; fgets(buf, sizeof buf, fp); n++) { | ||||||
|  | 		if(regexec(preg, buf, 0, NULL, 0) ^ vflag) | ||||||
|  | 			continue; | ||||||
|  | 		if(mode == 'c') | ||||||
|  | 			c++; | ||||||
|  | 		else if(mode == 'l') { | ||||||
|  | 			puts(str); | ||||||
|  | 			break; | ||||||
|  | 		} | ||||||
|  | 		else if(mode == 'q') | ||||||
|  | 			exit(0); | ||||||
|  | 		else { | ||||||
|  | 			if(many) | ||||||
|  | 				printf("%s:", str); | ||||||
|  | 			if(mode == 'n') | ||||||
|  | 				printf("%d:", n); | ||||||
|  | 			fputs(buf, stdout); | ||||||
|  | 		} | ||||||
|  | 		match = true; | ||||||
|  | 	} | ||||||
|  | 	if(mode == 'c') | ||||||
|  | 		printf("%d\n", c); | ||||||
|  | 	if(ferror(fp)) { | ||||||
|  | 		fprintf(stderr, "%s: read error: ", str); | ||||||
|  | 		perror(NULL); | ||||||
|  | 		exit(2); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								tee.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								tee.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | .TH TEE 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | tee \- duplicate stdin | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B tee | ||||||
|  | .RB [ \-a ] | ||||||
|  | .RI [ file ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B tee | ||||||
|  | writes from stdin to stdout, making copies in each file. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-a | ||||||
|  | append to each file rather than overwriting. | ||||||
							
								
								
									
										36
									
								
								tee.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								tee.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	bool aflag = false; | ||||||
|  | 	char buf[BUFSIZ]; | ||||||
|  | 	int i, nfps = 1; | ||||||
|  | 	size_t n; | ||||||
|  | 	FILE **fps; | ||||||
|  |  | ||||||
|  | 	if(argc > 1 && !strcmp(argv[1], "-a")) | ||||||
|  | 		aflag = true; | ||||||
|  | 	if(!(fps = malloc(sizeof *fps))) | ||||||
|  | 		eprintf("malloc:"); | ||||||
|  | 	fps[nfps-1] = stdout; | ||||||
|  |  | ||||||
|  | 	for(i = aflag ? 2 : 1; i < argc; i++) { | ||||||
|  | 		if(!(fps = realloc(fps, ++nfps * sizeof *fps))) | ||||||
|  | 			eprintf("realloc:"); | ||||||
|  | 		if(!(fps[nfps-1] = fopen(argv[i], aflag ? "a" : "w"))) | ||||||
|  | 			eprintf("fopen %s:", argv[i]); | ||||||
|  | 	} | ||||||
|  | 	while((n = fread(buf, 1, sizeof buf, stdin)) > 0) | ||||||
|  | 		for(i = 0; i < nfps; i++) | ||||||
|  | 			if(fwrite(buf, 1, n, fps[i]) != n) | ||||||
|  | 				eprintf("%s: write error:", buf); | ||||||
|  | 	if(ferror(stdin)) | ||||||
|  | 		eprintf("<stdin>: read error:"); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								touch.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								touch.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | .TH TOUCH 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | touch \- set files' modification time | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B touch | ||||||
|  | .RB [ \-c ] | ||||||
|  | .RB [ \-t | ||||||
|  | .IR time ] | ||||||
|  | .RI [ file ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B touch | ||||||
|  | sets the files' modification time to the current time.  If a file does not exist | ||||||
|  | it is created. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-c | ||||||
|  | do not create files if they do not exist. | ||||||
|  | .TP | ||||||
|  | .BI \-t " time" | ||||||
|  | sets the files' modification time to | ||||||
|  | .IR time , | ||||||
|  | given as the number of seconds since the Unix epoch. | ||||||
							
								
								
									
										58
									
								
								touch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								touch.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <errno.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <time.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <utime.h> | ||||||
|  | #include <sys/stat.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | static void touch(const char *); | ||||||
|  |  | ||||||
|  | static bool cflag = false; | ||||||
|  | static time_t t; | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  |  | ||||||
|  | 	t = time(NULL); | ||||||
|  |  | ||||||
|  | 	for(i = 1; i < argc; i++) | ||||||
|  | 		if(!strcmp(argv[i], "-c")) | ||||||
|  | 			cflag = true; | ||||||
|  | 		else if(!strcmp(argv[i], "-t") && i+1 < argc) | ||||||
|  | 			t = strtol(argv[++i], NULL, 0); | ||||||
|  | 		else | ||||||
|  | 			break; | ||||||
|  |  | ||||||
|  | 	for(; i < argc; i++) | ||||||
|  | 		touch(argv[i]); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | touch(const char *str) | ||||||
|  | { | ||||||
|  | 	int fd; | ||||||
|  | 	struct stat st; | ||||||
|  | 	struct utimbuf ut; | ||||||
|  |  | ||||||
|  | 	if(stat(str, &st) < 0) { | ||||||
|  | 		if(errno != ENOENT) | ||||||
|  | 			eprintf("stat %s:", str); | ||||||
|  | 		if(cflag) | ||||||
|  | 			return; | ||||||
|  | 		if((fd = creat(str, O_RDONLY|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) < 0) | ||||||
|  | 			eprintf("creat %s:", str); | ||||||
|  | 		close(fd); | ||||||
|  | 	} | ||||||
|  | 	ut.actime = st.st_atime; | ||||||
|  | 	ut.modtime = t; | ||||||
|  | 	if(utime(str, &ut) < 0) | ||||||
|  | 		eprintf("utime %s:", str); | ||||||
|  | } | ||||||
							
								
								
									
										8
									
								
								true.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								true.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | .TH TRUE 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | true \- return success | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B true | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B true | ||||||
|  | returns with a status code indicating success. | ||||||
							
								
								
									
										8
									
								
								true.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								true.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(void) | ||||||
|  | { | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
							
								
								
									
										22
									
								
								util.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								util.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <stdarg.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | void | ||||||
|  | eprintf(const char *fmt, ...) | ||||||
|  | { | ||||||
|  | 	va_list ap; | ||||||
|  |  | ||||||
|  | 	va_start(ap, fmt); | ||||||
|  | 	vfprintf(stderr, fmt, ap); | ||||||
|  | 	va_end(ap); | ||||||
|  |  | ||||||
|  | 	if(fmt[0] && fmt[strlen(fmt)-1] == ':') { | ||||||
|  | 		fputc(' ', stderr); | ||||||
|  | 		perror(NULL); | ||||||
|  | 	} | ||||||
|  | 	exit(EXIT_FAILURE); | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								util.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								util.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  |  | ||||||
|  | void eprintf(const char *, ...); | ||||||
							
								
								
									
										28
									
								
								wc.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								wc.1
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | .TH WC 1 sbase\-VERSION | ||||||
|  | .SH NAME | ||||||
|  | wc \- word count | ||||||
|  | .SH SYNOPSIS | ||||||
|  | .B wc | ||||||
|  | .RB [ \-c ] | ||||||
|  | .RB [ \-l ] | ||||||
|  | .RB [ \-m ] | ||||||
|  | .RB [ \-w ] | ||||||
|  | .RI [ file ...] | ||||||
|  | .SH DESCRIPTION | ||||||
|  | .B wc | ||||||
|  | prints the number of lines, words, and bytes in each file.  If any flags are | ||||||
|  | given, wc will print only the requested information.  If no files are given, wc | ||||||
|  | reads stdin. | ||||||
|  | .SH OPTIONS | ||||||
|  | .TP | ||||||
|  | .B \-c | ||||||
|  | print the number of bytes. | ||||||
|  | .TP | ||||||
|  | .B \-l | ||||||
|  | print the number of lines. | ||||||
|  | .TP | ||||||
|  | .B \-m | ||||||
|  | print the number of characters, not bytes. | ||||||
|  | .TP | ||||||
|  | .B \-w | ||||||
|  | print the number of words. | ||||||
							
								
								
									
										89
									
								
								wc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								wc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,89 @@ | |||||||
|  | /* See LICENSE file for copyright and license details. */ | ||||||
|  | #include <ctype.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include "util.h" | ||||||
|  |  | ||||||
|  | static void output(const char *, long, long, long); | ||||||
|  | static void wc(FILE *, const char *); | ||||||
|  |  | ||||||
|  | static bool lflag = false; | ||||||
|  | static bool wflag = false; | ||||||
|  | static char cmode = 0; | ||||||
|  | static long tc = 0, tl = 0, tw = 0; | ||||||
|  |  | ||||||
|  | int | ||||||
|  | main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  | 	bool many; | ||||||
|  | 	int i; | ||||||
|  | 	FILE *fp; | ||||||
|  |  | ||||||
|  | 	for(i = 1; i < argc; i++) | ||||||
|  | 		if(!strcmp(argv[i], "-c")) | ||||||
|  | 			cmode = 'c'; | ||||||
|  | 		else if(!strcmp(argv[i], "-l")) | ||||||
|  | 			lflag = true; | ||||||
|  | 		else if(!strcmp(argv[i], "-m")) | ||||||
|  | 			cmode = 'm'; | ||||||
|  | 		else if(!strcmp(argv[i], "-w")) | ||||||
|  | 			wflag = true; | ||||||
|  | 		else | ||||||
|  | 			break; | ||||||
|  | 	many = (argc > i+1); | ||||||
|  |  | ||||||
|  | 	if(i == argc) | ||||||
|  | 		wc(stdin, NULL); | ||||||
|  | 	else for(; i < argc; i++) { | ||||||
|  | 		if(!(fp = fopen(argv[i], "r"))) | ||||||
|  | 			eprintf("fopen %s:", argv[i]); | ||||||
|  | 		wc(fp, argv[i]); | ||||||
|  | 		fclose(fp); | ||||||
|  | 	} | ||||||
|  | 	if(many) | ||||||
|  | 		output("total", tc, tl, tw); | ||||||
|  | 	return EXIT_SUCCESS; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | output(const char *str, long nc, long nl, long nw) | ||||||
|  | { | ||||||
|  | 	bool noflags = !cmode && !lflag && !wflag; | ||||||
|  |  | ||||||
|  | 	if(lflag || noflags) | ||||||
|  | 		printf(" %5ld", nl); | ||||||
|  | 	if(wflag || noflags) | ||||||
|  | 		printf(" %5ld", nw); | ||||||
|  | 	if(cmode || noflags) | ||||||
|  | 		printf(" %5ld", nc); | ||||||
|  | 	if(str) | ||||||
|  | 		printf(" %s", str); | ||||||
|  | 	fputc('\n', stdout); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void | ||||||
|  | wc(FILE *fp, const char *str) | ||||||
|  | { | ||||||
|  | 	bool word = false; | ||||||
|  | 	char c; | ||||||
|  | 	long nc = 0, nl = 0, nw = 0; | ||||||
|  |  | ||||||
|  | 	while((c = fgetc(fp)) != EOF) { | ||||||
|  | 		if(cmode != 'm' || (c & 0xc0) != 0x80) | ||||||
|  | 			nc++; | ||||||
|  | 		if(c == '\n') | ||||||
|  | 			nl++; | ||||||
|  | 		if(!isspace(c)) | ||||||
|  | 			word = true; | ||||||
|  | 		else if(word) { | ||||||
|  | 			word = false; | ||||||
|  | 			nw++; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	tc += nc; | ||||||
|  | 	tl += nl; | ||||||
|  | 	tw += nw; | ||||||
|  | 	output(str, nc, nl, nw); | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user