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