home *** CD-ROM | disk | FTP | other *** search
/ Power CD-ROM!! 7 / POWERCD7.ISO / prgmming / inter43 / intprint.c < prev    next >
C/C++ Source or Header  |  1994-06-11  |  55KB  |  2,084 lines

  1. /************************************************************************/
  2. /* INTPRINT.C by Ralf Brown.  Donated to the Public Domain.        */
  3. /* Please do not remove my name from any copies or derivatives.        */
  4. /************************************************************************/
  5. /* Program History:                            */
  6. /*   v1.00  4/23/89  initial public release                */
  7. /*             with 4/30/89 list                    */
  8. /*   v1.10  5/21/89  added -I and -f                    */
  9. /*   v1.11  1/6/90   fixed #endif's for compilers which don't handle    */
  10. /*             labels                        */
  11. /*   v1.20  6/8/90   added -r                        */
  12. /*   v1.30  7/14/90  added -b, tables now stay aligned on odd indents    */
  13. /*   v1.40  10/6/90  added -B based on changes by Naoto Kimura, -w    */
  14. /*   v1.40a 5/6/91   HP LaserJet II support by Russ Herman        */
  15. /*   v1.41  7/9/91   HP PCL support by P.J.Farley III            */
  16. /*   v2.00  9/1/91   modular printer definitions            */
  17. /*             printing multipart interrupt list            */
  18. /*   v2.01  2/9/92   fixed summary entry for non-numeric AX= and AH=    */
  19. /*             smarter page breaks                */
  20. /*   v2.02  2/18/92  bugfix & isxdigit suggested by Aaron West        */
  21. /*   v2.10  3/14/92  updated to handle extra flags in headings        */
  22. /*   v2.11  5/23/92  bugfix pointed out by Joe White            */
  23. /*   v2.20  6/12/92  added -F based on code by Richard Brittain        */
  24. /*             added -H and Panasonic printer def by Lewis Paper    */
  25. /*   v2.21  10/14/92 fixed error in -H/-r interaction            */
  26. /*             updated for new 'Bitmask of' section        */
  27. /*   v2.22   2/15/93 exclude Index: by default, -x to force inclusion    */
  28. /*             changed 'Bitmask of' to 'Bitfields for'        */
  29. /*   v2.23   5/24/93 fix to allow INT/AL= to appear correctly in summary*/
  30. /*   v2.24   7/15/93 -k and infinite-length pages by Bent Lynggaard    */
  31. /*   v3.00   6/4/94  -T, -V, and multi-file break section skipping    */
  32. /*             major speedups; checked for BC++3.1 compatibility    */
  33. /*   v3.01   6/11/94 bugfix: crashed with -l0 -L1 on lines >=80 chars   */
  34. /************************************************************************/
  35. /* Recompiling:                                */
  36. /*   Turbo C / Borland C++                        */
  37. /*    tcc -mt -lt -O -a -Z -p -k- intprint                */
  38. /*      bcc -mt -lt -a -O1agim -p intprint.c                */
  39. /************************************************************************/
  40.  
  41. #include <ctype.h>
  42. #include <fcntl.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <sys/stat.h>        /* S_IREAD, S_IWRITE */
  47.  
  48. #define VERSION "3.01"
  49.  
  50. /***********************************************/
  51. /*    portability definitions               */
  52.  
  53. #define _other_        /* assume no system-specific match */
  54.  
  55. /*--------------------------------------------------*/
  56. /* first system: MS-DOS with Turbo/Borland C        */
  57.  
  58. #ifdef __TURBOC__
  59. #  define PROTOTYPES
  60. #  include <alloc.h>
  61. #  include <io.h>    /* open, close, read, lseek, etc. */
  62.    int _Cdecl isatty(int handle) ;
  63.  
  64.    /* definitions to reduce size of executable */
  65.    unsigned int _Cdecl _stklen = 1024 ;
  66.    #define close _close
  67.    #define read _read
  68.    #define write _write
  69.    void _Cdecl _setenvp(void) {} /* don't need environment--don't include it */
  70.    void *_Cdecl malloc(size_t size) { return sbrk(size) ; }
  71.    void _Cdecl free(void *var) { (void)var ; }
  72.    /* since our free() doesn't do anything, macro it out of existence */
  73.    #define free(p)
  74.  
  75.    #ifdef __BORLANDC__
  76.    void _Cdecl _setupio(void) {}
  77.    #pragma warn -eff
  78.    #endif
  79.  
  80. #undef _other_
  81. #endif /* __TURBOC__ */
  82.  
  83. #ifdef __MSDOS__
  84. #  define LINE_TERMINATOR '\n'
  85. #endif
  86.  
  87. /*--------------------------------------------------*/
  88. /*   Gnu C compiler                                 */
  89.  
  90. #ifdef __GNUC__
  91. #define PROTOTYPES
  92. #define NEED_ITOA
  93. #define NEED_ULTOA
  94. #define NEED_STRUPR
  95. #define NEED_STRNICMP
  96.  
  97. #undef _other_
  98. #endif /* __GNUC__ */
  99.  
  100. /*--------------------------------------------------*/
  101. /*  generic Unix definitions                        */
  102.  
  103. #ifdef unix
  104. #  include <sys/unistd.h>    /* open, close, read, lseek, etc. */
  105. #  include <sysent.h>        /* open, close, read, lseek, etc. */
  106. extern int isatty(int) ;
  107. #  define LINE_TERMINATOR '\n'
  108. #endif
  109.  
  110.  
  111. /*--------------------------------------------------*/
  112. /*  any other system                                */
  113.  
  114. #ifdef _other_
  115. /* unknown compiler/system, so set configuration #defines */
  116. #if 0  /* set to 1 if compiler supports ANSI-style prototypes, 0 otherwise */
  117. #define PROTOTYPES
  118. #endif
  119. #if 1  /* set to 0 if library contains strnicmp(), 1 otherwise */
  120. #define NEED_STRNICMP
  121. #endif
  122. #if 1  /* set to 0 if library contains isxdigit(), 1 otherwise */
  123. #define NEED_ISXDIGIT
  124. #endif
  125. #if 1  /* set to 0 if library contains strupr(), 1 otherwise */
  126. #define NEED_STRUPR
  127. #endif
  128. #if 1  /* set to 0 if library contains three-arg itoa(), 1 otherwise */
  129. #define NEED_ITOA
  130. #endif
  131. #if 1  /* set to 0 if library contains three-arg ultoa(), 1 otherwise */
  132. #define NEED_ULTOA
  133. #endif
  134.  
  135. /* the last character of the line termination sequence, i.e. '\n' for CRLF */
  136. /* and LF, '\r' if your system uses CR or LFCR */
  137. #define LINE_TERMINATOR '\n'
  138.  
  139. #endif /* _other_ */
  140.  
  141. /*--------------------------------------------------*/
  142. /*  catchall for macros which might not be defined  */
  143.  
  144. #ifndef O_BINARY
  145. #  define O_BINARY 0
  146. #endif
  147.  
  148. #ifndef _Cdecl
  149. #  define _Cdecl
  150. #endif
  151.  
  152. /***********************************************/
  153.  
  154. #ifndef FALSE
  155. #define FALSE 0
  156. #endif
  157. #ifndef TRUE
  158. #define TRUE !FALSE
  159. #endif
  160.  
  161. /***********************************************/
  162.  
  163. #define MAXLINE 82   /* at most 80 chars per line (plus CR and newline) */
  164. #define MAXPAGE 200  /* at most 200 lines per page */
  165.  
  166. #define lengthof(x) (sizeof(x)/sizeof(x[0]))
  167.  
  168. #define divider_line(line) (line[0] == '-' && memcmp(line+1,"-------",7) == 0)
  169. #ifdef __MSDOS__
  170. #define start_of_entry(s) (((int*)s)[0]==(256*'N'+'I')&&((int*)s)[1]==(256*' '+'T'))
  171. #define index_line(l) \
  172.   (((int*)l)[0]==(256*'n'+'I')&&((int*)l)[1]==(256*'e'+'d')&& \
  173.    ((int*)l)[2]==(256*':'+'x'))
  174. #else
  175. #define start_of_entry(s) (memcmp(s,"INT ",4) == 0)
  176. #define index_line(line) (line[0] == 'I' && memcmp(line+1,"ndex:",5) == 0)
  177. #endif
  178. #define section_start(line) is_keyword(line,section_start_keys,lengthof(section_start_keys))
  179. #define start_of_table(line) (is_keyword(line,table_start_keys,lengthof(table_start_keys)))
  180.    
  181. #define section_file_start(s) (s[0] == '-' && memcmp(s+1,"-------!---Section",18) == 0)
  182.  
  183.  
  184. /***********************************************/
  185. /*    replacement file I/O function macros     */
  186. /***********************************************/
  187.  
  188. typedef struct
  189.    {
  190.    int fd ;
  191.    int buf_maxsize ;
  192.    char *buf ;
  193.    unsigned long bufoffset ;
  194.    int bufsize ;
  195.    int bufpos ;
  196.    int write ;             /* file is output file if nonzero */
  197.    } IP_FILE ;
  198.  
  199. #define ip_putc(c,fp) \
  200.   ((fp)->buf[fp->bufpos++]=(c),\
  201.    ((fp)->bufpos>=(fp)->buf_maxsize&&ip_flush(fp)==-1)?-1:0)
  202.  
  203. /* output the indicated counted string to the given file */
  204. #define ip_putcstr(s,fp) ip_write((s)->str,(s)->len,fp)
  205. /* output the given string literal to the indicated file */
  206. #define ip_putlit(s,fp) ip_write((s),sizeof(s)-1,fp)
  207. /* output the given string variable to the indicated file */
  208. #define ip_puts(s, fp) ip_write(s,strlen(s),fp)
  209.  
  210. #ifdef __MSDOS__
  211. #define newline(fp) ip_write("\r\n",2,fp)
  212. #else
  213. #define newline(fp) ip_putc('\n',fp)
  214. #endif
  215.  
  216. /***********************************************/
  217.  
  218. typedef struct             /* a counted string */
  219.    {
  220.    int len ;             /* the string's length */
  221.    char *str ;             /* the actual contents of the string */
  222.    } cstr ;
  223.  
  224. #define CSTR(s) { sizeof(s)-1, (s) }  /* for defining a counted string literal */
  225. #define cstrlen(s) ((s)->len)     /* how long is the counted string? */
  226.  
  227. typedef struct
  228.    {
  229.    char *name ;            /* for selecting the appropriate printer */
  230.    cstr init1, init2 ;        /* initialization strings */
  231.    cstr marginl, marginc, marginr ; /* margins: duplex even, non-duplex, duplex odd */
  232.    cstr duplex_on ;        /* turn on duplex mode */
  233.    cstr term1, term2 ;        /* cleanup strings */
  234.    cstr bold_on, bold_off ;    /* boldface on/off */
  235.    int indent ;            /* how many extra spaces to indent */
  236.    int lines_per_page ;        /* how many lines to print on each page */
  237.    int page_length ;        /* how many lines on each page */
  238.    int page_width ;        /* how many printable columns per line? */
  239. #ifdef PROTOTYPES
  240.    void (*put_line)(IP_FILE *,int) ;/* function to call to print out divider line */
  241.    void (*set_typeface)(IP_FILE *,char *) ;
  242. #else
  243.    void (*put_line)() ;        /* function to call to print out divider line */
  244.    void (*set_typeface)() ;
  245. #endif /* PROTOTYPES */
  246.    int *flag ;            /* flag to set when using this printer definition */
  247.    } PRINTER_DEF ;
  248.  
  249. typedef struct filter_list
  250.    {
  251.    struct filter_list *next ;
  252.    char str[1] ;        /* will allocate enough for actual string */
  253.    } FILT_LIST ;
  254.  
  255. typedef struct
  256.    {
  257.    int part ;
  258.    int first_on_page ; /* TRUE if a new entry starts at the top of the page */
  259.    char desc[24] ;
  260.    int len ;
  261.    } HEADER ;
  262.  
  263. typedef struct
  264.    {
  265. /*   char *name ;*/
  266.    char name[14] ;
  267.    int length ;
  268.    } KEYWORDS ;
  269.  
  270. /***********************************************/
  271.  
  272. #ifdef PROTOTYPES
  273. void usage(void) ;
  274. void fatal(char *msg) ;
  275. void warning(char *msg) ;
  276. int unwanted_section(char *buf) ;
  277. IP_FILE *ip_fdopen(int fd,char *buf,int bufsiz, int maxsiz, int write) ;
  278. IP_FILE *ip_open_write(char *name, int trunc, char *buf, int bufsiz) ;
  279. IP_FILE *ip_open_read(char *name, char *buf, int bufsiz) ;
  280. int ip_close(IP_FILE *fp) ;
  281. unsigned long ip_fgets(char *buf, int max, IP_FILE *fp) ;
  282. int ip_write(char *buf, int count, IP_FILE *fp) ;
  283. int ip_flush(IP_FILE *fp) ;
  284. void get_raw_line(char *buf) ;
  285. void get_line(char *buf) ;
  286. void indent_to(int where,IP_FILE *fp) ;
  287. void put_line(IP_FILE *fp, int len) ;
  288. void HPPCL_put_line(IP_FILE *fp, int len) ;
  289. void HPPCL_set_typeface(IP_FILE *fp,char *typeface) ;
  290. int is_keyword(char *s, KEYWORDS *keys, unsigned int numkeys) ;
  291. void output_line(char *line,IP_FILE *fp) ;
  292. void fill_buffer(int lines, int lines_per_page) ;
  293. int find_page_break(int lines) ;
  294. int summarize(int line, int pages_printed) ;
  295. void start_format(char *line) ;
  296. void write_summary_header(IP_FILE *fp, char *title, int offsets, int tables) ;
  297. void show_offset(int line,IP_FILE *fp) ;
  298. void add_table(int i) ;
  299. FILT_LIST *add_filter_info(FILT_LIST *list,char *str) ;
  300. void build_filter_lists(char *file) ;
  301. int make_description(char *desc,int line) ;
  302. char *determine_heading(int last) ;
  303. void print_buffer(int last,int body_lines,int lines_per_page,int total_lines,
  304.           int use_FF) ;
  305. void select_printer(char *name) ;
  306. void display_printers(void) ;
  307. static void reset_printer_and_close(IP_FILE *fp) ;
  308. int _Cdecl main(int argc, char **argv) ;
  309. #else
  310. void put_line() ;
  311. void HPPCL_put_line() ;
  312. void HPPCL_set_typeface() ;
  313. void show_offset() ;
  314. #endif /* PROTOTYPES */
  315.  
  316. /***********************************************/
  317. /*    I/O buffers                   */
  318. /***********************************************/
  319.  
  320. char stderr_buf[256] ;
  321. char filter_buf[256] ;
  322. char infile_buf[8192] ;
  323. char outfile_buf[8192] ;
  324. char summary_buf[4096] ;
  325. char formats_buf[3072] ;
  326. char tables_buf[3072] ;
  327.  
  328. /***********************************************/
  329.  
  330. IP_FILE *err ;
  331. IP_FILE *infile ;
  332. IP_FILE *outfile ;
  333. char *input_file ;
  334. int input_file_namelen ;
  335.  
  336. char buffer[MAXPAGE][MAXLINE] ;
  337. unsigned long line_offsets[MAXPAGE] ;
  338. char num[6] ;
  339. int need_summary ;
  340. char summary_line[2*MAXLINE] ;
  341. int summary_line_len ;
  342.  
  343. int pages_printed = 0 ;
  344. int page_width = 0 ;        /* page width in characters, 0 = use prtdef */
  345. int indent = 0 ;            /* number of columns to indent lines */
  346. char *indent_string = NULL ;    /* what to add at start of line to indent */
  347. int indent_len = 0 ;            /* length of indent_string */
  348. int widow_length = 8 ;        /* number of lines to scan for good place to break */
  349. int page_numbers = FALSE ;    /* add page numbers to bottom of page? */
  350. int multi_file = FALSE ;    /* printing multipart interrupt list? */
  351. int out_of_files = FALSE ;    /* hit end of last file for multipart printing? */
  352. int do_summary = FALSE ;    /* create a one-line-per-call summary? */
  353. int do_tables = FALSE ;        /* create a one-line-per-table index? */
  354. int do_formats = FALSE ;    /* create a separate file with data structures? */
  355. int do_filter = FALSE ;        /* using a filtering file? */
  356. int do_headers = FALSE ;    /* add page headings? */
  357. int include_index_lines = FALSE ;
  358. int IBM_chars = FALSE ;        /* printer can handle IBM graphics characters */
  359. int boldface = FALSE ;        /* boldface titles and Return:/Notes: ? */
  360. int printer_bold = FALSE ;    /* boldface using printer control sequences? */
  361. int echo_format = FALSE ;
  362. int duplex = FALSE ;
  363. int HPPCL_mode = FALSE ;
  364. int show_offsets = FALSE ;
  365. int keep_divider_lines = FALSE ;
  366. IP_FILE *summary ;
  367. IP_FILE *tables ;
  368. IP_FILE *formats ;
  369. PRINTER_DEF *printer = NULL ;
  370.  
  371. unsigned long current_line_offset = 0 ;
  372. unsigned long offset_adjust = 0 ;
  373.  
  374. unsigned int first_page = 0 ;
  375. unsigned int last_page = ~0 ;
  376.  
  377. int prev_table = 0 ;
  378.  
  379. FILT_LIST *includes = NULL ;
  380. FILT_LIST *excludes = NULL ;
  381.  
  382. HEADER header_first = { 0, FALSE, "" } ;
  383. HEADER header_last = { 0, FALSE, "" } ;
  384.  
  385. /***********************************************/
  386.  
  387. PRINTER_DEF printers[] =
  388.    {
  389.      { "default",
  390.        CSTR(""), CSTR(""),
  391.        CSTR(""), CSTR(""), CSTR(""),
  392.        CSTR(""),
  393.        CSTR(""), CSTR(""),
  394.        CSTR(""), CSTR(""),
  395.        -1,
  396.        60,
  397.        0,
  398.        79,
  399.        put_line,
  400.        NULL,
  401.        NULL,
  402.      },
  403.      { "Epson FX80, 12 cpi",
  404.        CSTR("\033M"), CSTR(""),
  405.        CSTR("\033l\004"), CSTR("\033l\007"), CSTR("\033l\014"),
  406.        CSTR(""),
  407.        CSTR("\033P"), CSTR("\033l\000"),
  408.        CSTR("\033E"), CSTR("\033F"),
  409.        0,
  410.        60,
  411.        0,
  412.        87,    /* 96 - left margin - 1 right margin */
  413.        put_line,
  414.        NULL,
  415.        NULL,
  416.      },
  417.      { "Panasonic KX-P1124i / 10 cpi Epson",
  418.        CSTR(""), CSTR(""),
  419.        CSTR(""), CSTR(""), CSTR(""),
  420.        CSTR(""),
  421.        CSTR(""), CSTR(""),
  422.        CSTR("\033E"), CSTR("\033F"),
  423.        -1,
  424.        60,
  425.        0,
  426.        79,
  427.        put_line,
  428.        NULL,
  429.        NULL,
  430.      },
  431.      { "HP PCL",
  432.        CSTR("\033(8U"), CSTR(""),
  433.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  434.        CSTR("\033&l1S"),
  435.        CSTR("\033E"), CSTR(""),
  436.        CSTR("\033(s3B"), CSTR("\033(s0B"),
  437.        0,
  438.        69,
  439.        0,
  440.        87,    /* 96 - left margin - 1 right margin */
  441.        HPPCL_put_line,
  442.        HPPCL_set_typeface,
  443.        &HPPCL_mode,
  444.      },
  445. #define HPPCL_FONT_ON_A "\033(s0p12h10v0s0b"
  446. /* HP PCL4/5 Font select: Roman-8;Upright12Pitch10PointMediumWeight */
  447. #define HPPCL_FONT_ON_B "T\033&l6.8571C"
  448. /* HP PCL4/5 Font select: End typeface select;VMI=7LPI: (48/7)-48th's inches*/
  449. #define HPPCL_IBM_LN_A    "\033&f0S\033*p-15Y\033*c"
  450. /* HP PCL4/5 IBM Line:    Push Pos;Up 15/720";Hor.Rule ???/300ths" long */
  451. #define HPPCL_IBM_LN_B    "a3b0P\033&f1S"
  452. /* HP PCL4/5 IBM Line:     3/300ths" high,Print rule;Pop Position */
  453.      { "LaserJet II",
  454.        CSTR("\033(10U"),CSTR(""),
  455.        CSTR("\033&a4c4L"), CSTR("\033&a8c8L"), CSTR("\033&a12c12L"),
  456.        CSTR(""),
  457.        CSTR("\033E"),CSTR(""),
  458.        CSTR("\033(s3B"),CSTR("\033(s0B"),
  459.        0,
  460.        54,
  461.        60,
  462.        79,
  463.        put_line,
  464.        NULL,
  465.        &IBM_chars,
  466.      },
  467.    } ;
  468. #define NUM_PRINTERS lengthof(printers)
  469.  
  470. /***********************************************/
  471.  
  472. #define KEYWORD_ENTRY(s) { s, sizeof(s)-1 }
  473.  
  474. KEYWORDS section_start_keys[] =
  475.    {
  476.     KEYWORD_ENTRY("BUG:"),
  477.     KEYWORD_ENTRY("BUGS:"),
  478.     KEYWORD_ENTRY("Desc:"),
  479.     KEYWORD_ENTRY("Index:"),
  480.     KEYWORD_ENTRY("Note:"),
  481.     KEYWORD_ENTRY("Notes:"),
  482.     KEYWORD_ENTRY("Program:"),
  483.     KEYWORD_ENTRY("Range:"),
  484.     KEYWORD_ENTRY("Return:"),
  485.     KEYWORD_ENTRY("SeeAlso:"),
  486.    } ;
  487.  
  488. KEYWORDS table_start_keys[] =
  489.    {
  490.     KEYWORD_ENTRY("Bitfields "),
  491.     KEYWORD_ENTRY("Call "),
  492.     KEYWORD_ENTRY("Format "),
  493.     KEYWORD_ENTRY("Values "),
  494.    } ;
  495.  
  496. /***********************************************/
  497.  
  498. #ifdef isxdigit
  499. #undef NEED_ISXDIGIT
  500. #endif
  501.  
  502. #ifdef NEED_STRNICMP
  503. #ifdef PROTOTYPES
  504. int strnicmp(char *s1,char *s2,unsigned int len) ;
  505. #endif
  506. int strnicmp(s1,s2,len)
  507. char *s1,*s2 ;
  508. unsigned int len ;
  509. {
  510.    char c1, c2 ;
  511.  
  512.    while (*s1 && *s2 && len > 0)
  513.       {
  514.       len-- ;
  515.       c1 = (islower(*s1) ? toupper(*s1) : *s1) ;
  516.       c2 = (islower(*s2) ? toupper(*s2) : *s2) ;
  517.       if (c1 != c2 || len == 0)     /* mismatch or substrings exhausted? */
  518.      return (c1 - c2) ;
  519.       s1++ ;
  520.       s2++ ;
  521.       }
  522.    return 0 ;  /* strings match exactly on first 'len' characters */
  523. }
  524. #endif /* NEED_STRNICMP */
  525.  
  526. #ifdef NEED_STRUPR
  527. #ifdef PROTOTYPES
  528. char *strupr(char *s) ;
  529. #endif
  530. char *strupr(s)
  531. char *s ;
  532. {
  533.    char *orig_s = s ;
  534.    char c ;
  535.    
  536.    if (s)
  537.       while (*s)
  538.      {
  539.      c = *s ;      
  540.      *s++ = (islower(c) ? toupper(c) : c) ;
  541.      }
  542.    return orig_s ;
  543. }
  544. #endif /* NEED_STRUPR */
  545.  
  546. #ifdef NEED_ISXDIGIT
  547. #ifdef PROTOTYPES
  548. int isxdigit(int c) ;
  549. #endif
  550. int isxdigit(c)
  551. int c ;
  552. {
  553.    return isdigit(c) || (memchr("ABCDEFabcdef",c,12) != NULL) ;
  554. }
  555. #endif /* NEED_ISXDIGIT */
  556.  
  557. #ifdef NEED_ITOA
  558. #ifdef PROTOTYPES
  559. char *itoa(int num,char *buf,int radix) ;
  560. #endif
  561. char *itoa(num,buf,radix)   /* not everybody has the same itoa() as TurboC */
  562. int num ;            /* minimal implementation */
  563. char *buf ;
  564. int radix ;
  565. {
  566.    int count = 0 ;
  567.    int i ; 
  568.    char tmp ;
  569.  
  570.    do {
  571.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  572.       num /= radix ;
  573.    } while (num) ;
  574.    buf[count] = '\0' ;
  575.    if (count > 1)
  576.       for (i = 0 ; i < count / 2 ; i++)
  577.      {
  578.      tmp = buf[i] ;
  579.      buf[i] = buf[count-i-1] ;
  580.      buf[count-i-1] = tmp ;
  581.      }
  582.    return buf ;
  583. }
  584. #endif /* NEED_ITOA */
  585.  
  586. #ifdef NEED_ULTOA
  587. #ifdef PROTOTYPES
  588. char *ultoa(unsigned long num,char *buf,int radix) ;
  589. #endif
  590. char *ultoa(num,buf,radix)   /* not everybody has the same ultoa() as TurboC */
  591. unsigned long num ;         /* minimal implementation */
  592. char *buf ;
  593. int radix ;
  594. {
  595.    int count = 0 ;
  596.    int i ; 
  597.    char tmp ;
  598.  
  599.    do {
  600.       buf[count++] = "0123456789ABCDEF"[num % radix] ;
  601.       num /= radix ;
  602.    } while (num) ;
  603.    buf[count] = '\0' ;
  604.    if (count > 1)
  605.       for (i = 0 ; i < count / 2 ; i++)
  606.      {
  607.      tmp = buf[i] ;
  608.      buf[i] = buf[count-i-1] ;
  609.      buf[count-i-1] = tmp ;
  610.      }
  611.    return buf ;
  612. }
  613. #endif /* NEED_ULTOA */
  614.  
  615. /***********************************************/
  616.  
  617. void usage()
  618. {
  619.    ip_putlit("\
  620. Usage: intprint [options] intlist [>|>>]output\r\n\
  621. Options:\r\n\
  622. Filtering:\t-Ffile\tprint only entries matching filtering info in 'file'\r\n\
  623. \t\t-k\tkeep original divider lines\r\n\
  624. \t\t-rN:M\tprint only pages N through M\r\n\
  625. \t\t-x\tinclude Index: lines in formatted output\r\n\
  626. Formatting:\t-b\tboldface headings\t-B\tbold with control codes\r\n\
  627. \t\t-d\t(duplex) print even/odd pages with different indents\r\n\
  628. \t\t-e\t(elite) 96 chars/line\t-tN\tselect typeface N\r\n\
  629. Pagination:\t-H\tadd page headers\t-iN\tindent N spaces\r\n\
  630. \t\t-p\tnumber pages\t\t-nN\tN pages already printed\r\n\
  631. \t\t-wN\twidow lines control\r\n\
  632. \t\t-lN\tprint length\t\t-LN\ttotal page length\r\n\
  633. \t\t\t(0 = infinite)\t(use linefeeds if > #lines printed)\r\n\
  634. Printer:\t-I\tIBM graphics characters\r\n\
  635. \t\t-Pname\tassume printer 'name'\t-P?\tlist printers\r\n\
  636. Summaries:\t-ffile\tdata structure formats\t-sfile\tINT calls\r\n\
  637. \t\t-Tfile\tlist tables\r\n\
  638. Misc:\t\t-m\tprocess multiple parts\t-V\tmake INTERVUE summary\r\n\
  639. "
  640.     ,err) ;
  641.    ip_flush(err) ;
  642.    exit(1) ;
  643. }
  644.  
  645. /***********************************************/
  646.  
  647. void fatal(msg)
  648. char *msg ;
  649. {
  650.    ip_putlit("UNRECOVERABLE ERROR:",err) ;
  651.    newline(err) ;
  652.    ip_puts(msg,err) ;
  653.    newline(err) ;
  654.    exit(1) ;
  655. }
  656.  
  657. /***********************************************/
  658.  
  659. void warning(msg)
  660. char *msg ;
  661. {
  662.    ip_putlit("Warning: ",err) ;
  663.    ip_puts(msg,err) ;
  664.    newline(err) ;
  665. }
  666.  
  667. /***********************************************/
  668.  
  669. IP_FILE *ip_fdopen(fd,buf,bufsiz,maxsiz,write)
  670. int fd ;
  671. char *buf ;
  672. int bufsiz, maxsiz, write ;
  673. {
  674.    IP_FILE *fp = (IP_FILE *)malloc(sizeof(IP_FILE)) ;
  675.    
  676.    if (fp)
  677.       {
  678.       fp->fd = fd ;
  679.       fp->buf = buf ;
  680.       fp->bufsize = bufsiz ;
  681.       fp->buf_maxsize = maxsiz ;
  682.       fp->bufpos = 0 ;
  683.       fp->bufoffset = 0 ;
  684.       fp->write = write ;
  685.       }
  686.    return fp ;
  687. }
  688.  
  689. /***********************************************/
  690.  
  691. IP_FILE *ip_open_write(name,trunc,buf,bufsiz)
  692. char *name ;
  693. char *buf ;
  694. int trunc ;
  695. int bufsiz ;
  696. {
  697.    int fd ;
  698.    
  699.    if (name && *name == '\0')
  700.       fd = 1 ;    /* open stdout */
  701.    else
  702.       {
  703. #ifdef __TURBOC__
  704.       if (trunc)
  705.      fd = _creat(name,0) ;     /* create with no attribute bits sets */
  706.       else
  707.      fd = _open(name,O_WRONLY) ;
  708. #else
  709.       if (trunc) trunc = O_TRUNC ;
  710.       fd = open(name,O_WRONLY|O_BINARY|O_CREAT|trunc,S_IREAD|S_IWRITE) ;
  711. #endif
  712.       if (fd == -1)
  713.      return 0 ;
  714.       if (!trunc)
  715.      lseek(fd,0L,SEEK_END) ;
  716.       }
  717.    return ip_fdopen(fd,buf,bufsiz,bufsiz,1) ;
  718. }
  719.  
  720. /***********************************************/
  721.  
  722. IP_FILE *ip_open_read(name,buf,bufsiz)
  723. char *name ;
  724. char *buf ;
  725. int bufsiz ;
  726. {
  727.    int fd, siz ;
  728.  
  729. #ifdef __TURBOC__
  730.    if ((fd = _open(name,O_RDONLY)) != -1)
  731. #else
  732.    if ((fd = open(name,O_RDONLY | O_BINARY,0)) != -1)
  733. #endif
  734.       {
  735.       siz = read(fd,buf,bufsiz) ;
  736.       if (siz == -1)
  737.      return 0 ;
  738.       return ip_fdopen(fd,buf,siz,bufsiz,0) ;
  739.       }
  740.    else
  741.       return 0 ;
  742. }
  743.  
  744. /***********************************************/
  745.  
  746. int ip_flush(fp)
  747. IP_FILE *fp ;
  748. {
  749.    if (fp->write && fp->bufpos)
  750.       {
  751.       if (fp->bufpos > fp->buf_maxsize)
  752.      fp->bufpos = fp->buf_maxsize ;
  753.       if (write(fp->fd,fp->buf,fp->bufpos) == -1)
  754.      return -1 ;
  755.       fp->bufpos = 0 ;
  756.       }
  757.    return 0 ;       
  758. }
  759.  
  760. /***********************************************/
  761.  
  762. int ip_close(fp)
  763. IP_FILE *fp ;
  764. {
  765.    if (ip_flush(fp) == -1 || close(fp->fd) == -1)
  766.       return -1 ;
  767.    free(fp) ;
  768.    return 0 ;
  769. }
  770.  
  771. /***********************************************/
  772.  
  773. unsigned long ip_fgets(buf, max, fp)
  774. char *buf ;
  775. int max ;
  776. IP_FILE *fp ;
  777. {
  778.    unsigned long line_offset = fp->bufoffset + fp->bufpos ;
  779.    char *end ;
  780.    int len ;
  781.    int new_bufpos ;
  782.    char *fpbuf = fp->buf ;
  783.    int bufpos = fp->bufpos ;
  784.    
  785.    --max ;
  786.    if (bufpos + max < fp->bufsize)
  787.       {
  788.       end = (char *)memchr(fpbuf+bufpos,LINE_TERMINATOR,max) ;
  789.       if (end)
  790.      {
  791.      new_bufpos = (end-fpbuf) ;
  792.      len = new_bufpos++ - bufpos ;
  793.      /* eradicate rest of multi-character line terminator */
  794.      while (len > 0 && fpbuf[bufpos+len-1] <= ' ')
  795.         len-- ;
  796.      }
  797.       else
  798.      {
  799.      len = max ;
  800.      new_bufpos = bufpos + len ;
  801.      }
  802.       if (len)
  803.      memcpy(buf,fpbuf+bufpos,len) ;
  804.       buf[len] = '\0' ;
  805.       bufpos = new_bufpos ;
  806.       }
  807.    else
  808.       {
  809.       for (len = 1 ; len <= max ; len++)
  810.      {
  811.      *buf = fpbuf[bufpos++] ;
  812.      if (bufpos >= fp->bufsize)
  813.         {
  814.         if (fp->bufsize < fp->buf_maxsize)
  815.            {
  816.            fp->bufsize = bufpos = 0 ;
  817.            fpbuf[0] = '\0' ;  /* dummy value to ensure empty string */
  818.            }
  819.         else
  820.            {
  821.            fp->bufoffset += fp->buf_maxsize ;
  822.            fp->bufsize = read(fp->fd,fpbuf,fp->buf_maxsize) ;
  823.            bufpos = 0 ;
  824.            }
  825.         if (fp->bufsize <= 0)
  826.            {
  827.            line_offset = (unsigned long)-1 ; /* signal end of file */
  828.            if (*buf != LINE_TERMINATOR)
  829.           *buf++ = LINE_TERMINATOR;
  830.            break ;
  831.            }
  832.         }
  833.      if (*buf == LINE_TERMINATOR)
  834.         break ;
  835.      else
  836.         buf++ ;
  837.      }
  838.       if (len > max)       /* did we overflow before hitting EOL? */
  839.      *buf = '\0' ;       /* if yes, plug in the terminator */
  840.       else
  841.      /* eradicate rest of multi-character line terminator */
  842.      while (len-- > 0 && *buf <= ' ')
  843.         *buf-- = '\0' ;
  844.       }
  845.    fp->bufpos = bufpos ;
  846.    return line_offset ;
  847. }
  848.  
  849. /***********************************************/
  850.  
  851. int ip_write(buf, count, fp)
  852. char *buf ;
  853. int count ;
  854. IP_FILE *fp ;
  855. {
  856.    if (fp->bufpos + count < fp->buf_maxsize)
  857.       {
  858.       memcpy(fp->buf+fp->bufpos,buf,count) ;
  859.       fp->bufpos += count ;
  860.       }
  861.    else
  862.       while (count > 0)
  863.      {
  864.      int partial = fp->buf_maxsize - fp->bufpos ;
  865.  
  866.      if (count < partial)
  867.         partial = count ;
  868.      memcpy(fp->buf+fp->bufpos,buf,partial) ;
  869.      buf += partial ;
  870.      fp->bufpos += partial ;
  871.      count -= partial ;
  872.      if (fp->bufpos >= fp->buf_maxsize && ip_flush(fp) == -1)
  873.            return -1 ;
  874.      }
  875.    return 0 ;
  876. }
  877.  
  878. /***********************************************/
  879.  
  880. #define indent_line(fp) if(indent_string)ip_write(indent_string,indent_len,fp)
  881.  
  882. /***********************************************/
  883.  
  884. void indent_to(where,fp)
  885. int where ;
  886. IP_FILE *fp ;
  887. {
  888.    where += indent ;
  889.    while (where >= 8)
  890.       {
  891.       ip_putc('\t',fp) ;
  892.       where -= 8 ;
  893.       }
  894.    if (where)
  895.       ip_write("        ",where,fp) ;
  896. }
  897.  
  898. /***********************************************/
  899.  
  900. void put_line(fp,len)
  901. IP_FILE *fp ;
  902. int len ;
  903. {
  904.    static char line[8] = { 196, 196, 196, 196, 196, 196, 196, 196 } ;
  905.  
  906.    if (IBM_chars)
  907.       {
  908.       while (len >= 8)
  909.      {
  910.      ip_write(line,8,fp) ;
  911.      len -= 8 ;
  912.      }
  913.       if (len)
  914.      ip_write(line,len,fp) ;
  915.       }
  916.    else
  917.       {
  918.       while (len >= 8)
  919.      {
  920.      ip_write("--------",8,fp) ;
  921.      len -= 8 ;
  922.      }
  923.       if (len)
  924.      ip_write("--------",len,fp) ;
  925.       }
  926. }
  927.  
  928. /***********************************************/
  929.  
  930. void HPPCL_put_line(fp,len)
  931. IP_FILE *fp ;
  932. int len ;
  933. {
  934.    ip_putlit(HPPCL_IBM_LN_A,fp) ;
  935.    ip_puts(itoa((len * 25), num, 10),fp) ;
  936.    ip_putlit(HPPCL_IBM_LN_B,fp) ;
  937. }
  938.  
  939. /***********************************************/
  940.  
  941. void HPPCL_set_typeface(fp,typeface)
  942. IP_FILE *fp ;
  943. char *typeface ;
  944. {
  945.    ip_putlit(HPPCL_FONT_ON_A,fp) ;
  946.    if (typeface)
  947.       ip_puts(typeface,fp) ;
  948.    else
  949.       ip_putlit("8",fp) ;
  950.    ip_putlit(HPPCL_FONT_ON_B,fp) ;
  951. }
  952.  
  953. /***********************************************/
  954.  
  955. int is_keyword(s,keys,numkeys)
  956. char *s ;
  957. KEYWORDS *keys ;
  958. unsigned int numkeys ;
  959. {
  960.    register int cmp ;
  961.    register unsigned int i ;
  962.    KEYWORDS *currkey ;
  963.    int firstchar = *s ;
  964.  
  965.    do {
  966.       i = numkeys / 2 ;
  967.       currkey = &keys[i] ;
  968.       cmp = (firstchar - currkey->name[0]) ;
  969.       if (cmp == 0)
  970.          cmp = memcmp(s,currkey->name,currkey->length) ;
  971.       if (cmp < 0)
  972.      numkeys = i ;
  973.       else if (cmp > 0)
  974.      {
  975.      keys = currkey+1 ;
  976.      numkeys -= i+1 ;
  977.      }
  978.       else
  979.      return TRUE ;
  980.       } while (numkeys) ;
  981.    return FALSE ;
  982. }
  983.  
  984. /***********************************************/
  985.  
  986. void output_line(line,fp)
  987. char *line ;
  988. IP_FILE *fp ;
  989. {
  990.    if (*line)
  991.       {
  992.       int pos = 0 ;
  993.       int len = strlen(line) ;
  994.       
  995.       indent_line(fp) ;
  996.       if (boldface)
  997.      {
  998.      if (start_of_entry(line) || start_of_table(line))
  999.         {
  1000.         if (printer_bold)
  1001.            {
  1002.            ip_putcstr(&printer->bold_on,fp) ;
  1003.            ip_write(line,len,fp) ;
  1004.            ip_putcstr(&printer->bold_off,fp) ;
  1005.            newline(fp) ;
  1006.            return ;
  1007.            }
  1008.         else
  1009.            {
  1010.            ip_write(line,len,fp) ;
  1011.            ip_putc('\r',fp) ;
  1012.            indent_line(fp) ;
  1013.            }
  1014.         }
  1015.      else if (section_start(line))
  1016.         {
  1017.         pos = (char *)memchr(line,':',len) - line ;
  1018.         if (printer_bold)
  1019.            {
  1020.            ip_putcstr(&printer->bold_on,fp) ;
  1021.            ip_write(line,pos,fp) ;
  1022.            ip_putcstr(&printer->bold_off,fp) ;
  1023.            line += pos ;       /* adjust because no longer at left edge */
  1024.            }
  1025.         else
  1026.            {
  1027.            ip_write(line,pos,fp) ;
  1028.            ip_putc('\r',fp) ;
  1029.            indent_line(fp) ;
  1030.            }
  1031.         }
  1032.      } /* boldface */
  1033.       if (indent & 7)  /* indenting by other than a multiple of 8 ? */
  1034.      {
  1035.      while (*line)
  1036.         {
  1037.         if (*line == '\t')
  1038.            {
  1039.            ip_write("        ",8-(pos&7),fp) ;
  1040.            pos = 0 ;   /* absolute column doesn't matter, only mod 8 */
  1041.            }
  1042.         else
  1043.            {
  1044.            ip_putc(*line,fp) ;
  1045.            pos++ ;
  1046.            }
  1047.         line++ ;
  1048.         }
  1049.      }
  1050.       else
  1051.      ip_write(line,len,fp) ;
  1052.       }
  1053.    newline(fp) ;
  1054. }
  1055.  
  1056. /***********************************************/
  1057.  
  1058. void get_raw_line(buf)
  1059. char *buf ;
  1060. {
  1061.    IP_FILE *in ;
  1062.    
  1063.    buf[0] = '\0' ;
  1064.    if (out_of_files)
  1065.       return ;
  1066.    current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1067.    if (current_line_offset == (unsigned long)-1)
  1068.       if (multi_file)
  1069.      {
  1070.      offset_adjust += lseek(infile->fd,0L,SEEK_END) ;
  1071.      input_file[input_file_namelen-1]++ ;
  1072.      ip_close(infile) ;
  1073.      if ((in = ip_open_read(input_file,infile_buf,sizeof(infile_buf)))
  1074.            != NULL)
  1075.         {
  1076.         infile = in ;
  1077.         current_line_offset = ip_fgets(buf,MAXLINE,infile) ;
  1078.         }
  1079.      else
  1080.         {
  1081.         out_of_files = TRUE ;
  1082.         return ;
  1083.         }
  1084.      }
  1085.       else
  1086.      out_of_files = TRUE ;
  1087. }
  1088.  
  1089. /***********************************************/
  1090.  
  1091. int unwanted_section(buf)
  1092. char *buf ;
  1093. {
  1094.    int found ;
  1095.    char str[MAXLINE] ;
  1096.    FILT_LIST *p ;
  1097.  
  1098.    if (start_of_entry(buf)) /* is it an interrupt entry? */
  1099.       {
  1100.       strcpy(str,buf) ;
  1101.       (void) strupr(str) ;
  1102.       /* section is unwanted if *any* exclude string matches */
  1103.       for (p = excludes ; p ; p = p->next)
  1104.      {
  1105.      if (p->str && strstr(str, p->str) != NULL)
  1106.         return TRUE ;
  1107.      }
  1108.       /* if still wanted, set to TRUE if *no* include string matches */
  1109.       found = FALSE ;
  1110.       for (p = includes ; p ; p = p->next)
  1111.      {
  1112.      if (p->str && strstr(str, p->str) != NULL)
  1113.         {
  1114.         found = TRUE ;
  1115.         break ;
  1116.         }
  1117.      }
  1118.       if (!found)
  1119.      return TRUE ;
  1120.       }
  1121.    return FALSE ;
  1122. }
  1123.  
  1124. /***********************************************/
  1125.  
  1126. void get_line(buf)
  1127. char *buf ;
  1128. {
  1129.    static char next_line[MAXLINE] ;
  1130.    static int readahead = FALSE ;
  1131.  
  1132.    /* get the next line from the file, skipping unwanted entries */
  1133.    if (readahead)
  1134.       {
  1135.       strcpy(buf,next_line) ;
  1136.       readahead = FALSE ;
  1137.       }
  1138.    else
  1139.       {
  1140.       do {
  1141.      get_raw_line(buf) ;
  1142.      } while (!include_index_lines && index_line(buf)) ;
  1143.       if (section_file_start(buf))
  1144.      do {
  1145.         get_raw_line(buf) ;
  1146.         } while (buf[0] && !divider_line(buf)) ;
  1147.       if (do_filter)
  1148.      {
  1149.      /* if we read a divider line while filtering, we have to look ahead */
  1150.      strcpy(next_line,buf);
  1151.      while (next_line[0] && divider_line(next_line))
  1152.         {
  1153.         strcpy(buf,next_line) ; /* we may be returning the divider */
  1154.         get_raw_line(next_line) ;
  1155.         if (unwanted_section(next_line))
  1156.            {
  1157.            while (!divider_line(next_line))
  1158.           get_raw_line(next_line) ;
  1159.            }
  1160.         else /* section is wanted, so return divider and then next line */
  1161.            readahead = TRUE ;
  1162.         }
  1163.      }
  1164.       }
  1165. }
  1166.  
  1167. /***********************************************/
  1168.  
  1169. void fill_buffer(lines,lines_per_page)
  1170. int lines, lines_per_page ;
  1171. {
  1172.    int i ;
  1173.  
  1174.    /* copy remainder, if any, from last page to top of current page */
  1175.    if (lines)
  1176.       for (i = lines ; i < lines_per_page ; i++)
  1177.      {
  1178.      strcpy(buffer[i-lines], buffer[i]) ;
  1179.      line_offsets[i-lines] = line_offsets[i] ;
  1180.      }
  1181.    else
  1182.       lines = lines_per_page ;
  1183.    for (i = lines_per_page - lines ; i < lines_per_page ; i++)
  1184.       {
  1185.       get_line(buffer[i]) ;
  1186.       line_offsets[i] = current_line_offset + offset_adjust ;
  1187.       }
  1188. }
  1189.  
  1190. /***********************************************/
  1191.  
  1192. int find_page_break(lines)
  1193. int lines ;
  1194. {
  1195.    int i ;
  1196.    char *buf ;
  1197.  
  1198.    for (i = 0 ; i < widow_length ; i++)
  1199.       {
  1200.       buf = buffer[lines-i-1] ;
  1201.       if (buf[0] == '\0' || divider_line(buf))
  1202.      return lines - i ;
  1203.       else if (section_start(buf))
  1204.      return lines - i - 1 ;
  1205.       }
  1206.    return lines ;
  1207. }
  1208.  
  1209. /***********************************************/
  1210.  
  1211. int summarize(line, pages_printed)
  1212. int line, pages_printed ;
  1213. {
  1214.    char *s, reg ;
  1215.    int i ;
  1216.    int max_descrip ;
  1217.    int len, numlen ;
  1218.  
  1219.    s = buffer[line] ;
  1220.    if (start_of_entry(s))
  1221.       {
  1222.       memcpy(summary_line," -- -- -- ",10) ;
  1223.       summary_line[1] = s[4] ;     /* output interrupt number */
  1224.       summary_line[2] = s[5] ;
  1225.       len = 4 ;
  1226.       s = buffer[line+1] ;
  1227.       while (*s && isspace(*s))
  1228.      s++ ;
  1229.       if (*s == 'A')
  1230.      {
  1231.      reg = s[1] ;
  1232.      while (*s && *s != '=')
  1233.         s++ ;
  1234.      s++ ;        /* skip the equal sign */
  1235.      while (*s && isspace(*s))
  1236.         s++ ;    /* skip the space between equal sign and number */
  1237.      if (isxdigit(*s) && isxdigit(s[1]))
  1238.         {
  1239.         if (reg == 'L')
  1240.            len += 3 ;
  1241.         summary_line[len++] = *s++ ;
  1242.         summary_line[len++] = *s++ ;
  1243.         if (reg == 'X')
  1244.            {
  1245.            len++ ;
  1246.            summary_line[len++] = *s++ ;
  1247.            summary_line[len] = *s ;
  1248.            }
  1249.         }
  1250.      }
  1251.       len = 10 ;
  1252.       if (page_numbers)
  1253.      {
  1254.      itoa(pages_printed,num,10) ;
  1255.      numlen = strlen(num) ;
  1256.      for (i = numlen ; i < 3 ; i++)
  1257.         summary_line[len++] = ' ' ;
  1258.      memcpy(summary_line+len,num,numlen) ;
  1259.      len += numlen ;
  1260.      summary_line[len++] = ' ' ;
  1261.      }
  1262.       s = buffer[line] + 7 ;    /* find function description */
  1263.       if (*s && *s != '-')    /* does the heading contain flags? */
  1264.      {
  1265.      while (*s && !isspace(*s))
  1266.         summary_line[len++] = *s++ ;
  1267.      summary_line[len++] = '>' ;
  1268.      summary_line[len++] = ' ' ;
  1269.      while (*s && *s != '-')
  1270.         s++ ;
  1271.      }
  1272.       while (*s && !isspace(*s))
  1273.      s++ ;
  1274.       while (*s && isspace(*s))
  1275.      s++ ;
  1276.       max_descrip = (page_width > sizeof(summary_line)-1) ? 
  1277.                    sizeof(summary_line)-1 : page_width ;
  1278.       while (len < max_descrip && *s)
  1279.      summary_line[len++] = *s++ ;
  1280.       summary_line[len] = '\0' ;
  1281.       summary_line_len = len ;
  1282.       return 1 ;
  1283.       }
  1284.    else
  1285.       return 0 ;
  1286. }
  1287.  
  1288. /***********************************************/
  1289.  
  1290. void start_format(line)
  1291. char *line ;
  1292. {
  1293.    indent_line(formats) ;
  1294.    (*printer->put_line)(formats,79) ;
  1295.    newline(formats) ;
  1296.    indent_line(formats) ;
  1297.    ip_puts(summary_line,formats) ;
  1298.    newline(formats) ;
  1299.    indent_line(formats) ;
  1300.    ip_putc('\t',formats) ;
  1301.    ip_puts(line+10,formats) ;
  1302.    newline(formats) ;
  1303.    echo_format = TRUE ;
  1304. }
  1305.  
  1306. /***********************************************/
  1307.  
  1308. void show_offset(line,fp)
  1309. int line ;
  1310. IP_FILE *fp ;
  1311. {
  1312.    char offset_string[12] ;
  1313.    int len ;
  1314.    
  1315.    ultoa(line_offsets[line],offset_string,16) ;
  1316.    len = strlen(offset_string) ;
  1317.    ip_write("00000000",8-len,fp) ;
  1318.    ip_write(offset_string,len,fp) ;
  1319. }
  1320.  
  1321. /***********************************************/
  1322.  
  1323. void add_table(i)
  1324. int i ;
  1325. {
  1326.    char firstchar ;
  1327.    char num[6] ;
  1328.    char *end ;
  1329.    int len ;
  1330.    int summary_width ;
  1331.    char found = FALSE ;
  1332.    
  1333.    prev_table++ ;
  1334.    firstchar = buffer[i][0] ;
  1335.    if (firstchar == 'C' || firstchar == 'V')  /* Call.. or Values... ? */
  1336.       {
  1337.       if (i > 0 && buffer[i-1][0] == '(')
  1338.      {
  1339.      memcpy(num,buffer[i-1]+7,4) ;
  1340.      num[4] = '\0' ;
  1341.      len = 4 ;
  1342.      found = TRUE ;
  1343.      }
  1344.       }
  1345.    else if (firstchar == 'B' || firstchar == 'F') /* Bitfields.. or Format..? */
  1346.       {
  1347.       end = strrchr(buffer[i+1]+7,')') ;   /* rule out Bit(s) as only match */
  1348.       if (end)
  1349.      {
  1350.      memcpy(num,end-4,4) ;
  1351.      num[4] = '\0' ;
  1352.      len = 4 ;
  1353.      found = TRUE ;
  1354.      }
  1355.       }
  1356.    if (!found)
  1357.       {
  1358.       itoa(prev_table,num,10) ;
  1359.       len = strlen(num) ;
  1360.       }
  1361.    indent_line(tables) ;
  1362.    if (show_offsets)
  1363.       show_offset(i,tables) ;
  1364.    ip_write(" 0000",5-len,tables) ;
  1365.    ip_write(num,len,tables);
  1366.    if (page_numbers)
  1367.       {
  1368.       summary_width = 13 ;
  1369.       while (summary_line[summary_width] != ' ')
  1370.      summary_width++ ;
  1371.       summary_width++ ;    /* include the blank we found */
  1372.       }
  1373.    else
  1374.       summary_width = 10 ;
  1375.    ip_write(summary_line,summary_width,tables) ;
  1376.    len = strlen(buffer[i])-1 ;
  1377.    if (len > page_width - summary_width - 5)
  1378.       len = page_width - summary_width - 5 ;
  1379.    ip_write(buffer[i],len,tables) ;
  1380.    newline(tables) ;
  1381. }
  1382.  
  1383. /***********************************************/
  1384.  
  1385. int make_description(desc,line)
  1386. char *desc ;
  1387. int line ;
  1388. {
  1389.    char *start = desc ;
  1390.    
  1391.    summarize(line,pages_printed) ;
  1392.    memcpy(desc,"INT ", 4) ;
  1393.    desc += 4 ;
  1394.    *desc++ = summary_line[1] ;
  1395.    *desc++ = summary_line[2] ;
  1396.    if (summary_line[4] != '-')
  1397.       {
  1398.       memcpy(desc,", AH=", 5) ;
  1399.       desc += 5 ;
  1400.       *desc++ = summary_line[4] ;
  1401.       *desc++ = summary_line[5] ;
  1402.       }
  1403.    if (summary_line[7] != '-')
  1404.       {
  1405.       memcpy(desc,", AL=", 5) ;
  1406.       desc += 5 ;
  1407.       *desc++ = summary_line[7] ;
  1408.       *desc++ = summary_line[8] ;
  1409.       }
  1410.    *desc = '\0' ;
  1411.    return (desc-start)+1 ;
  1412. }
  1413.  
  1414. /***********************************************/
  1415.  
  1416. char *determine_heading(last)
  1417. int last ;
  1418. {
  1419.    int i ;
  1420.    static char heading[MAXLINE] ;
  1421.    char save[25] ;
  1422.    char num[10] ;
  1423.  
  1424.    /* ugly hack to keep the combination of -H and -T from showing wrong page */
  1425.    /* numbers for tables--copy last summary line from previous page to safe */
  1426.    /* place before processing current page, then restore it */
  1427.    memcpy(save,summary_line,sizeof(save)) ;
  1428.    if (start_of_entry(buffer[0]))
  1429.       {
  1430.       header_first.len = make_description(header_first.desc,0) ;
  1431.       header_first.part = 1 ;
  1432.       header_first.first_on_page = TRUE ;
  1433.       }
  1434.    else if (header_last.part == 0)  /* very first entry? */
  1435.       {
  1436.       for (i = 0 ; i < last ; i++)
  1437.      if (start_of_entry(buffer[i]))
  1438.         {
  1439.         header_first.len = make_description(header_first.desc,i) ;
  1440.         header_first.part = 1 ;
  1441.         header_first.first_on_page = TRUE ;
  1442.         break ;
  1443.         }
  1444.       }
  1445.    else
  1446.       {
  1447.       header_first.len = header_last.len ;
  1448.       memcpy(header_first.desc,header_last.desc,header_last.len) ;
  1449.       header_first.part = header_last.part + 1 ;
  1450.       header_first.first_on_page = FALSE ;
  1451.       }
  1452.    /* assume entry spans entire page */
  1453.    header_last.len = header_first.len ;
  1454.    memcpy(header_last.desc,header_first.desc,header_first.len) ;
  1455.    header_last.part = header_first.part ;
  1456.    header_last.first_on_page = header_first.first_on_page ;
  1457.    /* find last entry on page */
  1458.    if (header_first.part > 0)
  1459.       {
  1460.       for (i = last-1 ; i > 0 ; i--)
  1461.      if (start_of_entry(buffer[i]))
  1462.         {
  1463.         header_last.len = make_description(header_last.desc,i) ;
  1464.         header_last.part = 1 ;
  1465.         header_last.first_on_page = FALSE ;
  1466.         break ;
  1467.         }
  1468.       memcpy(heading,header_first.desc,header_first.len) ;
  1469.       if (header_first.part > 1)
  1470.      {
  1471.      strcat(heading," (Part ") ;
  1472.      strcat(heading,itoa(header_first.part,num,10)) ;
  1473.      strcat(heading,")") ;
  1474.      }
  1475.       if (memcmp(header_first.desc,header_last.desc,header_last.len) != 0 ||
  1476.       header_first.part != header_last.part)
  1477.      {
  1478.      strcat(heading," to ") ;
  1479.      strcat(heading,header_last.desc) ;
  1480.      if (header_last.part > 1)
  1481.         {
  1482.         strcat(heading," (Part ") ;
  1483.         strcat(heading,itoa(header_last.part,num,10)) ;
  1484.         strcat(heading,")") ;
  1485.         }
  1486.      }
  1487.       memcpy(summary_line,save,sizeof(save)) ;
  1488.       return heading ; 
  1489.       }
  1490.    else /* no headings yet */
  1491.       {
  1492.       memcpy(summary_line,save,sizeof(save)) ;
  1493.       return NULL ;
  1494.       }
  1495. }
  1496.  
  1497. /***********************************************/
  1498.  
  1499. void print_buffer(last,body_lines,lines_per_page,total_lines,use_FF)
  1500. int last, body_lines, lines_per_page, total_lines ;
  1501. int use_FF ;
  1502. {
  1503.    int i, len ;
  1504.    int headpos ;
  1505.    int print_this_page = (pages_printed>=first_page && pages_printed<=last_page);
  1506.    
  1507.    pages_printed++ ;
  1508.    if (do_headers)
  1509.       {
  1510.       char *heading ;
  1511.       
  1512.       if ((heading = determine_heading(last)) != NULL)
  1513.      {
  1514.      if (print_this_page)
  1515.         {
  1516.         len = strlen(heading) ;
  1517.         headpos = 40-len/2 ;
  1518.         indent_to(headpos,outfile) ;
  1519.         if (boldface)
  1520.            {
  1521.            if (printer_bold)
  1522.           {
  1523.           ip_putcstr(&printer->bold_on,outfile) ;
  1524.           ip_write(heading,len,outfile) ;
  1525.           ip_putcstr(&printer->bold_off,outfile) ;
  1526.           }
  1527.            else
  1528.           {
  1529.           ip_write(heading,len,outfile) ;
  1530.           ip_putc('\r',outfile) ;
  1531.           indent_to(headpos,outfile) ;
  1532.           ip_write(heading,len,outfile) ;
  1533.           }
  1534.            }
  1535.         else
  1536.            ip_write(heading,len,outfile) ;
  1537.         }
  1538.      }
  1539.       newline(outfile) ;
  1540.       newline(outfile) ;
  1541.       }
  1542.    for (i = 0 ; i < last ; i++)
  1543.       {
  1544.       if (print_this_page)
  1545.      {
  1546.      char *line = buffer[i] ;
  1547.      if (*line)
  1548.         {
  1549.         if (!keep_divider_lines && divider_line(line))
  1550.            {
  1551.            indent_line(outfile) ;
  1552.            (*printer->put_line)(outfile,79) ;
  1553.            newline(outfile) ;
  1554.            echo_format = FALSE ;
  1555.            }
  1556.         else
  1557.            {
  1558.            output_line(line, outfile) ;
  1559.            if (echo_format)
  1560.           output_line(line,formats) ;
  1561.            }
  1562.         }
  1563.      else
  1564.         {
  1565.         newline(outfile) ;
  1566.         echo_format = FALSE ;
  1567.         }
  1568.      }
  1569.       /* need summary lines if doing summary, formats, or table index */
  1570.       if (need_summary)
  1571.      {
  1572.      if (summarize(i,pages_printed) && do_summary && summary)
  1573.         {
  1574.         if (show_offsets)
  1575.            show_offset(i,summary) ;
  1576.         ip_write(summary_line,summary_line_len,summary) ;
  1577.         newline(summary) ;
  1578.         }
  1579.      if (do_formats && memcmp(buffer[i],"Format ",7) == 0)
  1580.         start_format(buffer[i]) ;
  1581.      if (do_tables && start_of_table(buffer[i]))
  1582.         add_table(i) ;
  1583.      }
  1584.       }
  1585.    if (print_this_page)
  1586.       {
  1587.       if (page_numbers)
  1588.      {
  1589.      for (i = last ; i <= body_lines ; i++)
  1590.         newline(outfile) ;
  1591.      itoa(pages_printed, num, 10) ;
  1592.      i = strlen(num) ;
  1593.      if (!duplex)
  1594.         indent_to(38-i/2,outfile) ;
  1595.      else if (pages_printed & 1)        /* odd-numbered page? */
  1596.         indent_to(75-i/2,outfile) ;
  1597.      else
  1598.         indent_to(2,outfile) ;
  1599.      ip_putlit("- ", outfile) ;
  1600.      ip_write(num, i, outfile) ;
  1601.      ip_putlit(" -", outfile) ;
  1602.      newline(outfile) ;
  1603.      }
  1604.       if (use_FF)
  1605.      ip_putc('\f',outfile) ;
  1606.       else
  1607.      for (i = page_numbers?lines_per_page:last ; i<total_lines ; i++)
  1608.         newline(outfile) ;
  1609.       if (duplex)
  1610.      {
  1611.      if (pages_printed & 1)           /* next page even or odd? */
  1612.         ip_putcstr(&printer->marginl, outfile) ;    /* even page */
  1613.      else
  1614.         ip_putcstr(&printer->marginr, outfile) ;    /* odd page */
  1615.      }
  1616.       }
  1617. }
  1618.  
  1619. /***********************************************/
  1620.  
  1621. void display_printers()
  1622. {
  1623.    int i ;
  1624.    
  1625.    ip_putlit("Valid printer names are:",err) ;
  1626.    newline(err) ;
  1627.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1628.       {
  1629.       ip_putc('\t',err) ;
  1630.       ip_puts(printers[i].name,err) ;
  1631.       newline(err) ;
  1632.       }
  1633.    ip_putlit("When entering the printer name, use either a dash or an",err) ;
  1634.    newline(err) ;
  1635.    ip_putlit("underscore in place of blanks.  Case is ignored, and the",err) ;
  1636.    newline(err) ;
  1637.    ip_putlit("name may be abbreviated to the shortest unique prefix.",err) ;
  1638.    newline(err) ;
  1639.    exit(1) ;
  1640. }
  1641.  
  1642. /***********************************************/
  1643.  
  1644. void select_printer(name)
  1645. char *name ;
  1646. {
  1647.    int i, len, prt = -1 ;
  1648.    
  1649.    len = strlen(name) ;
  1650.    for (i = 0 ; i < len ; i++)        /* convert dashes and underscores to blanks */
  1651.       if (name[i] == '-' || name[i] == '_')
  1652.      name[i] = ' ' ;
  1653.    for (i = 0 ; i < NUM_PRINTERS ; i++)
  1654.       if (strnicmp(name,printers[i].name,len) == 0)
  1655.      if (prt == -1)
  1656.         prt = i ;
  1657.      else
  1658.         fatal("Ambiguous printer name!  Use -P? to list printers.") ;
  1659.    if (prt == -1)
  1660.       fatal("Unknown printer name!  Use -P? to list printers.") ;
  1661.    else
  1662.       printer = &printers[prt] ;
  1663. }
  1664.  
  1665. /***********************************************/
  1666.  
  1667. FILT_LIST *add_filter_info(list,str)
  1668. FILT_LIST *list ;
  1669. char *str ;
  1670. {
  1671.    FILT_LIST *newfilt ;
  1672.    int len = strlen(str)+1 ;
  1673.    
  1674.    if ((newfilt = (FILT_LIST *)malloc(sizeof(struct filter_list)+len))
  1675.       != NULL)
  1676.       {
  1677.       newfilt->next = list ;
  1678.       memcpy(newfilt->str,str,len) ;
  1679.       strupr(newfilt->str) ;
  1680.       }
  1681.    else
  1682.       fatal("out of memory") ;
  1683.    return newfilt ;
  1684. }
  1685.  
  1686. /***********************************************/
  1687.  
  1688. void build_filter_lists(file)
  1689. char *file ;
  1690. {
  1691.    IP_FILE *fp ;
  1692.    char buf[MAXLINE] ;
  1693.    int len ;
  1694.    long result ;
  1695.  
  1696.    if ((fp = ip_open_read(file,filter_buf,sizeof(filter_buf))) == NULL)
  1697.       {
  1698.       warning("unable to open filtering file, will print entire list.") ;
  1699.       do_filter = FALSE ;
  1700.       }
  1701.    else /* OK, file is open, so start reading */
  1702.       {
  1703.       do {
  1704.      buf[0] = '\0' ;
  1705.      result = ip_fgets(buf, sizeof(buf), fp) ;
  1706.      len = strlen(buf) ;
  1707.      if (len > 1)
  1708.         {
  1709.         switch (buf[0])
  1710.            {
  1711.            case '+':
  1712.           includes = add_filter_info(includes,buf+1) ;
  1713.           break ;
  1714.            case '-':
  1715.           excludes = add_filter_info(excludes,buf+1) ;
  1716.           break ;
  1717.            case '#':        /* comment lines */
  1718.            default:
  1719.           break ;
  1720.            }
  1721.         }
  1722.      } while (result != -1) ;
  1723.       ip_close(fp) ;
  1724.       do_filter = TRUE ;
  1725.       }
  1726. }
  1727.  
  1728. /***********************************************/
  1729.  
  1730. void write_summary_header(fp,title,show_offsets,show_table)
  1731. IP_FILE *fp ;
  1732. char *title ;
  1733. int show_offsets, show_table ;
  1734. {
  1735.    /* set up the printer */
  1736.    ip_putcstr(&printer->init1,fp) ;
  1737.    ip_putcstr(&printer->init2,fp) ;
  1738.    ip_putcstr(&printer->marginc,fp) ;
  1739.    /* now start writing the actual header */
  1740.    indent_to(show_offsets?8:0,fp) ;
  1741.    ip_putlit("\t\t\t\t",fp) ;
  1742.    ip_puts(title,fp) ;
  1743.    newline(fp) ;
  1744.    indent_to(show_offsets?8:0,fp) ;
  1745.    ip_putlit("\t\t\t\t",fp) ;
  1746.    (*printer->put_line)(fp,strlen(title)) ;
  1747.    newline(fp) ;
  1748.    newline(fp) ;
  1749.    indent_line(fp) ;
  1750.    if (show_offsets)
  1751.       ip_putlit("Offset  ", fp) ;
  1752.    if (show_table)
  1753.       ip_putlit("Tbl# ",fp) ;
  1754.    ip_putlit("INT AH AL", fp) ;
  1755.    if (page_numbers)
  1756.       ip_putlit(" Page", fp) ;
  1757.    ip_putlit("\t\t\tDescription", fp) ;
  1758.    newline(fp) ;
  1759.    indent_line(fp) ;
  1760.    (*printer->put_line)(fp,page_width+(show_offsets?8:0)) ;
  1761.    newline(fp) ;
  1762. }
  1763.  
  1764. /***********************************************/
  1765.  
  1766. static void reset_printer_and_close(fp)
  1767. IP_FILE *fp ;
  1768. {
  1769.    ip_putcstr(&printer->term1,fp) ;
  1770.    ip_putcstr(&printer->term2,fp) ;
  1771.    ip_close(fp) ;
  1772. }
  1773.  
  1774. /***********************************************/
  1775.  
  1776. int _Cdecl main(argc,argv)
  1777. int argc ;
  1778. char *argv[] ;
  1779. {
  1780.    int lines_per_page = -1 ;
  1781.    int total_lines = -1 ;
  1782.    int use_FF = TRUE ;
  1783.    int last_line ;
  1784.    int body_lines ;
  1785.    char *typeface = NULL ;
  1786.    char *summary_file = NULL ;
  1787.    char *table_file = NULL ;
  1788.    char *formats_file = NULL ;
  1789.    char *filter_file = NULL ;
  1790.    char *last_page_num ;
  1791.  
  1792.    err = ip_fdopen(2,stderr_buf,sizeof(stderr_buf),sizeof(stderr_buf),1) ;
  1793.    ip_putlit("INTPRINT v", err) ;
  1794.    ip_putlit(VERSION, err) ;
  1795.    ip_putlit(" by Ralf Brown and others.  Donated to the Public Domain.",err) ;
  1796.    newline(err) ;
  1797.    ip_flush(err) ;
  1798.    if (argc == 1 && isatty(0))
  1799.       usage() ;      /* give help if invoked with no args and keybd input */
  1800.    while (argc >= 2 && argv[1][0] == '-')
  1801.       {
  1802.       switch (argv[1][1])
  1803.      {
  1804.      case 'B':
  1805.         printer_bold = TRUE ;
  1806.         /* fall through to -b */
  1807.      case 'b':
  1808.         boldface = TRUE ;
  1809.         break ;
  1810.      case 'd':
  1811.         duplex = TRUE ;
  1812.         break ;
  1813.      case 'e':
  1814.         indent = 8 ;
  1815.         page_width = 87 ;  /* 96 - indent - 1 right margin */
  1816.         break ;
  1817.      case 'f':
  1818.         formats_file = argv[1]+2 ;
  1819.         break ;
  1820.      case 'F':
  1821.         filter_file = argv[1]+2 ;
  1822.         break ;
  1823.      case 'H':   /* page headers */
  1824.         do_headers = TRUE ;
  1825.         break ;
  1826.      case 'i':
  1827.         indent = atoi(argv[1]+2) ;
  1828.         break ;
  1829.      case 'I':
  1830.         IBM_chars = TRUE ;
  1831.         break ;
  1832.      case 'k':
  1833.         keep_divider_lines = TRUE ;
  1834.         break ;
  1835.      case 'l':
  1836.         lines_per_page = atoi(argv[1]+2) ;
  1837.         break ;
  1838.      case 'L':
  1839.         total_lines = atoi(argv[1]+2) ;
  1840.         break ;
  1841.      case 'm':
  1842.         multi_file = TRUE ;
  1843.         break ;
  1844.      case 'n':
  1845.         pages_printed = atoi(argv[1]+2) ;
  1846.         break ;
  1847.      case 'P':
  1848.         if (argv[1][2] == '?')
  1849.            display_printers() ;
  1850.         else
  1851.            select_printer(argv[1]+2) ;
  1852.         break ;
  1853.      case 'p':
  1854.         page_numbers = TRUE ;
  1855.         break ;
  1856.      case 'r':
  1857.         first_page = atoi(argv[1]+2) ;
  1858.         last_page_num = strchr(argv[1]+2, ':') ;
  1859.         last_page = last_page_num ? atoi(last_page_num+1) : 0 ;
  1860.         if (last_page == 0)
  1861.            last_page = ~0 ;
  1862.         break ;
  1863.      case 's':
  1864.         summary_file = argv[1]+2 ;
  1865.         break ;
  1866.      case 't':
  1867.         typeface = argv[1]+2 ;
  1868.         break ;
  1869.      case 'T':
  1870.         table_file = argv[1]+2 ;
  1871.         break ;
  1872.      case 'V':
  1873.         show_offsets = IBM_chars = TRUE ;
  1874.         break ;
  1875.      case 'w':
  1876.         widow_length = atoi(argv[1]+2) ;
  1877.         break ;
  1878.      case 'x':
  1879.         include_index_lines = TRUE ;
  1880.         break ;
  1881.      default:
  1882.         usage() ;
  1883.      }
  1884.       argv++ ;
  1885.       argc-- ;
  1886.       }
  1887.    if (printer == NULL)
  1888.       select_printer("default") ;
  1889.    /* apply any necessary overrides to parameters */
  1890.    if (printer->indent != -1)
  1891.       indent = printer->indent ;
  1892.    if (lines_per_page < 0)
  1893.       lines_per_page = printer->lines_per_page ;
  1894.    if (total_lines <= 0)
  1895.       total_lines = printer->page_length ;
  1896.    if (page_width <= 0)
  1897.       page_width = printer->page_width ;
  1898.    if (show_offsets && page_width < 80)
  1899.       page_width = 80 ;
  1900.    if (printer->flag)
  1901.       *(printer->flag) = TRUE ;
  1902.    if (cstrlen(&printer->bold_on) == 0)     /* control sequences for bold? */
  1903.       printer_bold = FALSE ;        /* if not, don't try to use them */
  1904.    /* build the indent string */
  1905.    if (indent)
  1906.       {
  1907.       char *t ;
  1908.       int ind = indent ;
  1909.  
  1910.       indent_len = indent/8 + indent%8 ;
  1911.       t = indent_string = (char *)malloc(indent_len+1) ;
  1912.       while (ind >= 8)
  1913.      {
  1914.      *t++ = '\t' ;
  1915.      ind -= 8 ;
  1916.      }
  1917.       while (ind > 0)
  1918.      {
  1919.      *t++ = ' ' ;
  1920.      ind-- ;
  1921.      }
  1922.       }
  1923.    /* open the summary file, if any */
  1924.    if (summary_file && *summary_file)
  1925.       if ((summary = ip_open_write(summary_file,!pages_printed,summary_buf,
  1926.                    sizeof(summary_buf)))
  1927.         != NULL)
  1928.      do_summary = TRUE ;
  1929.       else
  1930.      warning("unable to open summary file") ;
  1931.    /* open the table index file, if any */
  1932.    if (table_file && *table_file)
  1933.       if ((tables = ip_open_write(table_file,!pages_printed,tables_buf,
  1934.                   sizeof(tables_buf)))
  1935.         != NULL)
  1936.      do_tables = TRUE ;
  1937.       else
  1938.      warning("unable to open table index file") ;
  1939.    /* open the data formats file, if any */
  1940.    if (formats_file && *formats_file)
  1941.       if ((formats = ip_open_write(formats_file,!pages_printed,formats_buf,
  1942.                    sizeof(formats_buf)))
  1943.         != NULL)
  1944.      do_formats = TRUE ;
  1945.       else
  1946.      warning("unable to open formats file") ;
  1947.    need_summary = (do_summary || do_formats || do_tables) ;
  1948.    /* initialize filtering data, if specified */
  1949.    if (filter_file && *filter_file)
  1950.       build_filter_lists(filter_file) ;
  1951.    if (total_lines <= lines_per_page)
  1952.       {
  1953.       total_lines = lines_per_page ;
  1954.       use_FF = TRUE ;
  1955.       }
  1956.    else
  1957.       use_FF = FALSE ;
  1958.    if (argc == 2 || argc == 3)
  1959.       {
  1960.       input_file = argv[1] ;
  1961.       input_file_namelen = strlen(input_file) ;
  1962.       if ((infile = ip_open_read(input_file,infile_buf,sizeof(infile_buf))) == NULL)
  1963.      fatal("unable to open input file") ;
  1964.       if (argc == 3)
  1965.      {
  1966.      outfile = ip_open_write(argv[2],!pages_printed,outfile_buf,
  1967.                  sizeof(outfile_buf)) ;
  1968.      if (outfile == NULL)
  1969.         fatal("unable to open output file") ;
  1970.      }
  1971.       else
  1972.      outfile = ip_open_write("",0,outfile_buf,sizeof(outfile_buf)) ;
  1973.       }
  1974.    else
  1975.       usage() ;
  1976.    if (lines_per_page > MAXPAGE)
  1977.       {
  1978.       ip_putlit("Surely you jest!  I can't handle pages that long.",err) ;
  1979.       newline(err) ;
  1980.       newline(err) ;
  1981.       usage() ;
  1982.       }
  1983.    else if (lines_per_page == 0) /* infinite page? */
  1984.       {
  1985.       widow_length = 0 ;
  1986.       if (total_lines <= 0)
  1987.      total_lines = MAXPAGE ;
  1988.       lines_per_page = total_lines ;
  1989.       use_FF = do_headers = page_numbers = FALSE ;
  1990.       }
  1991.    else
  1992.       {
  1993.       if (lines_per_page < 20)
  1994.      {
  1995.      ip_putlit("Surely your printer can handle at least 20 lines per page!",
  1996.            err) ;
  1997.      newline(err) ;
  1998.      ip_putlit("Adjusting page length....",err) ;
  1999.      newline(err) ;
  2000.      lines_per_page = 20 ;
  2001.      }
  2002.       if (widow_length < 3 || widow_length > lines_per_page / 2)
  2003.      {
  2004.      ip_putlit("Widow lines (-w) must be set to at least 3 and at most one-half of the",err) ;
  2005.      newline(err) ;
  2006.      ip_putlit("page length.  Using default of 8 lines.",err) ;
  2007.      newline(err) ;
  2008.      widow_length = 8 ;
  2009.      }
  2010.       }
  2011.    /* set up the printer */
  2012.    ip_putcstr(&printer->init1,outfile) ;
  2013.    ip_putcstr(&printer->init2,outfile) ;
  2014.    if (printer->set_typeface)
  2015.       (*printer->set_typeface)(outfile,typeface) ;
  2016.    if (duplex)
  2017.       {
  2018.       ip_putcstr(&printer->duplex_on,outfile) ;
  2019.       if (pages_printed & 1)          /* next page odd or even? */
  2020.      ip_putcstr(&printer->marginl,outfile) ;    /* even */
  2021.       else
  2022.      ip_putcstr(&printer->marginr,outfile) ;    /* odd */
  2023.       }
  2024.    else
  2025.       ip_putcstr(&printer->marginc,outfile) ;    /* non-duplex, so center */
  2026.    /* start the auxiliary files if this is the first part processed */
  2027.    if (pages_printed == 0)
  2028.       {
  2029.       /* start the summary file */
  2030.       if (do_summary)
  2031.      write_summary_header(summary,"Interrupt Summary",show_offsets,FALSE) ;
  2032.       /* start the table index file */
  2033.       if (do_tables)
  2034.      write_summary_header(tables,"Table Summary",show_offsets,TRUE) ;
  2035.       /* start the data formats file */
  2036.       if (do_formats)
  2037.      write_summary_header(formats,"Data Structure Formats",FALSE,FALSE) ;
  2038.       }
  2039.    if (page_numbers)
  2040.       body_lines = lines_per_page - 2 ;
  2041.    else
  2042.       body_lines = lines_per_page ;
  2043.    if (do_headers)
  2044.       body_lines -= 2 ;
  2045.    last_line = 0 ;
  2046.    while (!out_of_files)
  2047.       {
  2048.       fill_buffer(last_line,body_lines) ;
  2049.       last_line = find_page_break(body_lines) ;
  2050.       print_buffer(last_line,body_lines,lines_per_page,total_lines,use_FF) ;
  2051.       }
  2052.    if (last_line < body_lines)
  2053.       {
  2054.       int i ;
  2055.       
  2056.       for (i = last_line ; i < body_lines ; i++)
  2057.      {
  2058.      strcpy(buffer[i-last_line], buffer[i]) ;
  2059.      line_offsets[i-last_line] = line_offsets[i] ;
  2060.      }
  2061.       print_buffer(body_lines-last_line,body_lines,lines_per_page,total_lines,
  2062.            use_FF) ;
  2063.       }
  2064.    ip_close(infile) ;
  2065.    /* reset the printer */
  2066.    reset_printer_and_close(outfile) ;
  2067.    ip_puts(itoa(pages_printed, num, 10), err) ;
  2068.    ip_putlit(" pages", err) ;
  2069.    if (do_summary)
  2070.       reset_printer_and_close(summary) ;
  2071.    if (do_tables)
  2072.       {
  2073.       ip_putlit(", ", err) ;
  2074.       ip_puts(itoa(prev_table, num, 10), err) ;
  2075.       ip_putlit(" tables", err) ;
  2076.       reset_printer_and_close(tables) ;
  2077.       }
  2078.    if (do_formats)
  2079.       reset_printer_and_close(formats) ;
  2080.    newline(err) ;
  2081.    ip_close(err) ;
  2082.    return 0 ;
  2083. }
  2084.