home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / multtsk / cpmult / source / doclist.c next >
Encoding:
C/C++ Source or Header  |  1989-03-30  |  16.3 KB  |  684 lines

  1. /*///////////////////////////////////////////////////////////////////////////
  2. ///  Module...: doclist.c                                                 ///
  3. ///  Version..: 1.00                                                      ///
  4. ///  Author...: Christian Philipps                                        ///
  5. ///             Düsseldorfer Str. 316                                     ///
  6. ///             4130 Moers 1                                              ///
  7. ///  Date.....: March 1989                                                ///
  8. /////////////////////////////////////////////////////////////////////////////
  9. ///                                                                       ///
  10. ///     DocList is a simple to handle and yet powerful software manual    ///
  11. ///     formatter.                                                        ///
  12. ///     A variety of dot-commands supports section headers, page format,  ///
  13. ///     copyright notice in footer, indentation and the ability to ma-    ///
  14. ///     nage reference section headlines. The latter ones are similar to  ///
  15. ///     those found in Turbo Power Software's Reference Manuals.          ///
  16. ///                                                                       ///
  17. ///     DocList was primarily developed in order to ease the maintenance  ///
  18. ///     of largish, normally alphabetically ordered reference sections.   ///
  19. ///     Inserting new entries manually is quite difficult because you     ///
  20. ///     will have to shift all entries following the new one backwards.   ///
  21. ///     Page breaks will have to be adjusted and Headlines, designed to   ///
  22. ///     allow for easy access will have to be changed accordingly - puhh..///
  23. ///                                                                       ///
  24. ///     Well, after having done so twice, I decided to write some program ///
  25. ///     to format my on-disk ShareWare Manuals for printout the way I     ///
  26. ///     want. In addition to easy hadling, the unformatted text files     ///
  27. ///     consume less diskspace and may be kept in plain ASCII.            ///
  28. ///                                                                       ///
  29. ///     DocList now is what I came up with! Play with it, change it,      ///
  30. ///     love it or even scrap it. - The program is hereby placed in the   ///
  31. ///     public domaine and it's up to you to adapt it to your needs.      ///
  32. ///     If you feel you have greatly enhanced the program, please re-     ///
  33. ///     lease your new version in the public domaine to allow others to   ///
  34. ///     share the tool.                                                   ///
  35. ///                                                                       ///
  36. ///     Best regards, Christian Philipps (March, 14, 1989)                ///
  37. ///                                                                       ///
  38. ///////////////////////////////////////////////////////////////////////////*/
  39.  
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <malloc.h>
  43. #include <memory.h>
  44.  
  45. /*
  46. ** Some general purpose definitions
  47. */
  48. #define NULL_FP         (FILE *)NULL
  49. #define NULL_CP         (char *)NULL
  50. #ifndef TRUE
  51. #  define TRUE            (1==1)
  52. #endif
  53. #ifndef FALSE
  54. #  define FALSE           (0==1)
  55. #endif
  56. #ifndef BOOLEAN
  57. #  define BOOLEAN         int
  58. #endif
  59.  
  60. #define TOKSEP          " \t"           /* Token-Seperator for strtok() */
  61.  
  62. /*
  63. ** Dot-Command dispatch table
  64. */
  65. typedef struct cmd_t {
  66.     char *Cmd;
  67.     void (*CmdHand)();
  68. } CMD_T;
  69.  
  70. void CmdCO();   /* Each function hadles the command corresponding to */
  71. void CmdSE();   /* the last two characters of its name */
  72. void CmdPL();
  73. void CmdPA();
  74. void CmdID();
  75. void CmdRM();
  76. void CmdLL();
  77. void CmdRE();
  78. void CmdER();
  79. void CmdEE();
  80. void CmdML();
  81. void CmdHS();
  82. void CmdRS();
  83.  
  84. static CMD_T Commands[] = {
  85.     { "CO", CmdCO },        /* Copyright notice */
  86.     { "PA", CmdPA },        /* Page Break */
  87.     { "PL", CmdPL },        /* Page Length */
  88.     { "SE", CmdSE },        /* Section */
  89.     { "RE", CmdRE },        /* Reference Entry */
  90.     { "ER", CmdER },        /* End of Reference Section */
  91.     { "EE", CmdEE },        /* End of Reference Entry */
  92.     { "HS", CmdHS },        /* Headline-Seperator Character */
  93.     { "RS", CmdRS },        /* Reference-Seperator Character */
  94.     { "LL", CmdLL },        /* Line Length */
  95.     { "ID", CmdID },        /* Indentation */
  96.     { "RM", CmdRM },        /* Right Margin */
  97.     { "ML", CmdML },        /* Minimum lines on current page remaining */
  98.                 /* to start new reference entry */
  99.   /* More entries may be inserted here */
  100.     { NULL_CP, NULL }       /* End of Table marker */
  101. };
  102.  
  103. typedef char workstr[200];
  104.  
  105. /*
  106. ** Overall defaults
  107. */
  108. int  PageLength = 66;
  109. int  LineLength = 80;
  110. int  Indent     = 5;
  111. int  RightMargin= 5;
  112. int  MinLines   = 7;
  113. char LineChar   = '═';
  114. char RefSepChar = '─';
  115.  
  116. /*
  117. ** Macros and definitions used offset and length calculations
  118. */
  119. #define LINEDATA        (LineLength-Indent-RightMargin)
  120. #define LAYLINE(N)      (Layout+((N)*(LineLength+1)))
  121. #define HEADER          3
  122. #define HEADLEN         2
  123. #define TEXTSTART       (HEADER+HEADLEN+2)
  124. #define FOOTLEN         7
  125. #define FOOTER          (PageLength-FOOTLEN)
  126. #define TEXTEND         (FOOTER-3)
  127. #define INDENT(L)       { memset(L,'\0',LineLength+1); memset(L,' ',Indent); }
  128. #define CO_LEN          (LineLength-20)
  129. #define LINES_REM       (TEXTEND-Line+1)
  130. #define MIN_LINES       (MinLines+3)            /* plus size of divider line */
  131.  
  132. /*
  133. ** Page layout
  134. */
  135. char *Layout    = NULL_CP;
  136. BOOLEAN LayoutChanged = FALSE;
  137.  
  138. /*
  139. ** global workspace
  140. */
  141. char *Divider   = NULL_CP;                      /* Hedline divider */
  142. char *RefSep    = NULL_CP;                      /* Reference entry seperator */
  143.  
  144. int  Page;
  145. int  Line;
  146. BOOLEAN IgnoreLine = FALSE;
  147.  
  148. workstr Copyright = "";
  149. workstr RefItems;
  150. workstr LastRefItem;
  151. workstr SectionHeader;
  152.  
  153. /*
  154. ** ----------------------------------------------------------------------
  155. */
  156.  
  157. main(argc,argv)
  158. int argc;
  159. char **argv;
  160. {
  161.   void Usage();
  162.   void ListDoc();
  163.   void InitLayout();
  164.   char *InitDivider();
  165.  
  166.   if(argc < 2)
  167.     Usage();
  168.  
  169.   InitLayout();
  170.   Divider = InitDivider(Divider,LineChar);
  171.   RefSep  = InitDivider(RefSep,RefSepChar);
  172.  
  173.   if(stricmp("-s",argv[1]) != 0) {
  174.     while(--argc)
  175.       ListDoc(*(++argv));
  176.   }
  177.   else {                                        /* use stdin */
  178.     ListDoc(NULL_CP);
  179.   }
  180. }
  181.  
  182. /*
  183. ** ----------------------------------------------------------------------
  184. */
  185.  
  186. void InitLayout()
  187. /*
  188. ** Physically reserve space to hold the formatted page layout
  189. */
  190. {
  191.   if(Layout != NULL_CP)
  192.     free(Layout);
  193.   if((Layout=(char *)calloc(1,PageLength*(LineLength+1))) == NULL_CP) {
  194.     fputs("Sorry! - Couldn't allocate page layout!\n",stderr);
  195.     exit(1);
  196.   }
  197. }
  198.  
  199. /*
  200. ** ----------------------------------------------------------------------
  201. */
  202.  
  203. char *InitDivider(Divider,c)
  204. char *Divider;
  205. char c;
  206. /*
  207. ** Physically allocate space to hold a divider line
  208. */
  209. {
  210.   if(Divider != NULL_CP)
  211.     free(Divider);
  212.   if((Divider=(char *)calloc(1,LINEDATA+1)) == NULL_CP) {
  213.     fputs("Sorry! - Couldn't allocate divider line!\n",stderr);
  214.     exit(1);
  215.   }
  216.   memset(Divider,c,LINEDATA);
  217.   return(Divider);
  218. }
  219.  
  220. /*
  221. ** ----------------------------------------------------------------------
  222. */
  223.  
  224. void RJust(l,txt)
  225. char *l;
  226. char *txt;
  227. /*
  228. ** Place txt in layout line, justified right
  229. */
  230. {
  231.   int n, m;
  232.  
  233.   m=strlen(l);
  234.   n=LineLength-m-strlen(txt)-RightMargin;
  235.   if(n < 0)                                     /* Skip */
  236.     return;
  237.   memset(l+m,' ',n);
  238.   strcat(l,txt);
  239. }
  240.  
  241. /*
  242. ** ----------------------------------------------------------------------
  243. */
  244.  
  245. void UpdateFooter()
  246. /*
  247. ** Update footer display in the page layout buffer
  248. */
  249. {
  250.   void RJust();
  251.  
  252.   char pgnr[15];
  253.  
  254.   INDENT(LAYLINE(FOOTER+1));
  255.   strcat(LAYLINE(FOOTER+1),Copyright);
  256.   sprintf(pgnr,"Seite: %3d",Page);
  257.   RJust(LAYLINE(FOOTER+1),pgnr);
  258. }
  259.  
  260. /*
  261. ** ----------------------------------------------------------------------
  262. */
  263.  
  264. void UpdateDividers()
  265. /*
  266. ** Update hedline/footer dividers in the page layout buffer
  267. */
  268. {
  269.   INDENT(LAYLINE(HEADER+1));
  270.   INDENT(LAYLINE(FOOTER));
  271.   strcat(LAYLINE(HEADER+1),Divider);
  272.   strcat(LAYLINE(FOOTER),Divider);
  273. }
  274.  
  275. /*
  276. ** ----------------------------------------------------------------------
  277. */
  278.  
  279. void ClearPage()
  280. {
  281.   void UpdateFooter();
  282.   void UpdateDividers();
  283.  
  284.   int n;
  285.  
  286.   for(n=0;n<PageLength;n++)
  287.     *LAYLINE(n)='\0';
  288.   UpdateFooter();
  289.   UpdateDividers();
  290.   LayoutChanged = FALSE;
  291.   Line = TEXTSTART;
  292. }
  293.  
  294. /*
  295. ** ----------------------------------------------------------------------
  296. */
  297.  
  298. void OutputPage()
  299. /*
  300. ** Output current content of the page layout buffer to stdout and
  301. ** finally re-initialize it. The current page number is incremented.
  302. */
  303. {
  304.   void ClearPage();
  305.  
  306.   int n;
  307.  
  308.   if(!LayoutChanged)                    /* Only if something has changed */
  309.     return;
  310.  
  311.   for(n=0;n<PageLength;n++)
  312.     printf("%s\n",LAYLINE(n));
  313.   Page++;
  314.   ClearPage();
  315. }
  316.  
  317. /*
  318. ** ----------------------------------------------------------------------
  319. */
  320.  
  321. void Usage()
  322. {
  323.   fputs("Documentation Lister V1.00 / March 1989\n",stderr);
  324.   fputs("Author: Christian Philipps, Moers, West-Germany\n",stderr);
  325.   fputs("This program is hereby placed in the public domaine!\n\n",stderr);
  326.   fputs("Usage: doclist [-s < infile | file [...]] > outfile\n",stderr);
  327.   exit(1);
  328. }
  329.  
  330. /*
  331. ** ----------------------------------------------------------------------
  332. */
  333.  
  334. void ListDoc(fname)
  335. char *fname;
  336. /*
  337. ** Format single file for print
  338. */
  339. {
  340.   void ListLine();
  341.   void CommandLine();
  342.   void ClearPage();
  343.   void PageBreak();
  344.  
  345.   FILE *f;
  346.   workstr line;
  347.  
  348.   if(!*fname) {
  349.     f=stdin;
  350.   }
  351.   else {
  352.     if((f=fopen(fname,"rt"))==NULL_FP) {
  353.       fprintf(stderr,"Error opening %s!\n",fname);
  354.       return;
  355.     }
  356.   }
  357.   Page = 1;
  358.   *LastRefItem = *RefItems = *SectionHeader = '\0';
  359.   ClearPage();
  360.   while(fgets(line,sizeof(line),f) != NULL_CP) {
  361.     line[strlen(line)-1] = '\0';                /* Cut \n */
  362.     if(*line=='.')
  363.       CommandLine(strtok(line+1,TOKSEP));
  364.     else
  365.       ListLine(line);
  366.   }
  367.   fclose(f);
  368.   PageBreak();
  369. }
  370.  
  371. /*
  372. ** ----------------------------------------------------------------------
  373. */
  374.  
  375. void ListLine(l)
  376. char *l;
  377. /*
  378. ** Process line of text; perform page break if necessary
  379. */
  380. {
  381.   void PageBreak();
  382.  
  383.   if(IgnoreLine)                                /* between .EE ... .RE */
  384.     return;
  385.  
  386.   INDENT(LAYLINE(Line));
  387.   strncat(LAYLINE(Line),l,LINEDATA);
  388.   LayoutChanged = TRUE;
  389.   if(++Line > TEXTEND)
  390.     PageBreak();
  391. }
  392.  
  393. /*
  394. ** ----------------------------------------------------------------------
  395. */
  396.  
  397. void PageBreak()
  398. /*
  399. ** Perform page break, thereby outputting the current page to stdout.
  400. ** Update the list of items referenced on the current page. Care must
  401. ** be taken to keep the name of the last item mentioned if it is to
  402. ** be continued on the next page.
  403. */
  404. {
  405.   void OutputPage();
  406.   void RJust();
  407.  
  408.   INDENT(LAYLINE(HEADER));
  409.   strcat(LAYLINE(HEADER),SectionHeader);
  410.   RJust(LAYLINE(HEADER),RefItems);
  411.   OutputPage();
  412.   strcpy(RefItems,LastRefItem);
  413. }
  414.  
  415. /*
  416. ** ----------------------------------------------------------------------
  417. */
  418.  
  419. void CommandLine(l)
  420. char *l;
  421. /*
  422. ** Process line containing dot-command
  423. */
  424. {
  425.   int n;
  426.  
  427.   strupr(l);
  428.   for(n=0;Commands[n].Cmd != NULL_CP && strcmp(Commands[n].Cmd,l); n++)
  429.     ;
  430.   if(Commands[n].Cmd != NULL_CP && Commands[n].CmdHand != NULL)
  431.     (*Commands[n].CmdHand)(strtok(NULL_CP,NULL_CP));
  432. }
  433.  
  434. /*
  435. ** ----------------------------------------------------------------------
  436. */
  437.  
  438. void CmdCO(l)
  439. char *l;
  440. /*
  441. ** Get new copyright notice and place it into the current footer
  442. */
  443. {
  444.   void UpdateFooter();
  445.  
  446.   strncpy(Copyright,l,CO_LEN);
  447.   UpdateFooter();
  448. }
  449.  
  450. /*
  451. ** ----------------------------------------------------------------------
  452. */
  453.  
  454. void CmdHS(l)
  455. char *l;
  456. /*
  457. ** Change character used to draw the headline/footer divider
  458. */
  459. {
  460.   void UpdateDividers();
  461.   char *InitDivider();
  462.  
  463.   if(*l) {
  464.     LineChar = *l;
  465.     Divider = InitDivider(Divider,LineChar);
  466.     UpdateDividers();
  467.   }
  468. }
  469.  
  470. /*
  471. ** ----------------------------------------------------------------------
  472. */
  473.  
  474. void CmdRS(l)
  475. char *l;
  476. /*
  477. ** Change character used to draw the reference item divider
  478. */
  479. {
  480.   void UpdateDividers();
  481.   char *InitDivider();
  482.  
  483.   if(*l) {
  484.     RefSepChar = *l;
  485.     RefSep = InitDivider(RefSep,RefSepChar);
  486.   }
  487. }
  488.  
  489. /*
  490. ** ----------------------------------------------------------------------
  491. */
  492.  
  493. void CmdSE(l)
  494. char *l;
  495. /*
  496. ** Start new section. This action includes the "End of Reference Section"
  497. ** and "Page Break" commands.
  498. */
  499. {
  500.   void CmdER();
  501.  
  502.   CmdER();
  503.   strncpy(SectionHeader,l,LineLength);
  504. }
  505.  
  506. /*
  507. ** ----------------------------------------------------------------------
  508. */
  509.  
  510. void CmdPL(l)
  511. char *l;
  512. /*
  513. ** Adjust page length. This command is ignored whenever it is encountered
  514. ** in the middle of a page.
  515. */
  516. {
  517.   void InitLayout();
  518.   void ClearPage();
  519.  
  520.   if(*l && Line==TEXTSTART) {              /* Only at beginning of page */
  521.     sscanf(l,"%d",&PageLength);
  522.     InitLayout();
  523.     ClearPage();
  524.   }
  525. }
  526.  
  527. /*
  528. ** ----------------------------------------------------------------------
  529. */
  530.  
  531. void CmdPA()
  532. /*
  533. ** Unconditional page break, even if the current page is empty
  534. */
  535. {
  536.   void PageBreak();
  537.  
  538.   LayoutChanged = TRUE;
  539.   PageBreak();
  540. }
  541.  
  542. /*
  543. ** ----------------------------------------------------------------------
  544. */
  545.  
  546. void CmdID(l)
  547. char *l;
  548. /*
  549. ** Change number of characters, each line (including dividers, headers...)
  550. ** is indented
  551. */
  552. {
  553.   if(*l)
  554.     sscanf(l,"%d",&Indent);
  555. }
  556.  
  557. /*
  558. ** ----------------------------------------------------------------------
  559. */
  560.  
  561. void CmdML(l)
  562. char *l;
  563. /*
  564. ** Whenever the end of a reference entry is encountered, this value is
  565. ** used to decide, whether it is wise to start the next entry on the
  566. ** current page. If less than MinLines+3 lines are free, a page break
  567. ** is inserted and the new entry starts on the following page.
  568. */
  569. {
  570.   if(*l)
  571.     sscanf(l,"%d",&MinLines);
  572. }
  573.  
  574. /*
  575. ** ----------------------------------------------------------------------
  576. */
  577.  
  578. void CmdRM(l)
  579. char *l;
  580. /*
  581. ** Change number of characters to be left free at the right of each line
  582. */
  583. {
  584.   if(*l)
  585.     sscanf(l,"%d",&RightMargin);
  586. }
  587.  
  588. /*
  589. ** ----------------------------------------------------------------------
  590. */
  591.  
  592. void CmdLL(l)
  593. char *l;
  594. /*
  595. ** Adjust the number of characters per line
  596. */
  597. {
  598.   if(*l && Line==TEXTSTART) {              /* Only at beginning of page */
  599.     sscanf(l,"%d",&LineLength);
  600.     InitLayout();
  601.     Divider = InitDivider(Divider,LineChar);
  602.     RefSep  = InitDivider(RefSep,RefSepChar);
  603.     ClearPage();
  604.   }
  605. }
  606.  
  607. /*
  608. ** ----------------------------------------------------------------------
  609. */
  610.  
  611. void CmdRE(l)
  612. char *l;
  613. /*
  614. ** Start of Reference-Entry. This command implies the end of the
  615. ** previous entry if no "End of Reference Entry" command has been
  616. ** processed so far.
  617. */
  618. {
  619.   void CmdEE();
  620.  
  621.   if(!IgnoreLine && *RefItems)
  622.     CmdEE();
  623.   IgnoreLine = FALSE;
  624.  
  625.   strcpy(LastRefItem,strtok(l,TOKSEP));
  626.   if(*RefItems) {
  627.     strcat(RefItems," / ");
  628.     strcat(RefItems,LastRefItem);
  629.   }
  630.   else
  631.     strcpy(RefItems,LastRefItem);
  632. }
  633.  
  634. /*
  635. ** ----------------------------------------------------------------------
  636. */
  637.  
  638. void CmdEE()
  639. /*
  640. ** End of Reference Entry. For page break handling, please refer to
  641. ** the description of the ML-command.
  642. */
  643. {
  644.   void PageBreak();
  645.  
  646.   IgnoreLine = TRUE;
  647.   *LastRefItem = '\0';
  648.  
  649.   if(!LayoutChanged) {    /* Entry just fitted on the last page! */
  650.     *RefItems = '\0';
  651.     return;
  652.   }
  653.  
  654.   if(LINES_REM < MIN_LINES)  /* See if we'd better insert a page break */
  655.     PageBreak();
  656.   else {
  657.     INDENT(LAYLINE(Line+1));
  658.     strcat(LAYLINE(Line+1),RefSep);
  659.     Line += 3;
  660.   }
  661. }
  662.  
  663. /*
  664. ** ----------------------------------------------------------------------
  665. */
  666.  
  667. void CmdER()
  668. /*
  669. ** End of Reference Section. This implies a page break.
  670. */
  671. {
  672.   void PageBreak();
  673.  
  674.   IgnoreLine = FALSE;
  675.   *LastRefItem = '\0';
  676.   PageBreak();
  677. }
  678.  
  679. /*
  680. ** --------------------------------------------------------------------------
  681. ** --------------------------  ENDE DES MODULS ------------------------------
  682. ** --------------------------------------------------------------------------
  683. */
  684.