// @(#)input.cc 1.3 93/08/01 // // Copyright (c) Steve Holden and Rich Burridge. // All rights reserved. // // Permission is given to distribute these sources, as long as the // copyright messages are not removed, and no monies are exchanged. // // No responsibility is taken for any errors inherent either // to the comments or the code of this program, but if reported // to me then an attempt will be made to fix them. #include #include #include #include #include #include #include #include "header.hh" #include "input.hh" #include "patchlevel.hh" #include "print.hh" extern Header hdr ; extern Input input ; extern Print prt ; // Does a string compare between a1 and a2. // To return '0', a1 and a2 must match to the length of a2, and that // length has to be at least 'minlen'. Otherwise, return non-zero. int Input::argcmp(char *a1, char *a2, int minlen) { if (strlen(a1) < minlen || strlen(a2) < minlen) return(1) ; if (strlen(a1) > strlen(a2)) return(1) ; return(strncmp(a1, a2, strlen(a1))) ; } // Adds 'hdr' header argument to the given list if it doesn't already exist. void Input::get_hdr_arg(char *hdr, char **list, int *n) { char arg[MAXLINE] ; int i, len ; (void) sscanf(hdr, "%s", arg) ; len = strlen(arg) ; if (arg[len-1] != ':') (void) strcat(arg, ":") ; for (i = 0; i < *n; i++) if (!strcasecmp(list[i], arg)) return ; list[(*n)++] = strdup(arg) ; } // Read and process command line options. void Input::get_options(int argc, char **argv) { int i ; progname = argv[0] ; // Save this program name. if (!strcmp(progname, "digestp")) digest = 1 ; else if (!strcmp(progname, "filep")) text_doc = 1 ; else if (!strcmp(progname, "filofaxp")) ptype = PRO_FILOFAX ; else if (!strcmp(progname, "franklinp")) ptype = PRO_FRANKLIN ; else if (!strcmp(progname, "mailp")) toprinter = 1 ; else if (!strcmp(progname, "newsp")) article = 1 ; else if (!strcmp(progname, "timemanp")) ptype = PRO_TIME_MANAGER ; else if (!strcmp(progname, "timesysp")) ptype = PRO_TIME_SYSTEM ; else toprinter = 0 ; for (i = 1; i < argc; i++) { if (argv[i][0] != '-') { if (numnames < MAXNAMES) { namelist[numnames++] = argv[i] ; if (numnames == MAXNAMES) cerr << progname << ": too many filenames. Only using first " << MAXNAMES << ".\n" ; } } else if (!argcmp(argv[i], "-a4", 3)) // A4 paper size. prt.paper_size = A4 ; else if (!argcmp(argv[i], "-addhdr", 3)) // Another header to print. { if (++i < argc) get_hdr_arg(argv[i], addhdrs, &addhdr_num) ; } else if (!argcmp(argv[i], "-article", 3)) // "Article from" format. article = 1 ; else if (!argcmp(argv[i], "-chars", 3)) // Gecos (chars). { if (++i < argc) namelength = atoi(argv[i]) ; } else if (!argcmp(argv[i], "-columns", 4)) // # of columns of output. { if (++i < argc) numcols = atoi(argv[i]) ; cols_given = 1 ; } else if (!argcmp(argv[i], "-content", 4)) // Use Content-Length: header. content = 1 ; else if (!argcmp(argv[i], "-digest", 2)) // Print digest. digest = 1 ; else if (!argcmp(argv[i], "-elm", 2)) // ELM mail file format. { elm_if = 1 ; folder = 1 ; // Kind of folder. } else if (!argcmp(argv[i], "-filofax", 3)) // Filofax output. ptype = PRO_FILOFAX ; else if (!argcmp(argv[i], "-folder", 3)) // Print mail folder. folder = 1 ; else if (!argcmp(argv[i], "-franklin", 4)) // Franklin Planner. ptype = PRO_FRANKLIN ; else if (!argcmp(argv[i], "-from", 4)) // Print originators name. print_orig = 1 ; else if (!argcmp(argv[i], "-help", 2)) // Print usage message. usage() ; else if (!argcmp(argv[i], "-landscape", 3)) // Landscape printing. { landscape = 1 ; ptype = PRO_LANDSCAPE ; } else if (!argcmp(argv[i], "-linelength", 3)) // # of chars per line. { if (++i < argc) llen = atoi(argv[i]) ; llen_given = 1 ; } else if (!argcmp(argv[i], "-modtime", 2)) // Print last mod. time. modtime = 1 ; else if (!argcmp(argv[i], "-nobanner", 3)) // No burst page. banner = 0 ; else if (!argcmp(argv[i], "-number", 3)) // Number lines. number = 1 ; else if (!argcmp(argv[i], "-pagelength", 3)) // # of lines per page. { if (++i < argc) plen = atoi(argv[i]) ; plen_given = 1 ; } else if (!argcmp(argv[i], "-postscript", 3)) // Print PostScript files. print_ps = 0 ; else if (!argcmp(argv[i], "-printer", 4)) // Printer name. { toprinter = 1 ; if (++i < argc && argv[i][0] != '-') prt.printer_name = argv[i] ; } else if (!argcmp(argv[i], "-prologue", 4)) // New prologue file. { if (++i < argc) (void) strcpy(proname, argv[i]) ; } else if (!argcmp(argv[i], "-remhdr", 3)) // Remove header to print. { if (++i < argc) get_hdr_arg(argv[i], remhdrs, &remhdr_num) ; } else if (!argcmp(argv[i], "-subject", 2)) // New subject line. { if (++i < argc) hdr.gsubject = argv[i] ; } else if (!argcmp(argv[i], "-tab", 3)) // # of spaces in a tab. { if (++i < argc) tabsize = atoi(argv[i]) ; } else if (!argcmp(argv[i], "-text", 3)) // Print ordinary text file. text_doc = 1 ; else if (!argcmp(argv[i], "-timeman", 6)) // Time Manager. ptype = PRO_TIME_MANAGER ; else if (!argcmp(argv[i], "-timesys", 6)) // Time/System Int. ptype = PRO_TIME_SYSTEM ; else if (!argcmp(argv[i], "-us", 2)) // US paper size. prt.paper_size = US ; else if (!argcmp(argv[i], "-version", 2)) // Print mp version number. cerr << progname << " version 3.0." << PATCHLEVEL << "\n\n" ; else if (!argcmp(argv[i], "-words", 3)) // Gecos (words). { if (++i < argc) namefields = atoi(argv[i]) ; } else if (!argcmp(argv[i], "-wrap", 3)) // Wrap words of output. wrapwords = 1 ; else usage() ; } } void Input::init_setup(void) // Set default values for various options. { char *c ; int amp_cnt = 0 ; // Number of ampersands in gecos field. int i, len ; struct passwd *pp ; c = getlogin() ; // Pointer to users login name. if (c == NULL || *c == '\0') // Get username from password file. { pp = getpwuid(geteuid()) ; if (pp == NULL) c = "printing" ; else c = pp->pw_name ; } owner = (char *) malloc((unsigned) (strlen(c) + 1)) ; (void) strcpy(owner, c) ; whoami = (char *) malloc((unsigned) (strlen(c) + 1)) ; (void) strcpy(whoami, c) ; // Save User login name. // Have a look for the users gecos (normally real name), so that its a bit // more recognisable. If this field is too long, then we need to truncate // sensibly. We also need to check a few things. If we've extracted // namefields "words" or have found a comma, then exit. If an ampersand is // found, this is expanded to the users name in capitals. pp = getpwnam(owner) ; if (pp != NULL && pp->pw_gecos && pp->pw_gecos[0] != '\0') { len = strlen(pp->pw_gecos) ; for (i = 0; i < len; i++) if (pp->pw_gecos[i] == '&') amp_cnt++ ; nameptr = getenv("NAME") ; if (nameptr != NULL) len = strlen(nameptr) ; else len = strlen(pp->pw_gecos) + amp_cnt * strlen(c) ; owner = (char *) malloc((unsigned) (len + 1)) ; if (nameptr != NULL) process_name_field(c, nameptr, namefields, namelength) ; else process_name_field(c, pp->pw_gecos, namefields, namelength) ; } if (text_doc) doc_type = DO_TEXT ; switch (doc_type) { case DO_TEXT : prt.message_for = "Listing for "; digest = 0 ; break ; case DO_MAIL : prt.message_for = digest ? "Mail digest for " : "Mail for " ; break ; case DO_NEWS : prt.message_for = digest ? "News digest for " : "News for " ; break ; } } Input::Input() { int i ; article = 0 ; // Set for news in "Article from " format. banner = 1 ; // Print a burst page by default. content = 0 ; // Set if Content-Length: has message length. digest = 0 ; // Set if printing a mail digest. elm_if = 0 ; // ELM mail frontend intermediate file format. end_of_file = 0 ; // EOF indicator. folder = 0 ; // Set if we are printing a mail folder. landscape = 0 ; // Set if we are printing in landscape mode. llen = LINELENGTH ; // Number of characters per line. modtime = 0 ; // If set, use last modification time. number = 0 ; // Don't number lines by default. numcols = 1 ; // Number of columns per page. plen = PAGELENGTH ; // Number of lines per page. print_orig = 0 ; // Print From rather than To in mail header. print_ps = 1 ; // Print PostScript files if set. tabsize = 8 ; // Number of spaces in a tab character. text_doc = 0 ; // Printing normal text. toprinter = 1 ; // Output to a printer. wrapwords = 0 ; // Wrap words of output if set. cols_given = 0 ; // Set if "-columns #" on command line. llen_given = 0 ; // Set if "-linelength #" on command line. plen_given = 0 ; // Set if "-pagelength #" on command line. // Try to get location of the mp prologue file from an environment variable. // If it's not found, then use the default value. if ((prologue = getenv("MP_PROLOGUE")) == NULL) prologue = PROLOGUE ; ptype = PRO_NORMAL ; for (i = 0; i < MAXHDRS; i++) hdrs[i] = NULL ; addhdr_num = 0 ; // Number of additional header lines to print. cpos = 0 ; // Current column position for usage output. linenum = 0 ; // Current line number from input file. numnames = 0 ; // Number of file names from argv. overflow = 0 ; // Initially no text wraparound. proname[0] = '\0' ; // Full pathname of the prologue file. remhdr_num = 0 ; // Number of additional header lines not to print. doc_type = DO_MAIL ; // Printing type - default mail. #ifdef GECOSFIELDS namefields = GECOSFIELDS ; // New no. of "words" from passwd gecos. #else namefields = NAMEFIELDS ; // Not supplied; use default. #endif /*GECOSFIELDS*/ #ifdef GECOSLENGTH namelength = GECOSLENGTH ; // New max. no. of chars. from passwd gecos. #else namelength = NAMELENGTH ; // Not supplied; use default. #endif /*GECOSLENGTH*/ } // Extract user name from $NAME or passwd GECOS. void Input::process_name_field(char *c, char *ptr, int fields, int length) { int i, j, len, n, spaces, slen ; n = spaces = 0 ; slen = strlen(ptr) ; for (i = 0; i < slen; i++) { if (*ptr == ',') break ; else if (*ptr == '&') { if (islower(c[0])) owner[n++] = toupper(c[0]) ; len = strlen(c) ; for (j = 1; j < len; j++) owner[n++] = c[j] ; ptr++ ; } else if (*ptr == ' ' || *ptr == '\t') { if (++spaces == fields) break ; else while (*ptr == ' ' || *ptr == '\t') owner[n++] = *ptr++ ; } else owner[n++] = *ptr++ ; if (n >= length) break ; } if (n > length) n = length ; owner[n] = '\0' ; } // Read an input line into nextline, setting end_of_file, end_of_page // and end_of_line appropriately. void Input::readline(void) { char *ptr ; int c ; int i = 0 ; // Index into current line being read. int len = 0 ; // Length of the current line. int startpos = 0 ; // Start position of real text in line. if (end_of_file) return ; end_of_page = end_of_line = 0 ; if (number) // Should we number output lines? { (void) sprintf(nextline, "%6d ", ++linenum) ; startpos = len = i = 8 ; } if (overflow) // Is this -wrap with word wraparound? { (void) strncpy(&nextline[len], iobuf, overflow) ; len += overflow ; i += overflow ; overflow = 0 ; } while (len < input.llen && (c = getc(ifp)) != EOF && c != '\n' && c != '\f') { if (c == '\t') { do { nextline[i++] = ' ' ; len++ ; } while (len % tabsize != 0 && len <= input.llen) ; } else { nextline[i++] = c ; len++ ; } if (c == '\b') { len -= 2 ; i -= 2 ; } } nextline[i] = '\0' ; if (len == input.llen && c != EOF && c != '\n' && c != '\f') { c = getc(ifp) ; if (c != EOF && c != '\n' && c != '\f') (void) ungetc(c, ifp) ; if (wrapwords && (ptr = strrchr(nextline, ' ')) != NULL) { (void) strcpy(iobuf, ptr+1) ; len = ptr - nextline + 1 ; nextline[len] = '\0' ; // Terminate current line. overflow = input.llen - len ; // # of chars wrapped. } } if (elm_if && c == '\f') { len-- ; i-- ; } switch (c) { case EOF : if (i == startpos) end_of_file = 1 ; else { (void) ungetc(c, ifp) ; end_of_line = 1 ; } break ; case '\n' : end_of_line = 1 ; break ; // /usr/ucb/mail for some unknown reason, appends a bogus formfeed at // the end of piped output. The next character is checked; if it's an // EOF, then end_of_file is set, else the character is put back. case '\f' : if ((c = getc(ifp)) == EOF) end_of_file = 1 ; else (void) ungetc(c, ifp) ; end_of_line = 1 ; end_of_page = 1 ; break ; } clen = len + 1 ; // Current line length (includes newline). } void Input::usage(void) // Print usage message and exit. { cerr << "Usage:\n" ; usageoption(progname) ; usageoption("[-a4]") ; // A4 paper size. usageoption("[-addhdr type]") ; // Add header to be printed. usageoption("[-article]") ; // "Article from" format. usageoption("[-chars #]") ; // Gecos (chars). usageoption("[-columns #]") ; // Number of columns of output. usageoption("[-content]") ; // Use Content-Length: header. usageoption("[-digest]") ; // Print digest. usageoption("[-elm]") ; // ELM mail file format. usageoption("[-filofax]") ; // Filofax output. usageoption("[-folder]") ; // Print mail folder. usageoption("[-franklin]") ; // Franklin Planner. usageoption("[-from]") ; // Print originators name. usageoption("[-help]") ; // Print usage message. usageoption("[-landscape]") ; // Landscape printing. usageoption("[-linelength #]") ; // Number of chars per line output. usageoption("[-modtime]") ; // Last modification time. usageoption("[-nobanner]") ; // No burst page on printer. usageoption("[-pagelength #]") ; // Number of lines per page output. usageoption("[-postscript]") ; // Print PostScript files. usageoption("[-printer]") ; // Send output to printer. usageoption("[-prologue name]") ; // New prologue file. usageoption("[-remhdr type]") ; // Remove header to print. usageoption("[-subject text]") ; // New subject line. usageoption("[-tab #]") ; // # spaces in a tab. usageoption("[-text]") ; // Print ordinary text file. usageoption("[-timeman]") ; // Time Manager. usageoption("[-timesys]") ; // Time/System Int. usageoption("[-us]") ; // US paper size. usageoption("[-version]") ; // Print mp version number. usageoption("[-words #]") ; // Gecos (words). usageoption("[-wrap]") ; // Wraps words of output. usageoption("[filename ...]") ; cerr << "\n\n" ; exit(1) ; } void Input::usageoption(char *st) // Output usage option. { if (strlen(st) + cpos > 78) { cerr << "\n " ; cpos = 3 ; } cerr << st << " " ; cpos += strlen(st) + 1 ; }