/* ** maxline ** ** Look at line lengths and count 'odd' characters. ** Useful for a first quick (jaundiced?) look at an ** imported file. */ /* Configuration ** ** Set the macros below appropriately. */ #define SIZE_T unsigned /* The type of the size parameter in various lib functions */ #define HAVE_STRERROR 1 #define HAVE_STRDUP 1 #if defined MSDOS # define KILL_CR 1 /* ignore '\r' before '\n' or end of file without '\n' */ # define Buffsize 10*BUFSIZ /* Buffer size - read(2) being int is the real limit (32K for DOS) */ #else /* assume Unix */ # define KILL_CR 0 # define Buffsize 3000*BUFSIZ #endif /* It should be automatic from here down. (HA!) */ #if defined __STDC__ # define PT(types) types #else # define PT(types) () # define const # define volatile # if defined lint && ! defined __GNUC__ # define void char # endif /* lint */ #endif /* stdc */ #if !defined lint static char rcsid[] = "$Id: maxline.c,v 1.7 1996/12/20 14:25:59 holdp Exp $"; #endif #include #include #include #include #include #include #include #include #if defined MSDOS # include #else # include #endif /* typedefs and #defines */ #define Streq(s1, s2) (strcmp(s1, s2) == 0) #define Init_ptr(p, str) { static char writable[] = str; p = writable; } #define True 1 #define False 0 typedef enum { E_open, E_close, E_nolf, E_read_err, E_toolong, E_impossible, E_silly1, E_nomem, E_invarg, E_oddchar } Emsg; typedef enum { Vanilla = 0, Char_cr, Char_ctrl, Char_form, Char_lf, Char_nonascii, Char_null, Char_tab, Char_backspace, Char_delete } Char_q; typedef enum { Everything, This_file } Init_ctl; typedef enum { Original, Dbfile } Op_style; #if defined lint int errno; /* llib-lc misses this. :-( */ #endif static char const *Usage = "\n\ Usage is maxline -adhflrtw -s nn -x nn -Tnn -o outfile [infile...]\n\ -h for more help.\n\n\ "; static char const *Document = "\ Examine line lengths of a file, normally reporting the maximum\n\ length and the existence of any 'difficult' characters\n\n\ -a display all lines\n\ -d delimit lines thusly ^....$\n\ -D output stub dbfile entry\n\ -F don't regard form-feeds as special\n\ -f display file names\n\ -h type this help\n\ -I don't regard tab characters as special\n\ -l display the length of lines\n\ -m nn display up to nn lines\n\ -n display line number\n\ -r reset at the start of each file\n\ -S display any line containing special characters\n\ -s nn display lines shorter than nn\n\ -t display text of lines for -a -w -x -s\n\ -T nn like -t, but display only the first nn chars of a line\n\ -o ofil use ofil for o/p\n\ -w display high water points\n\ -x nn display lines exceeding nn in length\n\n\ "; static char buff[Buffsize + 1]; /* we put a dummy '\n' at the end */ static Char_q char_class[256]; static char * current_file; static int show_ends = False; /* do we display anything on the fly */ static int display_all = False; static int display_highwater = False; static int display_shorter = 0; static int display_xs = Buffsize + 1; static long display_limit = 500L; static int display_something = False; static int display_specials = False; static int display_suspended = False; static char * file_of_max = NULL; static int form_feed_special = True; static int infd = -1; static char line[Buffsize + 1]; static long line_no; static long line_no_of_max; static long lines_displayed; static int max_length; static char * my_name = NULL; static long n_cr; static long n_chars; static long n_ctrl; static long n_form; static int n_files; static long n_lf; static long n_nonascii; static long n_null; static long n_tab; static long n_backspace; static long n_delete; static Op_style op_style = Original; static FILE * outfp = stdout; static int previous_length; static int recs_vary; static int reset_each_file = False; static int specials_in_line; static int tab_special = True; /* what do we show in the summary (and perhaps also on the fly) */ static int show_file_name = False; static int show_line_no = False; static int show_length = False; static int show_something; static int show_text = False; static int show_limit = Buffsize + 1; /* Function declarations (and a couple of #includes) */ #if defined __STDC__ # include static void whinge PT((int how, Emsg ecode, ...)); #else # include static void whinge(); #endif static void display PT((int ll, long ln, char *str)); static void do_line PT((char *start, char *end)); static void do_options PT((int *argcp, char ***argvp)); static void document PT((int print_full_help)); static int get_next_file PT((char ***argvp)); extern int getopt PT((int argc, char * const * argv , char const * options)); extern int main PT((int argc, char** argv)); static int pipe_read PT((int fd, char *ibuff, int want)); static void process PT((void)); static void reset PT((Init_ctl what)); static char * scan_to_lf PT((char *from)); static void setup_class PT((void)); extern char * strerror PT((int)); extern char * strdup PT((char const *)); static void summarise PT((void)); static void summarise_dbfile PT((void)); static void summarise_original PT((void)); /* MAIN ** */ int main(argc, argv) int argc; char ** argv; { my_name = *argv; Init_ptr(current_file, "stdin"); do_options(&argc, &argv); show_something = show_file_name | show_line_no | show_length | show_text; display_something = display_all || display_highwater || display_specials || (display_shorter > 0) || (display_xs <= Buffsize); if ( display_something && ! show_something ) whinge(3, E_silly1); setup_class(); file_of_max = malloc(1); /* we won't have to test before freeing now */ reset(Everything); n_files = 0; while ( (infd = get_next_file(&argv)) >= 0) { n_files++; process(); if ( reset_each_file ) { summarise(); reset(Everything); } else { reset(This_file); } } if ( !reset_each_file ) summarise(); free(file_of_max); return 0; } /* DISPLAY ** ** Display current maximum according to the format options. ** This could mean displaying nothing at all. */ static void display(len, num, file) int len; long num; char * file; { int n_show; unsigned char * uc; if ( display_suspended ) return; if ( show_file_name ) fprintf(outfp, "%s:", file); if ( show_line_no ) fprintf(outfp, "%5ldN:", num); if ( show_length ) fprintf(outfp, "%4dL:", len); if ( show_text ) { n_show = (show_limit < len)? show_limit : len; if ( show_ends ) putc('^', outfp); for ( uc = (unsigned char *)line; uc - (unsigned char *)line < n_show; uc++ ) { if ( char_class[*uc] != Vanilla || *uc == '\\' ) { if ( *uc == '\\' ) fprintf(outfp, "\\"); else fprintf(outfp, "\\%02X", *uc); } else { putc((char)*uc, outfp); } } if ( show_ends ) putc('$', outfp); } if ( show_something ) { if ( ++lines_displayed >= display_limit && !display_all ) { display_suspended = True; if ( lines_displayed == display_limit) fprintf(outfp, "\nDISPLAY SUSPENDED - limit %ld\n" , display_limit); } putc('\n', outfp); } } /* DO_LINE ** ** Process current line. The line runs >= start to < end ** with *end == '\n'. There is not a '\0' in sight! */ static void do_line(start, end) char * start; char * end; { int line_length; int show_this = False; int need_copy = False; line_length = end - start; /* i.e. don't count the '\n' */ #if KILL_CR if ( start[line_length-1] == '\r') { n_cr--; line_length--; } #endif if ( previous_length == -1 ) previous_length = line_length; else if ( previous_length != line_length ) recs_vary = True; if ( line_length > max_length ) { need_copy = True; max_length = line_length; line_no_of_max = line_no; if ( !Streq(file_of_max, current_file) ) { free(file_of_max); if ( (file_of_max = strdup(current_file)) == NULL ) whinge(3, E_nomem); } if ( display_highwater ) show_this = True; } if ( display_shorter > display_xs ) { /* sounds silly, but interpret it 'xs' < length < 'shorter' */ if ( line_length > display_xs && line_length < display_shorter ) { need_copy = True; show_this = True; } } else { if ( line_length > display_xs || line_length < display_shorter ) { need_copy = True; show_this = True; } } if ( display_all || (display_specials && specials_in_line) ) { need_copy = True; show_this = True; } if ( need_copy ) { /* note, line is NOT a record of high water if any ** display_xxx is set */ memcpy(line, start, (SIZE_T)line_length); line[line_length] = '\0'; /* stomping on the '\n' */ } if ( show_this ) display(line_length, line_no, current_file); } /* DO_OPTIONS ** ** Process options on the command line. The arguments, pointers ** to argv and argc, are updated to point to the first filename ** argument or to the NULL at the end of the argument vector if ** no files were named. ** Whinge and die if any problems. */ static void do_options(argcp, argvp) int * argcp; char ***argvp; { extern char * optarg; extern int optind; extern int opterr; int option; int opt_errors = 0; FILE * tmpfp; opterr = 1; /* Messages from getopt on/off */ while ( (option = getopt(*argcp, *argvp, "aDdhIFflnrtwo:Ss:x:T:m:")) != EOF ) { switch ( option ) { case 'a': display_all = True; break; case 'd': show_ends = True; break; case 'D': op_style = Dbfile; /* various implicit settings for this botch */ reset_each_file = True; break; case 'F': form_feed_special = False; break; case 'f': show_file_name = True; break; case 'h': document(True); break; case 'I': tab_special = False; break; case 'l': show_length = True; break; case 'm': display_limit = atol(optarg); break; case 'n': show_line_no = True; break; case 'r': reset_each_file = True; break; case 'S': display_specials = True; break; case 's': display_shorter = atoi(optarg); if ( display_shorter <= 0 || display_shorter > Buffsize ) { whinge(2, E_invarg, option); opt_errors++; } break; case 'T': show_limit = atoi(optarg); if ( show_limit <= 0 || show_limit > Buffsize ) { whinge(2, E_invarg, option); opt_errors++; } show_text = True; break; case 't': show_text = True; break; case 'w': display_highwater = True; break; case 'o': tmpfp = fopen(optarg, "w"); if (tmpfp == NULL) whinge(3, E_open, optarg, strerror(errno)); else outfp = tmpfp; break; case 'x': display_xs = atoi(optarg); if ( display_xs <= 0 || display_xs > Buffsize ) { whinge(2, E_invarg, option); opt_errors++; } break; default: opt_errors++; break; } } *argcp -= optind; *argvp = &(*argvp)[optind]; if ( opt_errors ) document(False); } /* DOCUMENT ** ** Type documentation: outputs usage message and optionally ** also a fuller help text. */ static void document(print_full_help) int print_full_help; { fputs(Usage, stderr); if ( print_full_help ) { fputs(Document, stderr); exit(0); } else { exit(1); } } /* GET_NEXT_FILE ** ** Close any file opened on a previous call with error checks. ** Open the next file named on the command line and advance ** argv over it. Return a file descriptor for it and when the ** list of file names is exhausted, return -1. If *argv == NULL ** on the first call (i.e. no files named) return the standard ** input (0). ** Whinge and die if problems arise. */ static int get_next_file(argvp) char *** argvp; { static int n_calls = 0; n_calls++; if ( infd != -1 ) if( close(infd) < 0 ) whinge(3, E_close, strerror(errno)); if ( **argvp == NULL) return (n_calls == 1)? 0 : -1; if ( (infd = open(**argvp, O_RDONLY) ) < 0 ) whinge(3, E_open, **argvp, strerror(errno)); current_file = **argvp; (*argvp)++; return infd; } /* PROCESS ** ** Process current file. */ static void process() { int expect_eof; int have_read; int to_read; int left_over; char * where_read; char * end_data; char * start_line; char * next_ch; where_read = buff; to_read = Buffsize; /* We read *big* chunks and process all complete lines in the ** buffer. We then move any left-over partial line down to the ** start of the buffer and set 'where_read' to point just after ** it. 'to_read' is correpondingly reduced and then rounded ** down to a multiple of 'BUFSIZ'. */ expect_eof = False; while ( (have_read = pipe_read(infd, where_read, to_read) ) >= 0 ) { if ( expect_eof && have_read != 0) whinge(3, E_impossible, "Missing end"); if ( have_read == 0 && where_read == buff ) return; n_chars += have_read; end_data = where_read + have_read - 1; *(end_data + 1) = '\n'; /* dummy end stop */ next_ch = where_read; /* not buff, to avoid double count */ start_line = buff; /* buff, to get length calc right */ for ( ;; ) { next_ch = scan_to_lf(next_ch); if ( (next_ch <= end_data) ) { /* all of a line in this buffer */ line_no++; n_lf++; do_line(start_line, next_ch); if ( next_ch++ == end_data ) { /* line fitted exactly */ where_read = buff; to_read = Buffsize; break; } start_line = next_ch; } else if ( have_read < to_read ) { /* can only be last bytes in the file */ line_no++; whinge(1, E_nolf, next_ch - start_line , current_file); do_line(start_line, next_ch); expect_eof = True; where_read = buff; to_read = Buffsize; break; } else { /* try for more */ left_over = next_ch - start_line; if ( start_line == buff ) whinge(3, E_toolong, Buffsize); memcpy(buff, start_line, (SIZE_T)left_over); where_read = buff + left_over; to_read = Buffsize - left_over; if ( to_read > BUFSIZ ) to_read = (to_read/BUFSIZ)*BUFSIZ; break; } } } if ( have_read < 0 ) whinge(3, E_read_err, strerror(errno)); } /* PIPE_READ ** ** Like read(2) except that, even if input is from a pipe, it will ** not return less than 'want' (except at EOF of course). */ static int pipe_read(fd, ibuff, want) int fd; char * ibuff; int want; { int reply; int got; got = 0; while (got < want) { reply = read(fd, ibuff+got, (SIZE_T)want-got); if ( reply < 0 ) return reply; /* though may have *some*, pre error */ else if ( reply == 0 ) return got; else /* some (at least) read */ got += reply; } return got; } /* RESET ** ** Reset global variables to starting values. Some always reset, ** others only if forced. */ static void reset(what) Init_ctl what; { line_no = 0; lines_displayed = 0; if ( what == Everything ) { max_length = -1; /* -1 to pick up zero length lines */ n_cr = 0L; n_ctrl = 0L; n_chars = 0L; n_form = 0L; n_lf = 0L; n_nonascii = 0L; n_null = 0L; n_tab = 0L; n_backspace = 0L; n_delete = 0L; previous_length = -1; recs_vary = False; } } /* SCAN_TO_LF ** ** Scan buffer looking for '\n', (and there is a *dummy* '\n' at least), ** counting various oddities. */ static char * scan_to_lf(from) char * from; { Char_q type; specials_in_line = False; for ( ; ; from++ ) { type = char_class[(unsigned char)*from]; if ( type != Vanilla ) { switch( type ) { case Char_lf: return from; /* NOTREACHED */ break; case Char_cr: specials_in_line = True; n_cr++; break; case Char_ctrl: specials_in_line = True; n_ctrl++; break; case Char_form: specials_in_line = True; n_form++; break; case Char_nonascii: specials_in_line = True; n_nonascii++; break; case Char_null: specials_in_line = True; n_null++; break; case Char_tab: specials_in_line = True; n_tab++; break; case Char_backspace: specials_in_line = True; n_backspace++; break; case Char_delete: specials_in_line = True; n_delete++; break; default: whinge(3, E_impossible, "Freak char"); break; } } } } /* SETUP_CLASS ** ** Set up the array to classify characters into those that need ** further examination and those which are just part of an ** ordinary line. It really ought to be a static initialsed at ** compile time. */ static void setup_class() { unsigned int i; for ( i = 0; i < (unsigned char)' '; i++ ) char_class[i] = Char_ctrl; for ( i = (unsigned char)' '; i < 128; i++ ) char_class[i] = Vanilla; for ( i = 128; i < 256; i++ ) char_class[i] = Char_nonascii; char_class[0] = Char_null; char_class[(unsigned char)'\f'] = form_feed_special? Char_form : Vanilla; char_class[(unsigned char)'\n'] = Char_lf; char_class[(unsigned char)'\r'] = Char_cr; char_class[(unsigned char)'\t'] = tab_special? Char_tab : Vanilla; char_class[8] = Char_backspace; char_class[127] = Char_delete; } #if !HAVE_STRDUP /* STRDUP ** ** Make a copy of a string in malloc space and return a pointer to ** it. Returns NULL if malloc fails. */ char * strdup(s) char const * s; { char * reply; reply = malloc(strlen(s) + 1); if (reply != NULL) strcpy(reply, s); return reply; } #endif #if !HAVE_STRERROR /* STRERROR ** ** Return a description the most recent system error - fakes ** strerror(3) for systems that don't have it. */ char * strerror(no) int no; { static char noinfo[50]; extern int sys_nerr; extern char * sys_errlist[]; if ( no > 0 && no < sys_nerr ) { return sys_errlist[no]; } else { sprintf(noinfo, "error code %d", no); return noinfo; } } #endif /* SUMMARISE ** ** Call appropriate O/P routine. */ static void summarise() { switch (op_style) { case Original: summarise_original(); break; case Dbfile: summarise_dbfile(); break; default: whinge(3, E_impossible, "Freak output style"); break; } } /* SUMMARISE_DBFILE ** ** Report on characters and oddities seen. Unless otherwise listing, ** display maximum line. */ static void summarise_dbfile() { if ( n_cr + n_ctrl + n_form + n_nonascii + n_null + n_tab + n_backspace + n_delete > 0) whinge(1, E_oddchar, current_file); fprintf(outfp, "%s location 1 %d %ld %ld description\n" , current_file, max_length, n_lf, n_chars); } /* SUMMARISE_ORIGINAL ** ** Report on characters and oddities seen. Unless otherwise listing, ** display maximum line. */ static void summarise_original() { fprintf(outfp, "\n"); fprintf(outfp, "%8d Maximum line length", max_length); if ( n_files > 1 || reset_each_file ) fprintf(outfp, " (in file %s)", file_of_max); if ( recs_vary ) fprintf(outfp, ", variable records\n\n"); else fprintf(outfp, ", constant records\n\n"); fprintf(outfp, "%8ld Line feeds\n", n_lf); if ( n_cr > 0 ) fprintf(outfp, "%8ld CARRIAGE RETURNS\n", n_cr); if ( n_ctrl > 0 ) fprintf(outfp, "%8ld CONTROL CHARACTERS\n", n_ctrl); if ( n_form > 0 ) fprintf(outfp, "%8ld FORM FEEDS\n", n_form); if ( n_nonascii > 0 ) fprintf(outfp, "%8ld NON - ASCII (> 0177)\n", n_nonascii); if ( n_null > 0 ) fprintf(outfp, "%8ld NULL CHARACTERS\n", n_null); if ( n_tab > 0 ) fprintf(outfp, "%8ld HORIZONTAL TABS\n", n_tab); if ( n_backspace > 0 ) fprintf(outfp, "%8ld BACKSPACES\n", n_backspace); if ( n_delete > 0 ) fprintf(outfp, "%8ld DELETE\n", n_delete); fprintf(outfp, "%8ld Total characters\n", n_chars); if( !display_something ) { putc('\n', outfp); display(max_length, line_no_of_max, file_of_max); } } /* WHINGE ** ** Prints an error message corresponding to ecode. The parameter ** 'how' controls what is prepended to the message and whether or ** not we exit. ** how==0 -> how==1 -> WARNING ** how==2 -> ERROR how==3 -> ERROR and exit(1); */ static void #if defined __STDC__ whinge(int how, Emsg ecode, ...) #else /* VARARGS 2 */ whinge(va_alist) # ifdef lint char va_alist; # else va_dcl # endif #endif { int i; char const * this_one = "unclassified error\n"; static struct mess_tab { Emsg code; char const *mess; } mess_tab[] = { { E_close, "error closing file\n" }, { E_impossible, "BUG: INTERNAL INCONSISTENCY (%s)\n" }, { E_invarg, "invalid argument to option %c\n" }, { E_open, "can't open %s, %s\n" }, { E_oddchar, "odd characters seen, file %s\n\ run without -D for more details.\n" }, { E_nolf, "last line has no line feed - length %d, file %s\n" }, { E_nomem, "can't get memory\n" }, { E_read_err, "read error: %s\n" }, { E_silly1, "options S, x, s, w or a without at least one of\n\t\tf,l,n,t or T, is silly\n" }, { E_toolong, "line too long - maximum %d\n" } }; int tabsize = sizeof mess_tab/sizeof(struct mess_tab); va_list args; #if defined __STDC__ va_start(args, ecode); #else int how; Emsg ecode; va_start(args); # ifdef lint how = 0; ecode = E_open; # else how = va_arg(args, int); ecode = va_arg(args, Emsg); # endif #endif for (i = 0; i < tabsize; i++) { if (ecode == mess_tab[i].code) { this_one = mess_tab[i].mess; break; } } fflush(outfp); if (how == 3) fprintf(stderr, "\n%s: ERROR - ", my_name); else if (how == 2) fprintf(stderr, "\n%s: ERROR - ", my_name); else if (how == 1) fprintf(stderr, "\n%s: WARNING - ", my_name); else fprintf(stderr, "%s: ", my_name); vfprintf(stderr, this_one, args); va_end(args); if (how == 3) exit(1); } ******************MAN PAGES*********************** .\" .\" $Id: maxline.1,v 1.3 1994/08/16 11:28:53 holdp Exp $ .\" .TH MAXLINE 1 "1 Oct 1992" "ESRC Data Archive" " " .SH NAME maxline \- report on line lengths and problem characters in files .SH SYNOPSIS \fB maxline \fR[\fB\-adDFfIhlnrStw\fR] [\fB\-x \fInn\fR] [\fB\-T \fInn\fR] [\fB\-o \fIofile\fR] \fIfile\fR... .SH DESCRIPTION \fBmaxline\fP finds the length of the longest line in \fIfiles\fR and reports the number \'odd\' characters. Odd characters are control characters and characters with an octal code greater than 177. Horizontal tab, form\-feed, Null, line\-feed, backspace and carriage\-control are separately counted. If the last line is not terminated by line feed, this fact is reported. The program also reports whether or not all records are the same size. It is of use when importing/exporting files from foreign machines, enabling the user to check the gross characteristics of a file. .SH OPTIONS .TP 4 \fB\-a\fR display all lines as specified by \fB\-flntT\fR. .TP 4 \fB\-d\fR delimit the text of displayed lines with \'^\' and \'$\'. .TP 4 \fB\-D\fR output in a form useful as a stub for a dbfile entry \- implies \fB\-r\fR. .TP 4 \fB-F\fR don't regard form\-feed as special. .TP 4 \fB\-f\fR display the current file name for lines listed by \fB\-awSsx\fR, and in the summary. .TP 4 \fB\-h\fR display help text. .TP 4 \fB-I\fR don't regard horizontal tab as special. .TP 4 \fB\-l\fR display the lengths of lines (flagged \'L\') for lines listed by \fB\-awSsx\fR, and in the summary. .TP 4 \fB\-m\fI nn\fR display up to \fInn\fR lines for the \fB\-awSsx\fR options. The default is to suspend output after 500 lines in order to avoid drowning the user in output if the file is not as expected. .TP 4 \fB\-n\fR display the line numbers (flagged \'N\') for lines listed by \fB\-awSsx\fR, and in the summary. .TP 4 \fB\-r\fR report individually on each file. .TP 4 \fB\-S\fR display lines containing any special characters as specified by \fB\-flntT\fR. .TP 4 \fB\-s\fI nn\fR display lines shorter than \fInn\fR as specified by \fB\-flntT\fR. .TP 4 \fB\-t\fR display the text of the line for \fB\-awSsx\fR, and in the summary. Non\-printing characters are displayed as a two digit hexadecimal number preceded by the character '\\'; any real '\\' characters in the line are displayed as '\\\\'. .TP 4 \fB\-T\fI nn\fR like \fB-t\fR, but only the first \fInn\fR characters of the line are displayed. .TP 4 \fB\-w\fR display high water points as specified by \fB\-flntT\fR as longer and longer lines are read. .TP 4 \fB\-o \fIofile\fP write output to file \fIofile\fR. .TP 4 \fB\-x\fI nn\fR display lines exceeding \fInn\fR characters as specified by \fB\-flntT\fR. .LP The use of the \fB\-s\fI ns\fR and the \fB\-x\fI nx\fR in combination is given the following meanings: if \fIns\fR is less than or equal to\fInx\fR, \fBmaxline\fR does just what you ask and lists the short and long lines; if \fIns\fR is greater than \fInx\fR, \fBmaxline\fR lists lines the lengths of which are between (and \fInot\fR including) \fIns\fR and \fInx\fR. .SH BUGS Only line-feed is regarded as a line delimiter: any form-feeds in the file are just part of a line. .LP This program is beginning to suffer from galloping optionitis. ##################### MAXLINE(1) MAXLINE(1) NAME maxline - report on line lengths and problem characters in files SYNOPSIS maxline [-adDFfIhlnrStw] [-x nn] [-T nn] [-o ofile] file... DESCRIPTION maxline finds the length of the longest line in files and reports the number 'odd' characters. Odd characters are con- trol characters and characters with an octal code greater than 177. Horizontal tab, form-feed, Null, line-feed, back- space and carriage-control are separately counted. If the last line is not terminated by line feed, this fact is reported. The program also reports whether or not all records are the same size. It is of use when importing/exporting files from foreign machines, enabling the user to check the gross characteristics of a file. OPTIONS -a display all lines as specified by -flntT. -d delimit the text of displayed lines with '^' and '$'. -D output in a form useful as a stub for a dbfile entry - implies -r. -F don't regard form-feed as special. -f display the current file name for lines listed by - awSsx, and in the summary. -h display help text. -I don't regard horizontal tab as special. -l display the lengths of lines (flagged 'L' ) for lines listed by -awSsx, and in the summary. -m nn display up to nn lines for the - awSsx options. The default is to suspend output after 500 lines in order to avoid drowning the user in output if the file is not as expected. -n display the line numbers (flagged 'N') for lines listed by -awSsx, and in the summary. -r report individually on each file. -S display lines containing any special characters as specified by -flntT. ESRC Data Archive Last change: 1 Oct 1992 1 MAXLINE(1) MAXLINE(1) -s nn display lines shorter than nn as specified by -flntT. -t display the text of the line for - awSsx, and in the summary. Non-printing characters are displayed as a two digit hexadecimal number preceded by the character '\'; any real '\' characters in the line are displayed as '\\'. -T nn like -t, but only the first nn characters of the line are displayed. -w display high water points as specified by - flntT as longer and longer lines are read. -o ofile write output to file ofile. -x nn display lines exceeding nn characters as specified by - flntT. The use of the -s ns and the -x nx in combination is given the following meanings: if ns is less than or equal tonx, maxline does just what you ask and lists the short and long lines; if ns is greater than nx, maxline lists lines the lengths of which are between (and not including) ns and nx. BUGS Only line-feed is regarded as a line delimiter: any form- feeds in the file are just part of a line. This program is beginning to suffer from galloping option- itis.