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