@*Splitting mailing lists. The object of the game is to split mailing lists into multiple files. Usage is $$\hbox{\tt filesplit prefix numbers}$$ where {\tt prefix} is the prefix of all the output file names, and {\tt numbers} is a list of line numbers on which pieces of the file begin. The first line of the file is considered line~1 (for compatibility with {\tt awk(1)}). The numbers must be sorted in increasing order. A section consists of material from one number to the next. The material is printed in a file whose name begins with the {\tt prefix}, and which ends with a unique suffix (e.g. {\tt 00001, 00002, ...}). If a section number is preceded by a minus sign, the section beginning with that line number gets thrown on the floor instead of printed. If the prefix is |"-"|, we write all the writable sections to standard output. This makes it posssible to extract just pieces of a file. @= fprintf(stderr,"Usage:\n"); fprintf(stderr,"\tfilesplit prefix numbers...\n"); exit(1); @ @c #include main (argc, argv) int argc; char ** argv; { char *prefix; @; if (argc--<3) { @; } prefix = *++argv; argc--, argv++; @; exit(0); } @ With only one number left in the list, our job is to print from that line to end of file. Otherwise, we have two numbers, which we'll call |from_line| and |to_line|. We'll track the current line with |this_line|, which will be the number of next line schedule to be written to the output (or thrown on the floor). We have an implicit initial {\tt -1}, i.e. we don't print the initial segment of the file. @= int from_line, to_line; int this_line; /* the number of the next line scheduled to be printed */ @ @= multi_output=1; @; printing=0; from_line=0; this_line=1; while (argc!=0) { @; @; while (this_line != to_line) { @; } @; from_line = to_line; printing = next_printing; } @; while (1) { @; } finish: @; @ We ended prematurely if |from_line!=to_line|. @= if (from_line != to_line) fprintf(stderr,"filesplit: premature end of file\n"); @ We might as well get the details of the output files done with now. @= FILE *output; char filename[255]; int sequence_number=0; int multi_output; @ @= if (!strcmp(prefix,"-")) { output=stdout; multi_output=0; } @ @= if (printing && multi_output) { sprintf(filename,"%s%05d", prefix, sequence_number++); if ((output=fopen(filename,"w"))==NULL) { @; } } @ @= if (printing && multi_output) fclose(output); @ Here's how the copying works @= while ((c=getchar())!=EOF) { if (printing) putc(c,output); if (c=='\n') { this_line++; break; } } if (c==EOF) goto finish; @ @=char c; @ Since we determine sign when we read the target, we save the sign to set |printing| the next time around. @=int printing, next_printing; @ Here's our argument processing: @ @= sscanf(*argv++,"%d",&to_line); argc--; if (to_line<0) { to_line = - to_line; next_printing = 0; } else { next_printing=1; } if (to_line <= from_line) { fprintf(stderr,"filesplit: numbers out of order\n"); exit(-1); } @ @= fprintf(stderr,"filesplit: I couldn't open a file or something\n"); exit(-1); @*Index.