pscat(1)
This commit is contained in:
		
							parent
							
								
									1ba5208e58
								
							
						
					
					
						commit
						9a95b64618
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,6 +4,7 @@ bin/id | ||||
| bin/lowercase | ||||
| bin/nonzero | ||||
| bin/nutshell | ||||
| bin/pscat | ||||
| bin/rldecode | ||||
| bin/rlencode | ||||
| bin/roll | ||||
|  | ||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							| @ -25,6 +25,7 @@ cleanprograms: | ||||
| 	$(RM) bin/mm | ||||
| 	$(RM) bin/multiply | ||||
| 	$(RM) bin/nonzero | ||||
| 	$(RM) bin/pscat | ||||
| 	$(RM) bin/simexec | ||||
| 	$(RM) bin/sleep | ||||
| 	$(RM) bin/streq | ||||
| @ -90,6 +91,12 @@ nutshell.o: libio usefulmacros src/nutshell.c src/nutshell.h src/nutshell_builti | ||||
| nutshell: libio nutshell.o | ||||
| 	$(CC) $(CFLAGS) -o bin/nutshell build/libio.o build/nutshell.o | ||||
| 
 | ||||
| pscat.o: libio src/pscat.c | ||||
| 	$(CC) $(CFLAGS) -c -o build/pscat.o src/pscat.c | ||||
| 
 | ||||
| pscat: libio pscat.o | ||||
| 	$(CC) $(CFLAGS) -o bin/pscat build/libio.o build/pscat.o | ||||
| 
 | ||||
| roll.o: lib/libio.h src/roll.c sysexits | ||||
| 	$(CC) $(CFLAGS) -c -o build/roll.o src/roll.c | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										33
									
								
								man/pscat.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								man/pscat.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | ||||
| .TH PSCAT 1 | ||||
| 
 | ||||
| .SH NAME | ||||
| 
 | ||||
| pscat \- concatenate the output of processes | ||||
| 
 | ||||
| .SH SYNOPSIS | ||||
| 
 | ||||
| pscat | ||||
| "["  | ||||
| .RB [ utility | ||||
| .RB [ argument... ]] | ||||
| "]" ... | ||||
| 
 | ||||
| .SH DESCRIPTION | ||||
| 
 | ||||
| Pscat executes multiple commands, one after the other. | ||||
| This allows multiple processes to be piped as one to another program. | ||||
| 
 | ||||
| .SH DIAGNOSTICS | ||||
| 
 | ||||
| Pscat will print an error message and exit with the appropriate status from sysexits(3) if executed improperly. | ||||
| Pscat will exit with the sum of the child processes' exit statuses if run correctly. | ||||
| 
 | ||||
| .SH BUGS | ||||
| 
 | ||||
| Pscat's exit status isn't useful when run correctly; there's no way to tell which process failed if one did. | ||||
| This issue of ergonomics isn't obviously mendable as processes' standard outputs and standard errors are meant to both be conveyed. | ||||
| If either could be ignored the individual exit statuses could simply be printed. | ||||
| 
 | ||||
| .SH COPYRIGHT | ||||
| 
 | ||||
| Public domain. | ||||
							
								
								
									
										88
									
								
								src/pscat.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/pscat.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| #include <ascii.h> | ||||
| #include <sysexits.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
| #include "libio.h" | ||||
| 
 | ||||
| static char *program_name = "pscat"; | ||||
| 
 | ||||
| /* Originally designed to use parentheses but changed to brackets to escape the
 | ||||
|  * hassle of escaping them from the Bourne shell. */ | ||||
| #define L_PAREN ASCII_LEFT_SQUARE_BRACKET | ||||
| #define R_PAREN ASCII_RIGHT_SQUARE_BRACKET | ||||
| 
 | ||||
| /* Test string containing { c, '\0' } without iteration.
 | ||||
|  * Theoretically saves a little bit of time compared to strcmp(3). */ | ||||
| int | ||||
| scmpflat(char *s, int c){ | ||||
| 	return | ||||
| 		s[0] != '\0' | ||||
| 		&& s[1] == '\0' | ||||
| 		&& s[0] == c | ||||
| 	; | ||||
| } | ||||
| 
 | ||||
| /* Verifies arguments to pscat are sensible. */ | ||||
| int | ||||
| check_arg(char **argv){ | ||||
| 	enum { | ||||
| 		UNINITIALIZED = 0, | ||||
| 		INLPAREN = 1, | ||||
| 		NORMAL = 2 | ||||
| 	} s; | ||||
| 	int terms; | ||||
| 
 | ||||
| 	for(s = UNINITIALIZED, terms = 0; *argv != NULL; ++argv) | ||||
| 		switch(s){ | ||||
| 		case UNINITIALIZED: case NORMAL: | ||||
| 			if(scmpflat(*argv, L_PAREN)) | ||||
| 				s = INLPAREN; | ||||
| 			else | ||||
| 				return 0; /* syntax error */ | ||||
| 			break; | ||||
| 		case INLPAREN: | ||||
| 			if(scmpflat(*argv, R_PAREN)) | ||||
| 				{ ++s; ++terms; } | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 	return terms; | ||||
| } | ||||
| 
 | ||||
| int main(int argc, char *argv[]){ | ||||
| 	char *argv0; | ||||
| 	char **psstart; | ||||
| 	int child; | ||||
| 	int i; | ||||
| 	int retval; | ||||
| 	int terms; | ||||
| 
 | ||||
| 	argv0 = argv[0] == NULL ? program_name : argv[0]; | ||||
| 	retval = 0; | ||||
| 
 | ||||
| 	if((terms = check_arg(++argv)) == 0){ | ||||
| 		write(2, "Usage: ", 7); | ||||
| 		fdprint(2, argv0); | ||||
| 		write(2, " \"[\" [utility [argument...]] \"]\" ...\n", 37); | ||||
| 		return EX_USAGE; | ||||
| 	} | ||||
| 
 | ||||
| 	/* loop starts with *argv -> the next L_PAREN */ | ||||
| 	for(i = 0; i < terms; ++i){ | ||||
| 		psstart = ++argv; | ||||
| 		while(!scmpflat(*++argv, R_PAREN)); | ||||
| 		/* *argv -> the corresponding R_PAREN. turn it into NULL to
 | ||||
| 		 * terminate the argument list to send to execvp(3) */ | ||||
| 		*argv = NULL; | ||||
| 		if(fork() == 0){ | ||||
| 			execvp(psstart[0], psstart); | ||||
| 		}else | ||||
| 			wait(&child); | ||||
| 		/* interpret status information from wait(2) */ | ||||
| 		if(WIFEXITED(child)) | ||||
| 			retval += WEXITSTATUS(child); | ||||
| 		++argv; | ||||
| 	} | ||||
| 
 | ||||
| 	return retval; | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user