#define _POSIX_C_SOURCE 200809L #include #include #include #include #include #include int main(int argc, char * argv[]) { /* Corresponds to -b (0), -f (1), and -h (2). 0 - -b a; 1 - -b t; 2 - -b n; 3 - -b p number_regex is for -b (0), -f (1), -h (2) */ int numbering[3] = {1, 2, 2}; char * number_regex[3]; /* delim is the delimiter used for sections specified by -d incr is the number of lines to increment numbering by (-i) */ char delim[3] = "\\:"; int incr = 1; /* lines corresponds to the -l option Only applies w/ -{b,f,h} t; -l 2 would number every other blank line (i.e. first blank not numbered, second blank numbered) format is format for numbering given by -n. 00 - rn; 01 - ln; 02 - rz restart is for -p, don't restart at page delimiters 1 is don't restart (-p given), 0 is restart (default) */ int lines = 1; int format = 00; int restart = 0; char sep = '\t'; /* Separator of number and line, given by -s */ int init_val = 1; /* Initial line number, given by -v */ int width = 6; /* Width of line number given by -w */ char c; char line[LINE_MAX]; char ln_format[90]; char format_str[LINE_MAX + 90]; FILE * file = NULL; int cur_section = 2; /* section being printed, as for -b, etc. */ while((c = getopt(argc, argv, "b:f:h:d:i:l:n:ps:v:w:")) != -1) { switch(c) { case 'p': restart = 1; break; case 'b': switch(optarg[0]) { case 'a': numbering[0] = 0; break; case 't': numbering[0] = 1; break; case 'n': numbering[0] = 2; break; case 'p': numbering[0] = 3; number_regex[0] = strdup(optarg+1); break; } break; case 'f': switch(optarg[0]) { case 'a': numbering[1] = 0; break; case 't': numbering[1] = 1; break; case 'n': numbering[1] = 2; break; case 'p': numbering[1] = 3; number_regex[1] = strdup(optarg+1); break; } break; case 'h': switch(optarg[0]) { case 'a': numbering[2] = 0; break; case 't': numbering[2] = 1; break; case 'n': numbering[2] = 2; break; case 'p': numbering[2] = 3; number_regex[2] = strdup(optarg+1); break; } break; case 'd': delim[0] = optarg[0]; delim[1] = optarg[1] == '\0' ? ':' : optarg[1]; break; case 'i': incr = atoi(optarg); break; case 'l': lines = atoi(optarg); break; case 'n': format = optarg[0] == 'l' ? 01 : 00; format = optarg[1] == 'z' ? format | 02 : format; break; case 's': sep = optarg[0]; case 'v': init_val = atoi(optarg); break; case 'w': width = atoi(width); break; } } ln_format[0] = '%'; ln_format[1] = format & 01 ? '-' : format & 02 ? '0' : '\0'; sprintf(ln_format + (ln_format[1] == '\0' ? 1 : 2), "%dd", width); strcpy(format_str, ln_format); strcat(format_str, "%c%s"); while(file == NULL) { file = fopen(argv[optind], "r"); if(file == NULL) { switch(errno) { case EACCES: fprintf(stderr, "%s: %s: access denied\n", argv[0], argv[optind]); exit(1); case EINTR: break; case EISDIR: fprintf(stderr, "%s: %s: is a directory\n", argv[0], argv[optind]); exit(2); case ELOOP: fprintf(stderr, "%s: %s: symlink loop detected\n", argv[0], argv[optind]); exit(3); case EMFILE: fprintf(stderr, "Hi, you shouldn't see this. %s somehow used up all the file descriptors available to it.\n", argv[0]); fprintf(stderr, "This is a bug. If you could let us know about it, that'd be much appreciated\n"); fprintf(stderr, "If you wanna debug, check near line 83 of nl.c. Otherwise, we'll just exit now.\n"); exit(5); case ENAMETOOLONG: fprintf(stderr, "%s: %s: name too long\n", argv[0], argv[optind]); exit(6); case ENFILE: fprintf(stderr, "%s: too many files open in system", argv[0]); exit(7); case ENOENT: fprintf(stderr, "%s: %s: file doesn't exist\n", argv[0], argv[optind]); exit(8); case ENOTDIR: int i = strlen(argv[optind]); while(argv[optind][i-1] == '/') { i--; } argv[optind][i] = '\0'; break; case ENXIO: fprintf(stderr, "%s: Did you mean to feed a device file to nl?\n", argv[0]); fprintf(stderr, "In any case, the device for this file doesn't exist (ENXIO). Sorry :P\n"); exit(9); case EOVERFLOW: fprintf(stderr, "%s: %s: file too big\n", argv[0], argv[optind]); exit(4); } } } }