about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arr.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/arr.c b/arr.c
index 2644cf3..b489720 100644
--- a/arr.c
+++ b/arr.c
@@ -22,7 +22,7 @@ static char *s;
 //  "%{" FIELD (CHOP FIELD)* (("|" | "*") FIELD ((, | :) FIELD)*)? "}"
 
 void
-fmt_range(char **args, int bytewise)
+fmt_range(char **args, int bytewise, size_t argsnum)
 {
 	long n = 0;
 	char *end;
@@ -42,11 +42,13 @@ fmt_range(char **args, int bytewise)
 			}
 			s = end;
 			if (bytewise) {
-				printf("%c", args[0][n-1]);
+				if (n <= argsnum)
+					printf("%c", args[0][n-1]);
 			} else {
 				if (printed++)
 					printf("%c", lastsplit);
-				printf("%s", args[n]);
+				if (n < argsnum)
+					printf("%s", args[n]);
 			}
 			break;
 		case ',':
@@ -62,8 +64,12 @@ fmt_range(char **args, int bytewise)
 				fprintf(stderr, "can't parse number at '%s'.\n", s);
 				exit(1);
 			}
+			if (s == end)  // default to max range
+				n = argsnum;
 			s = end;
 			if (bytewise) {
+				if (n > argsnum)
+					n = argsnum;
 				if (l <= n)
 					for (l++; l <= n; l++)
 						printf("%c", args[0][l-1]);
@@ -71,6 +77,8 @@ fmt_range(char **args, int bytewise)
 					for (l--; l >= n; l--)
 						printf("%c", args[0][l-1]);
 			} else {
+				if (n >= argsnum)
+					n = argsnum-1;
 				if (l <= n)
 					for (l++; l <= n; l++) {
 						if (printed++)
@@ -97,7 +105,7 @@ fmt_range(char **args, int bytewise)
 }
 
 void
-fmt_inner(char **args)
+fmt_inner(char **args, size_t argsnum)
 {
 	long field, newfield;
 	char *end;
@@ -123,17 +131,19 @@ fmt_inner(char **args)
 			break;
 		case '|':
 			s++;
-			fmt_range(args, 0);
+			fmt_range(args, 0, argsnum);
 			return;
 		case '*':
 			s++;
-			fmt_range(args+field, 1);
+			if (field >= 0 && field < argsnum-1)
+				fmt_range(args+field, 1, strlen(args[field]));
+			else
+				fmt_range(args, 1, 0);
 			return;
 		case '}':
 			s++;
-			if (field == 0)
-				abort();
-			printf("%s", args[field]);
+			if (field >= 1 && field < argsnum-1)
+				printf("%s", args[field]);
 			return;
 		case '"':
 			s++;
@@ -154,7 +164,11 @@ fmt_inner(char **args)
 			lastsplit = *s;
 			s++;
 			split2:;
-			char *t = strdup(args[field]);
+			char *t;
+			if (field >= 1 && field < argsnum-1)
+				t = strdup(args[field]);
+			else
+				t = strdup("");
 			char **newargs = calloc(32 /*XXX*/, sizeof (char *));
 			if (lastsplit == ' ') {  // split on any ws
 				while (isspace((unsigned char)*t))
@@ -177,6 +191,7 @@ fmt_inner(char **args)
 				}
 			}
 			args = newargs;
+			argsnum = i;
 			field = 0;
 		}
 		}
@@ -184,7 +199,7 @@ fmt_inner(char **args)
 }
 
 void
-fmt(const char *pattern, char **args)
+fmt(const char *pattern, char **args, size_t argsnum)
 {
 	s = pattern;
 	lastsplit = '\t';
@@ -200,7 +215,7 @@ fmt(const char *pattern, char **args)
 				break;
 			case '{':
 				s++;
-				fmt_inner(args);
+				fmt_inner(args, argsnum);
 				break;
 			default:
 				putchar('%');
@@ -283,7 +298,7 @@ main(int argc, char *argv[]) {
 		}
 		if (eof)
 			break;
-		fmt(argv[1], lines);
+		fmt(argv[1], lines, argc+stdins);
 		printf("%c", delim);
 	}