home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / CLIPPER / MISC / INTER32C.ZIP / INT2GUID.ZIP / INT2GUID.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-05-10  |  16.4 KB  |  603 lines

  1. /* INT2GUID.C
  2.  *
  3.  * from:
  4.  * INT2QH.C
  5.  *
  6.  * Author:   Kai Uwe Rommel
  7.  * Date:     Sun 07-Oct-1990
  8.  * Update:   Sat 20-Oct-1990
  9.  * Update:   Sun 11-Nov-1990  Ralf Brown
  10.  *
  11.  * Compiler: MS C 5.00 and newer / compact model, or TC 2.0 / compact model
  12.  * System:   PC/MS-DOS 3.20 and newer, OS/2 1.0 and newer
  13.  *
  14.  *
  15.  * INT2GUID.C is a GUIDE/MAKEHELP version of INT2QH.C. GUIDE and MAKEHELP
  16.  * are programs for pop-up help included the TurboPower Software package
  17.  * Turbo Professional.
  18.  *
  19.  * Transscriptor:    Bent Lynggaard
  20.  * Date:    1.00    Sun 24-Mar-1991
  21.  * Update:    1.01    Tue 02-Apr-1991    - test '!', ';' in line pos 1.
  22.  *                    - test disk full
  23.  *        1.02    Sun 14-Apr-1991    - smaller index pages
  24.  *                    - main index always leads to start of
  25.  *                      an INT #
  26.  *        1.03    Sun 12-May-1991    - configuration file.
  27.  *        1.04    Sat 18-May-1991 - conditional mask in *.cfg
  28.  *        1.05    Sun 29-Dec-1991 - fixed \n bug in configurate()
  29.  *        1.06    Sun 09-May-1992 - adjusted for change in file format
  30.  *                    - "dividerline" info as headings
  31.  *                    - all registers can carry parameters
  32.  *
  33.  * This program creates output to the standard output device. The output
  34.  * should be redirected to a file INTERRUP.TXT. The created file should
  35.  * be compiled by the TurboPower MAKEHELP program to a INTERRUP.HLP file,
  36.  * which can be interpreted by the TurboPower GUIDE TSR program:
  37.  *    INT2GUID > [ramdisk:]INTERRUP.TXT
  38.  *    MAKEHELP [ramdisk:INTERRUPT] INTERRUP[.HLP] /Q
  39.  *    GUIDE INTERRUP    (or enter GUIDE with a hot key, press F3,
  40.  *            enter INTERRUP)
  41.  *
  42.  * TurboPower Software supplies a program called POPHELP in their Object
  43.  * Professional package, which is a successor to GUIDE. INT2GUID has
  44.  * facilities for conditional interpretation of supplementary files, so
  45.  * these files can include code optimized for both GUIDE and POPHELP, and
  46.  * the parts compiled depends on a mask defined in the configuration file.
  47.  *
  48.  * The following is considered in creating the topic (and popup window)
  49.  * headers:
  50.  * The first word in the header is the interrupt number, so that GUIDE's
  51.  * search mechanism can find the entry if the hot key is pressed when
  52.  * the cursor is at an interrupt number.
  53.  * MAKEHELP restricts the (length of longest header + 1) times the number
  54.  * of topics to 64 kB. INTER191 had about 2200 topics, so the length of
  55.  * the headers should be limited to 25 characters. However, rather than
  56.  * truncating the INTERRUP.LST header lines to some nonsence, this
  57.  * program uses only the interrupt number as topic headings, plus the
  58.  * AH or AX values where applicable.
  59.  * (v. 1.06: "divider line" info (e.g. "214C" in "--------214C------...")
  60.  * is used for headings, thus allowing a more selective search by GUIDE's
  61.  * cursor-word search.)
  62.  * The main index references some subindeces. The subindeces use the
  63.  * MAKEHELP cross reference facility. MAKEHELP limits the number of cross
  64.  * references to 50 per topic, however, this program limits each subindex
  65.  * to 18 entries, so each "topic" can be shown on one single screen with
  66.  * height 20 lines. For each interrupt number, the entries are temporarily
  67.  * stored, and written to the current subindex page only if all entries
  68.  * for the interrupt number fit on the page.
  69.  *
  70.  * MAKEHELP's text wrapping mechanism is disabled, and as the active
  71.  * window is limited to 76 characters, some lines are missing one or two
  72.  * characters.
  73.  * The amount of text that can be displayed per topic is limited by
  74.  * GUIDE's setting of pages/topic (default = 20) and the screen height
  75.  * defined when GUIDE was initialized.
  76.  *
  77.  */
  78.  
  79. #define LABEL    "int2guid.c"
  80. #define VERSION  "1.06"
  81.  
  82. #include <stdio.h>
  83. #include <stdlib.h>
  84. #include <string.h>
  85. #include <ctype.h>
  86.  
  87. #define divider_line(s) (strncmp(s,"--------",8)==0)
  88. #define maxIndeces 18
  89.   /* max 50, 18 gives one page with height 20 (18 active lines) */
  90. #define mainIndex 200
  91.   /* 1-99 reserved for program, 100-199 reserved for user */
  92. #define false 0
  93. #define true 1
  94.  
  95. FILE *input, *output, *topics, *subtopics, *config;
  96.  
  97. char line1[128];
  98. char line2[128];
  99. char tempBuffer[50 * 128];
  100. char *tempPtr;
  101. char category[4] = "--";
  102. char nextHeader[14] = "??";
  103. char infilename[14] = "interrup.lst";
  104. #define infileExt 9
  105. int splitInfile = 0;
  106.  
  107. char configfile[14] = "int2guid.cfg";
  108. char configmarker[18] = "INT2GUIDE CONFIG";
  109.  
  110. char missingFile[] = "Missing include file.";
  111.  
  112. int sub = 0, indexed = 1;
  113. unsigned currentID = 1, activeID = 1, indeces = 0, indexNo = 0, buffered = 0,
  114.   subindeces, activeSub, mask;
  115.  
  116. void exitfunc(void)
  117. {
  118.   fcloseall();
  119.   unlink("topic.tmp");
  120.   unlink("subtopic.tmp");
  121. }
  122.  
  123. void errorexit(char *msg)
  124. /* writes msg to stderr and exits with error code 1 */
  125. {
  126.   fputs(msg, stderr);
  127.   exit(1);
  128. } /* errorexit */
  129.  
  130. void diskFull(int temporary)
  131. /* reports disk full and exits */
  132. {
  133.   char msg[80];
  134.   sprintf(msg,"\n\nDisk full, %s file\n", temporary ? "temporary" : "output");
  135.   errorexit(msg);
  136. } /* diskFull */
  137.  
  138.  
  139. int _fputs(char *line, FILE *stream)
  140. /* filters TABs to spaces, and inserts a leading space in lines starting
  141.    with the MAKEHELP command and comment characters '!' and ';'. "_fputs"
  142.    should be used when copying from unknown sources. Use "fputs" when
  143.    copying files with information specifically for this program.
  144. */
  145. {
  146.   char buffer[128];
  147.   int cnt = 0;
  148.  
  149.   if ( (*line=='!') || (*line==';') ) /* MAKEHELP command/comment? */
  150.     buffer[cnt++] = ' '; /* start with a space */
  151.  
  152.   while ( *line )
  153.   {
  154.     switch ( *line )
  155.     {
  156.       case '\t': do buffer[cnt++] = ' '; while ( cnt & 7 ); break;
  157.             /* MAKEHELP does not interpret tabs */
  158.       default  : buffer[cnt++] = *line;
  159.     }
  160.     line++;
  161.   }
  162.  
  163.   buffer[cnt] = 0;
  164.  
  165.   if ( (cnt = fputs(buffer, stream)) == EOF )
  166.     diskFull(stream != output);
  167.  
  168.   return cnt;
  169. }
  170.  
  171. char *_fgets(char *s, int n, FILE *stream)
  172. {
  173.   char *ptr;
  174.   ptr = fgets(s, n, stream);
  175.   if ( (ptr==NULL) && (stream==input) && splitInfile )
  176.   {
  177.     fclose(input);
  178.     infilename[infileExt]++;
  179.     input = fopen(infilename, "r");
  180.     if ( input != NULL )
  181.     {
  182.       fprintf(stderr, "%s\n", infilename);
  183.       ptr = fgets(s, n, input);
  184.     }
  185.   }
  186.   return ptr;
  187. } /* _fgets */
  188.  
  189. void Initialize(void)
  190. {
  191.   input     = fopen(infilename, "r");
  192.   if ( input == NULL )
  193.   {
  194.     infilename[infileExt] = 'a';
  195.     infilename[infileExt+1] = 0;
  196.     input = fopen(infilename, "r");
  197.     if ( input == NULL )
  198.     {
  199.       fputs("Cannot open input file (INTERRUP.LST or INTERRUP.A)\n", stderr);
  200.       exit(1);
  201.     }
  202.     splitInfile = 1;
  203.   }
  204.   fprintf(stderr, "%s\n", infilename);
  205.   output    = stdout;
  206.   topics    = fopen("topic.tmp", "w");
  207.   subtopics = fopen("subtopic.tmp", "w");
  208.  
  209.   tempPtr = tempBuffer;
  210.  
  211.   fprintf(output,
  212.     ";INTERRUPT help text for MAKEHELP/GUIDE.\n;\n!WIDTH 80\n;\n");
  213.   fprintf(topics, "!TOPIC 1 Interrupt List\n!INDEX %u\n", mainIndex);
  214. }
  215.  
  216.  
  217. void testTopic(void) /* limit xrefs/topic to maxIndeces */
  218. {
  219.   if ( indeces+buffered >= maxIndeces ) /* leave one entry for forw. ref */
  220.   {
  221.     currentID++;
  222.     fprintf(topics, "\004%u\005INT %s\005 (index continued)\n"
  223.       "!TOPIC %u INT %s (cont)\n!INDEX %u\n"
  224.       "(continued \004%u\005from\005)\n",
  225.       currentID, category, currentID, category, ++indexNo, activeID);
  226.     indeces = 1; /* the backwards ref */
  227.     activeID = currentID;
  228.   }
  229. } /* testTopic */
  230.  
  231. void copyBuffer(void)
  232. {
  233.   if ( buffered == 0 )
  234.     return;
  235.  
  236.   testTopic();
  237.   if ( fputs(tempBuffer, topics) == EOF )
  238.       diskFull(true);
  239.   indeces += buffered;
  240.   buffered = 0;
  241.   tempPtr = tempBuffer;
  242. } /* copyBuffer */
  243.  
  244. void Cleanup(void)
  245. {
  246.   copyBuffer();
  247.   fclose(topics);
  248.   fclose(subtopics);
  249.   fputs("Cleaning up\n", stderr);
  250.  
  251.   topics = fopen("topic.tmp", "r");
  252.   subtopics = fopen("subtopic.tmp", "r");
  253.  
  254.   while ( fgets(line1, sizeof(line1), topics) )
  255.     if ( fputs(line1, output) == EOF )
  256.       diskFull(false);
  257.  
  258.   while ( fgets(line1, sizeof(line1), subtopics) )
  259.     if ( fputs(line1, output) == EOF )
  260.       diskFull(false);
  261. }
  262.  
  263.  
  264. int CopyFile(char *name, int commands)
  265. /* copies a file to the database, returns 0 for success or 1 for error */
  266.  
  267. /* If commands!=0, also interprets lines starting with "!! <number>" as
  268.    an update to variable "condition", and copies lines to the database
  269.    only if condition == 0 or (condition & mask) != 0
  270. */
  271. {
  272.   int condition = 0;
  273.   FILE *temp = fopen(name, "r");
  274.   fprintf(stderr, "%s\n", name);
  275.   if ( temp == NULL )
  276.   {
  277.     fprintf(stderr, "WARNING: Could not open %s\n", name);
  278.     fputs("Information was not available\n", output);
  279.     return 1;
  280.   }
  281.   else
  282.   {
  283.     while ( fgets(line2, sizeof(line2), temp) )
  284.       if ( !commands )
  285.     _fputs(line2, output);
  286.       else
  287.     /* does line start with "!! <number>" ? */
  288.     if ( sscanf(line2, "!!%i", &condition) != 1 )
  289.       /* yes: condition updated, sscanf returns 1 */
  290.       if ( (condition==0) || (condition & mask) )
  291.         fputs(line2, output);
  292.  
  293.     fputs("!NOWRAP\n", output); /* in case it was left in !WRAP state */
  294.     fclose(temp);
  295.     return 0;
  296.   }
  297. } /* CopyFile */
  298.  
  299. void testTemp(void)
  300. /* v. 1.06: allow no more than 50 entries in tempBuffer */
  301. {
  302.   if (buffered >= 50)
  303.   {
  304.     copyBuffer();
  305.     fprintf(stderr,"WARNING: Too many entrees for GUIDE in INT %s.\n"
  306.       "Manual editing of topic %u may be desirable.\n", category, currentID);
  307.   }
  308. } /* testTemp */
  309.  
  310. void testSubtopic(char *marker)
  311. {
  312.   if ( ++subindeces >= maxIndeces )
  313.   {
  314.     testTemp();
  315.     sprintf(tempPtr, "\004%u\005%s\005  (list cont.)\n",
  316.       ++currentID, marker);
  317.     tempPtr += strlen(tempPtr);
  318.     buffered++;
  319.     fprintf(subtopics,
  320.       "\004%u\005%s\005  (list cont.)\n!TOPIC %u %s (list cont)\n!NOINDEX\n"
  321.       "(continued \004%u\005from\005)\n",
  322.       currentID, marker, currentID, category, activeSub);
  323.       activeSub = currentID;
  324.     subindeces = 2;
  325.   }
  326. } /* testSubtopic */
  327.  
  328.  
  329. void StartTopic(char *header, char *marker, char *desc)
  330. {
  331.   if ( sub )
  332.   {
  333.     testSubtopic(marker);
  334.     if ( fprintf(subtopics, "\004%u\005%s\005  %s",
  335.       ++currentID, marker, desc) == EOF )
  336.     diskFull(true);
  337.   }
  338.   else
  339.   {
  340.     testTemp();
  341.     sprintf(tempPtr, "\004%u\005%s\005  %s", ++currentID, marker, desc);
  342.     tempPtr += strlen(tempPtr);
  343.     buffered++;
  344.   }
  345.  
  346.   fprintf(output, "!TOPIC %u %s\n", currentID, header);
  347.   if ( indexed )
  348.     indexNo++;
  349.   fprintf(output, indexed ? "!INDEX %u\n" : "!NOINDEX\n", indexNo);
  350. }
  351.  
  352.  
  353. void StartList(void)
  354. {
  355.   testTemp();
  356.   sprintf(tempPtr, "\004%u\005INT %s\005  (list)\n",
  357.     ++currentID, category);
  358.   tempPtr += strlen(tempPtr);
  359.   buffered++;
  360.   fprintf(subtopics, "!TOPIC %u %s (list)\n!NOINDEX\n",
  361.     currentID, category);
  362.  
  363.   sub = 1;
  364.   subindeces = 0;
  365.   activeSub = currentID;
  366. }
  367.  
  368.  
  369. /* void EndList(void) - not used */
  370.  
  371.  
  372. /* char *NextID(void) - not used */
  373.  
  374.  
  375. int RecognizedTopic(void)
  376. {
  377.   char *ptr, *pdesc, topic[4], reg[4], header[16], marker[20];
  378.   int i;
  379.  
  380.   if ( _fgets(line2, sizeof(line2), input) == NULL )
  381.     return 0;
  382.  
  383. /* v. 1.06: interrupt number suggested to start after line1[4] */
  384. /* line1 is already tested to start with "INT " */
  385.   if ( (pdesc = strchr(line1, '-')) == NULL )
  386.     return 0;
  387.  
  388.   for (ptr = line1+3; isspace(*ptr); ptr++)
  389.     ;
  390.   strncpy(topic, ptr, 2); /* interrupt number */
  391.   topic[2] = '\0';
  392.  
  393.   if ( strcmp(category, topic) )
  394.   {
  395.     sub = 0;
  396.     copyBuffer();
  397.     strcpy(category, topic);
  398.     fprintf(stderr, "%s\015", topic); /* show progress */
  399.   }
  400.   else
  401.     fprintf(output, "\004%u\005INT %s\005 (continued)\n",
  402.       currentID+1, topic);
  403.     /* insert a reference to this one in the former topic */
  404.  
  405.   strcpy(header, topic);
  406.  
  407. /* v. 1.06: accept any register as a parameter carrier */
  408.   for (ptr = line2 ; isspace(*ptr) ; ptr++)
  409.      ;
  410.   reg[0] = toupper(*ptr);
  411.   reg[1] = toupper(ptr[1]);
  412.   reg[2] = 0;
  413.  
  414.   if ( !isspace(reg[1]) &&
  415.     strstr("AX AH AL BX BH BL CX CH CL DX DH DL SI DI BP ES DS", reg)
  416.     != NULL &&
  417.     !strncmp(ptr+2, " =", 2)
  418.       )
  419.   {
  420.     for ( i = 5; (tolower(ptr[i]) != 'h') && !isspace(ptr[i]); i++ )
  421.       ;
  422.     if ( i < 11 )
  423.     {
  424.       if ( !sub )
  425.     StartList();
  426.       strcat(header, "  ");
  427.       strncat(header, ptr, i);
  428.     }
  429.   }
  430.  
  431.   strcpy(marker, "INT ");
  432.   strcat(marker, header);
  433.  
  434. /* v. 1.06: use global "nextHeader" rather than local "header" */
  435.   StartTopic(nextHeader, marker, pdesc);
  436.  
  437.   _fputs(line1, output);
  438.   if ( !divider_line(line2) )
  439.     _fputs(line2, output);
  440.  
  441.   return 1;
  442. }
  443.  
  444.  
  445. void CopyTopic(void)
  446. {
  447.   char *ptr;
  448.   if ( divider_line(line2) )
  449.   { /* kludge for one-line interrupts */
  450.     _fgets(line1, sizeof(line2), input);
  451.     return;
  452.   }
  453.  
  454.   for (;;)
  455.   {
  456.     if ( _fgets(line1, sizeof(line1), input) == NULL )
  457.       break;
  458.  
  459.     if ( !divider_line(line1) )
  460.       _fputs(line1, output);
  461.     else
  462.     {
  463.       if ( _fgets(line2, sizeof(line2), input) == NULL )
  464.     break;
  465.  
  466.       if ( strncmp(line2, "INT ", 4) )
  467.       {
  468.     _fputs(line1, output);
  469.     _fputs(line2, output);
  470.       }
  471.       else
  472.       {
  473.     /* v. 1-06: store divider line info as a header */
  474.     for (ptr=line1+6; *ptr=='-' || isspace(*ptr); ptr++)
  475.       ;
  476.     strncpy(nextHeader,ptr,sizeof(nextHeader));
  477.     ptr = strchr(nextHeader, '-');
  478.     if (ptr==NULL || ptr>nextHeader+sizeof(nextHeader))
  479.       nextHeader[sizeof(nextHeader)-1] = 0;
  480.     else
  481.       *ptr = 0;
  482.     strcpy(line1, line2);
  483.     break;
  484.       }
  485.     }
  486.   }
  487. }
  488.  
  489. void configError(void)
  490. {
  491.   errorexit("\nFormat error in configuration file.\n");
  492. } /* configError */
  493.  
  494. void readconfig(void)
  495. /* reads one line from file config to line2 */
  496. {
  497.   if ( fgets(line2, sizeof(line2), config) == NULL )
  498.     configError();
  499. } /* readconfig */
  500.  
  501. void copyline(char *str, int len)
  502. /* copies line2 (after deleting the terminating '\n') to str
  503.     for max len characters. */
  504. {
  505.   line2[strlen(line2)-1] = 0; /* ignore '\n' */
  506.   strncpy(str, line2, len);
  507.   str[len] = 0; /* edited: v. 1.05 */
  508. } /* copyline */
  509.  
  510. void configurate(void)
  511. /* parses configuration file */
  512. {
  513. #define maxHeader 14
  514. #define markerLen 12
  515.   int confv, confsubv, command, extraTopics, i;
  516.   char header[(maxHeader+2) & 0xFE], marker[(markerLen+2) & 0xFE],
  517.     desc[(76-markerLen) & 0xFE], filename[80];
  518.   config = fopen(configfile, "r");
  519.   if ( config == NULL )
  520.   {
  521.     fputs("\nWarning: No configuration file.\n", stderr);
  522.     return;
  523.   }
  524.   readconfig();
  525.   if ( strncmp(line2, configmarker, strlen(configmarker)) )
  526.     configError();
  527.   readconfig();
  528.   if ( sscanf(line2, "%u%u", &confv, &confsubv) < 2 )
  529.     configError();
  530.   if ( ((confv << 8) + confsubv) < 0x104 )
  531.     errorexit ("\nThe configuration file is incompatible with this"
  532.     " version of INT2GUID");
  533.   while ( !feof(config) )
  534.   {
  535.     while ( (fgets(line2, sizeof(line2), config) != NULL)
  536.       && (line2[0] == ';') ) ;
  537.     if feof(config) break;
  538.     copyline(filename, 79);
  539.     readconfig();
  540.     copyline(header, maxHeader);
  541.     readconfig();
  542.     copyline(marker, markerLen);
  543.     i = strlen(marker);
  544.     while ( i<markerLen-1 ) /* pad with spaces if short */
  545.       marker[i++] = ' '; /* is already 0-terminated at markerLen */
  546.     readconfig();
  547.     copyline(desc, 76-markerLen-2);
  548.     i = strlen(desc); /* edited: v. 1.05 */
  549.     desc[i] = '\n';
  550.     desc[++i] = 0;
  551.     readconfig();
  552.     if ( sscanf(line2, "%u%u%i", &command, &extraTopics, &mask) < 3 )
  553.       configError();
  554.  
  555.     StartTopic(header, marker, desc);
  556.     CopyFile(filename, command);
  557.     currentID += extraTopics;
  558.   }
  559.   fclose(config);
  560. #undef maxHeader
  561. #undef markerLen
  562. } /* configurate */
  563.  
  564. void main(void)
  565. {
  566.   fprintf(stderr, "\nINT2GUID %s - (c) Kai Uwe Rommel/Bent Lynggaard - %s\n",
  567.     VERSION, __DATE__);
  568.   atexit(exitfunc);
  569.  
  570.   Initialize(); /* uses topic 1 */
  571.  
  572.   fputs("Including:\n",stderr);
  573.   StartTopic("Copyright etc.", "Copyright  ", "and references.\n");
  574.   if ( CopyFile("int2guid.ref", true) ) /* topic 2 */
  575.     errorexit(missingFile);
  576.  
  577.   StartTopic("INTERRUP.LST", "HEADER     ", "Overview of the Interrupt List\n");
  578.   fputs("(See also \4""4\5INTERRUP.1ST\5)\n", output); /* insert reference */
  579.   CopyTopic(); /* topic 3 */
  580.  
  581.   StartTopic("INTERRUP.1ST", "Mail etc.  ", "How to get/update INTERRUP.LST\n");
  582.   if ( CopyFile("interrup.1st", false) ) /* topic 4 */
  583.     errorexit(missingFile);
  584.  
  585.   StartTopic("GUIDE Program", "GUIDE      ", "Popup Reference Engine.\n");
  586.   if ( CopyFile("int2guid.gui", true) ) /* topic 5 */
  587.     errorexit(missingFile);
  588.  
  589.   configurate();
  590.  
  591.   indexed = 0;
  592.   indexNo = mainIndex;
  593.  
  594.   while ( RecognizedTopic() )
  595.     CopyTopic();
  596.  
  597.   Cleanup();
  598.  
  599.   exit(0);
  600. }
  601.  
  602. /* End of INT2GUID.C */
  603.