| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | /* See LICENSE file for copyright and license details. */ | 
					
						
							| 
									
										
										
										
											2015-02-20 12:21:46 +00:00
										 |  |  | #include <limits.h>
 | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | #include <stdint.h>
 | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | #include <stdio.h>
 | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							| 
									
										
										
										
											2014-11-13 18:29:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | #include "text.h"
 | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | #include "utf.h"
 | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | #include "util.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | static size_t   startnum = 1; | 
					
						
							|  |  |  | static size_t   incr = 1; | 
					
						
							|  |  |  | static size_t   blines = 1; | 
					
						
							|  |  |  | static size_t   delimlen = 2; | 
					
						
							|  |  |  | static int      width = 6; | 
					
						
							|  |  |  | static int      pflag = 0; | 
					
						
							|  |  |  | static char     type[] = { 'n', 't', 'n' }; /* footer, body, header */ | 
					
						
							|  |  |  | static char    *delim = "\\:"; | 
					
						
							|  |  |  | static char     format[8] = "%*ld%s"; | 
					
						
							|  |  |  | static char    *sep = "\t"; | 
					
						
							|  |  |  | static regex_t  preg[3]; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | static int | 
					
						
							|  |  |  | getsection(char *buf, int *section) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	int sectionchanged = 0, newsection = *section; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | 	for (; !strncmp(buf, delim, delimlen); buf += delimlen) { | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		if (!sectionchanged) { | 
					
						
							|  |  |  | 			sectionchanged = 1; | 
					
						
							|  |  |  | 			newsection = 0; | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 			newsection = (newsection + 1) % 3; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	if (!buf[0] || buf[0] == '\n') | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		*section = newsection; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		sectionchanged = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sectionchanged; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-07 13:33:39 +01:00
										 |  |  | static void | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | nl(const char *fname, FILE *fp) | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2015-03-27 17:03:44 +01:00
										 |  |  | 	size_t number = startnum, size = 0, bl = 1; | 
					
						
							|  |  |  | 	int donumber, oldsection, section = 1; | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	char *buf = NULL; | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-27 14:49:48 +01:00
										 |  |  | 	while (getline(&buf, &size, fp) > 0) { | 
					
						
							| 
									
										
										
										
											2015-03-10 12:49:56 +01:00
										 |  |  | 		donumber = 0; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		oldsection = section; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (getsection(buf, §ion)) { | 
					
						
							|  |  |  | 			if ((section >= oldsection) && !pflag) | 
					
						
							|  |  |  | 				number = startnum; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-10 12:49:56 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		switch (type[section]) { | 
					
						
							|  |  |  | 		case 't': | 
					
						
							|  |  |  | 			if (buf[0] != '\n') | 
					
						
							|  |  |  | 				donumber = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'p': | 
					
						
							| 
									
										
										
										
											2015-03-22 19:23:57 +00:00
										 |  |  | 			if (!regexec(preg + section, buf, 0, NULL, 0)) | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 				donumber = 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 'a': | 
					
						
							| 
									
										
										
										
											2015-03-10 12:49:56 +01:00
										 |  |  | 			if (buf[0] == '\n' && bl < blines) { | 
					
						
							|  |  |  | 				++bl; | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				donumber = 1; | 
					
						
							|  |  |  | 				bl = 1; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (donumber) { | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 			printf(format, width, number, sep); | 
					
						
							|  |  |  | 			number += incr; | 
					
						
							| 
									
										
										
										
											2015-02-20 12:05:54 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		fputs(buf, stdout); | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	free(buf); | 
					
						
							|  |  |  | 	if (ferror(fp)) | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		eprintf("getline %s:", fname); | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | static void | 
					
						
							|  |  |  | usage(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	eprintf("usage: %s [-p] [-b type] [-d delim] [-f type]\n" | 
					
						
							|  |  |  | 	        "       [-h type] [-i num] [-l num] [-n format]\n" | 
					
						
							| 
									
										
										
										
											2015-12-21 18:36:28 +01:00
										 |  |  | 	        "       [-s sep] [-v num] [-w num] [file]\n", argv0); | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | static char | 
					
						
							|  |  |  | getlinetype(char *type, regex_t *preg) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (type[0] == 'p') | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		eregcomp(preg, type + 1, REG_NOSUB); | 
					
						
							|  |  |  | 	else if (!type[0] || !strchr("ant", type[0])) | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		usage(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return type[0]; | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | int | 
					
						
							|  |  |  | main(int argc, char *argv[]) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-04-04 23:09:06 +02:00
										 |  |  | 	FILE *fp = NULL; | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | 	size_t l, s; | 
					
						
							| 
									
										
										
										
											2015-05-25 01:33:19 +02:00
										 |  |  | 	int ret = 0; | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	char *d, *formattype, *formatblit; | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 	ARGBEGIN { | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 	case 'd': | 
					
						
							|  |  |  | 		d = EARGF(usage()); | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | 		l = utflen(d); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		switch (l) { | 
					
						
							|  |  |  | 		case 0: | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			s = strlen(d); | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 			delim = emalloc(s + 1 + 1); | 
					
						
							|  |  |  | 			estrlcpy(delim, d, s + 1 + 1); | 
					
						
							|  |  |  | 			estrlcat(delim, ":", s + 1 + 1); | 
					
						
							| 
									
										
										
										
											2015-03-20 18:09:23 +01:00
										 |  |  | 			delimlen = s + 1; | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		default: | 
					
						
							|  |  |  | 			delim = d; | 
					
						
							|  |  |  | 			delimlen = strlen(delim); | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 'f': | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		type[0] = getlinetype(EARGF(usage()), preg); | 
					
						
							|  |  |  | 		break; | 
					
						
							|  |  |  | 	case 'b': | 
					
						
							|  |  |  | 		type[1] = getlinetype(EARGF(usage()), preg + 1); | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case 'h': | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		type[2] = getlinetype(EARGF(usage()), preg + 2); | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 	case 'i': | 
					
						
							| 
									
										
										
										
											2015-02-01 01:24:03 +01:00
										 |  |  | 		incr = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2015-03-10 12:49:56 +01:00
										 |  |  | 	case 'l': | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		blines = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); | 
					
						
							| 
									
										
										
										
											2015-03-10 12:49:56 +01:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2015-02-20 14:12:03 +00:00
										 |  |  | 	case 'n': | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 		formattype = EARGF(usage()); | 
					
						
							|  |  |  | 		estrlcpy(format, "%", sizeof(format)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (!strcmp(formattype, "ln")) { | 
					
						
							|  |  |  | 			formatblit = "-"; | 
					
						
							|  |  |  | 		} else if (!strcmp(formattype, "rn")) { | 
					
						
							|  |  |  | 			formatblit = ""; | 
					
						
							|  |  |  | 		} else if (!strcmp(formattype, "rz")) { | 
					
						
							|  |  |  | 			formatblit = "0"; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			eprintf("%s: bad format\n", formattype); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		estrlcat(format, formatblit, sizeof(format)); | 
					
						
							|  |  |  | 		estrlcat(format, "*ld%s", sizeof(format)); | 
					
						
							| 
									
										
										
										
											2015-02-20 14:12:03 +00:00
										 |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2015-03-18 17:58:09 +01:00
										 |  |  | 	case 'p': | 
					
						
							|  |  |  | 		pflag = 1; | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 	case 's': | 
					
						
							|  |  |  | 		sep = EARGF(usage()); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2015-02-20 12:05:54 +00:00
										 |  |  | 	case 'v': | 
					
						
							|  |  |  | 		startnum = estrtonum(EARGF(usage()), 0, MIN(LLONG_MAX, SIZE_MAX)); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2015-02-20 12:15:43 +00:00
										 |  |  | 	case 'w': | 
					
						
							|  |  |  | 		width = estrtonum(EARGF(usage()), 1, INT_MAX); | 
					
						
							|  |  |  | 		break; | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 	default: | 
					
						
							|  |  |  | 		usage(); | 
					
						
							| 
									
										
										
										
											2015-11-01 10:16:49 +00:00
										 |  |  | 	} ARGEND | 
					
						
							| 
									
										
										
										
											2013-06-14 20:20:47 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-04 12:04:41 +00:00
										 |  |  | 	if (argc > 1) | 
					
						
							|  |  |  | 		usage(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 	if (!argc) { | 
					
						
							| 
									
										
										
										
											2014-12-04 12:00:19 +00:00
										 |  |  | 		nl("<stdin>", stdin); | 
					
						
							| 
									
										
										
										
											2014-12-04 12:04:41 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2015-05-19 17:44:15 +02:00
										 |  |  | 		if (!strcmp(argv[0], "-")) { | 
					
						
							| 
									
										
										
										
											2015-05-15 13:28:39 +02:00
										 |  |  | 			argv[0] = "<stdin>"; | 
					
						
							|  |  |  | 			fp = stdin; | 
					
						
							|  |  |  | 		} else if (!(fp = fopen(argv[0], "r"))) { | 
					
						
							| 
									
										
										
										
											2014-12-04 12:04:41 +00:00
										 |  |  | 			eprintf("fopen %s:", argv[0]); | 
					
						
							| 
									
										
										
										
											2015-05-15 13:28:39 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-12-04 12:00:19 +00:00
										 |  |  | 		nl(argv[0], fp); | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-22 16:29:50 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-25 01:33:19 +02:00
										 |  |  | 	ret |= fp && fp != stdin && fshut(fp, argv[0]); | 
					
						
							|  |  |  | 	ret |= fshut(stdin, "<stdin>") | fshut(stdout, "<stdout>"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ret; | 
					
						
							| 
									
										
										
										
											2011-05-29 21:30:44 +01:00
										 |  |  | } |