home *** CD-ROM | disk | FTP | other *** search
- /*///////////////////////////////////////////////////////////////////////////
- /// Module...: doclist.c ///
- /// Version..: 1.00 ///
- /// Author...: Christian Philipps ///
- /// Düsseldorfer Str. 316 ///
- /// 4130 Moers 1 ///
- /// Date.....: March 1989 ///
- /////////////////////////////////////////////////////////////////////////////
- /// ///
- /// DocList is a simple to handle and yet powerful software manual ///
- /// formatter. ///
- /// A variety of dot-commands supports section headers, page format, ///
- /// copyright notice in footer, indentation and the ability to ma- ///
- /// nage reference section headlines. The latter ones are similar to ///
- /// those found in Turbo Power Software's Reference Manuals. ///
- /// ///
- /// DocList was primarily developed in order to ease the maintenance ///
- /// of largish, normally alphabetically ordered reference sections. ///
- /// Inserting new entries manually is quite difficult because you ///
- /// will have to shift all entries following the new one backwards. ///
- /// Page breaks will have to be adjusted and Headlines, designed to ///
- /// allow for easy access will have to be changed accordingly - puhh..///
- /// ///
- /// Well, after having done so twice, I decided to write some program ///
- /// to format my on-disk ShareWare Manuals for printout the way I ///
- /// want. In addition to easy hadling, the unformatted text files ///
- /// consume less diskspace and may be kept in plain ASCII. ///
- /// ///
- /// DocList now is what I came up with! Play with it, change it, ///
- /// love it or even scrap it. - The program is hereby placed in the ///
- /// public domaine and it's up to you to adapt it to your needs. ///
- /// If you feel you have greatly enhanced the program, please re- ///
- /// lease your new version in the public domaine to allow others to ///
- /// share the tool. ///
- /// ///
- /// Best regards, Christian Philipps (March, 14, 1989) ///
- /// ///
- ///////////////////////////////////////////////////////////////////////////*/
-
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
- #include <memory.h>
-
- /*
- ** Some general purpose definitions
- */
- #define NULL_FP (FILE *)NULL
- #define NULL_CP (char *)NULL
- #ifndef TRUE
- # define TRUE (1==1)
- #endif
- #ifndef FALSE
- # define FALSE (0==1)
- #endif
- #ifndef BOOLEAN
- # define BOOLEAN int
- #endif
-
- #define TOKSEP " \t" /* Token-Seperator for strtok() */
-
- /*
- ** Dot-Command dispatch table
- */
- typedef struct cmd_t {
- char *Cmd;
- void (*CmdHand)();
- } CMD_T;
-
- void CmdCO(); /* Each function hadles the command corresponding to */
- void CmdSE(); /* the last two characters of its name */
- void CmdPL();
- void CmdPA();
- void CmdID();
- void CmdRM();
- void CmdLL();
- void CmdRE();
- void CmdER();
- void CmdEE();
- void CmdML();
- void CmdHS();
- void CmdRS();
-
- static CMD_T Commands[] = {
- { "CO", CmdCO }, /* Copyright notice */
- { "PA", CmdPA }, /* Page Break */
- { "PL", CmdPL }, /* Page Length */
- { "SE", CmdSE }, /* Section */
- { "RE", CmdRE }, /* Reference Entry */
- { "ER", CmdER }, /* End of Reference Section */
- { "EE", CmdEE }, /* End of Reference Entry */
- { "HS", CmdHS }, /* Headline-Seperator Character */
- { "RS", CmdRS }, /* Reference-Seperator Character */
- { "LL", CmdLL }, /* Line Length */
- { "ID", CmdID }, /* Indentation */
- { "RM", CmdRM }, /* Right Margin */
- { "ML", CmdML }, /* Minimum lines on current page remaining */
- /* to start new reference entry */
- /* More entries may be inserted here */
- { NULL_CP, NULL } /* End of Table marker */
- };
-
- typedef char workstr[200];
-
- /*
- ** Overall defaults
- */
- int PageLength = 66;
- int LineLength = 80;
- int Indent = 5;
- int RightMargin= 5;
- int MinLines = 7;
- char LineChar = '═';
- char RefSepChar = '─';
-
- /*
- ** Macros and definitions used offset and length calculations
- */
- #define LINEDATA (LineLength-Indent-RightMargin)
- #define LAYLINE(N) (Layout+((N)*(LineLength+1)))
- #define HEADER 3
- #define HEADLEN 2
- #define TEXTSTART (HEADER+HEADLEN+2)
- #define FOOTLEN 7
- #define FOOTER (PageLength-FOOTLEN)
- #define TEXTEND (FOOTER-3)
- #define INDENT(L) { memset(L,'\0',LineLength+1); memset(L,' ',Indent); }
- #define CO_LEN (LineLength-20)
- #define LINES_REM (TEXTEND-Line+1)
- #define MIN_LINES (MinLines+3) /* plus size of divider line */
-
- /*
- ** Page layout
- */
- char *Layout = NULL_CP;
- BOOLEAN LayoutChanged = FALSE;
-
- /*
- ** global workspace
- */
- char *Divider = NULL_CP; /* Hedline divider */
- char *RefSep = NULL_CP; /* Reference entry seperator */
-
- int Page;
- int Line;
- BOOLEAN IgnoreLine = FALSE;
-
- workstr Copyright = "";
- workstr RefItems;
- workstr LastRefItem;
- workstr SectionHeader;
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- main(argc,argv)
- int argc;
- char **argv;
- {
- void Usage();
- void ListDoc();
- void InitLayout();
- char *InitDivider();
-
- if(argc < 2)
- Usage();
-
- InitLayout();
- Divider = InitDivider(Divider,LineChar);
- RefSep = InitDivider(RefSep,RefSepChar);
-
- if(stricmp("-s",argv[1]) != 0) {
- while(--argc)
- ListDoc(*(++argv));
- }
- else { /* use stdin */
- ListDoc(NULL_CP);
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void InitLayout()
- /*
- ** Physically reserve space to hold the formatted page layout
- */
- {
- if(Layout != NULL_CP)
- free(Layout);
- if((Layout=(char *)calloc(1,PageLength*(LineLength+1))) == NULL_CP) {
- fputs("Sorry! - Couldn't allocate page layout!\n",stderr);
- exit(1);
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- char *InitDivider(Divider,c)
- char *Divider;
- char c;
- /*
- ** Physically allocate space to hold a divider line
- */
- {
- if(Divider != NULL_CP)
- free(Divider);
- if((Divider=(char *)calloc(1,LINEDATA+1)) == NULL_CP) {
- fputs("Sorry! - Couldn't allocate divider line!\n",stderr);
- exit(1);
- }
- memset(Divider,c,LINEDATA);
- return(Divider);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void RJust(l,txt)
- char *l;
- char *txt;
- /*
- ** Place txt in layout line, justified right
- */
- {
- int n, m;
-
- m=strlen(l);
- n=LineLength-m-strlen(txt)-RightMargin;
- if(n < 0) /* Skip */
- return;
- memset(l+m,' ',n);
- strcat(l,txt);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void UpdateFooter()
- /*
- ** Update footer display in the page layout buffer
- */
- {
- void RJust();
-
- char pgnr[15];
-
- INDENT(LAYLINE(FOOTER+1));
- strcat(LAYLINE(FOOTER+1),Copyright);
- sprintf(pgnr,"Seite: %3d",Page);
- RJust(LAYLINE(FOOTER+1),pgnr);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void UpdateDividers()
- /*
- ** Update hedline/footer dividers in the page layout buffer
- */
- {
- INDENT(LAYLINE(HEADER+1));
- INDENT(LAYLINE(FOOTER));
- strcat(LAYLINE(HEADER+1),Divider);
- strcat(LAYLINE(FOOTER),Divider);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void ClearPage()
- {
- void UpdateFooter();
- void UpdateDividers();
-
- int n;
-
- for(n=0;n<PageLength;n++)
- *LAYLINE(n)='\0';
- UpdateFooter();
- UpdateDividers();
- LayoutChanged = FALSE;
- Line = TEXTSTART;
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void OutputPage()
- /*
- ** Output current content of the page layout buffer to stdout and
- ** finally re-initialize it. The current page number is incremented.
- */
- {
- void ClearPage();
-
- int n;
-
- if(!LayoutChanged) /* Only if something has changed */
- return;
-
- for(n=0;n<PageLength;n++)
- printf("%s\n",LAYLINE(n));
- Page++;
- ClearPage();
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void Usage()
- {
- fputs("Documentation Lister V1.00 / March 1989\n",stderr);
- fputs("Author: Christian Philipps, Moers, West-Germany\n",stderr);
- fputs("This program is hereby placed in the public domaine!\n\n",stderr);
- fputs("Usage: doclist [-s < infile | file [...]] > outfile\n",stderr);
- exit(1);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void ListDoc(fname)
- char *fname;
- /*
- ** Format single file for print
- */
- {
- void ListLine();
- void CommandLine();
- void ClearPage();
- void PageBreak();
-
- FILE *f;
- workstr line;
-
- if(!*fname) {
- f=stdin;
- }
- else {
- if((f=fopen(fname,"rt"))==NULL_FP) {
- fprintf(stderr,"Error opening %s!\n",fname);
- return;
- }
- }
- Page = 1;
- *LastRefItem = *RefItems = *SectionHeader = '\0';
- ClearPage();
- while(fgets(line,sizeof(line),f) != NULL_CP) {
- line[strlen(line)-1] = '\0'; /* Cut \n */
- if(*line=='.')
- CommandLine(strtok(line+1,TOKSEP));
- else
- ListLine(line);
- }
- fclose(f);
- PageBreak();
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void ListLine(l)
- char *l;
- /*
- ** Process line of text; perform page break if necessary
- */
- {
- void PageBreak();
-
- if(IgnoreLine) /* between .EE ... .RE */
- return;
-
- INDENT(LAYLINE(Line));
- strncat(LAYLINE(Line),l,LINEDATA);
- LayoutChanged = TRUE;
- if(++Line > TEXTEND)
- PageBreak();
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void PageBreak()
- /*
- ** Perform page break, thereby outputting the current page to stdout.
- ** Update the list of items referenced on the current page. Care must
- ** be taken to keep the name of the last item mentioned if it is to
- ** be continued on the next page.
- */
- {
- void OutputPage();
- void RJust();
-
- INDENT(LAYLINE(HEADER));
- strcat(LAYLINE(HEADER),SectionHeader);
- RJust(LAYLINE(HEADER),RefItems);
- OutputPage();
- strcpy(RefItems,LastRefItem);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CommandLine(l)
- char *l;
- /*
- ** Process line containing dot-command
- */
- {
- int n;
-
- strupr(l);
- for(n=0;Commands[n].Cmd != NULL_CP && strcmp(Commands[n].Cmd,l); n++)
- ;
- if(Commands[n].Cmd != NULL_CP && Commands[n].CmdHand != NULL)
- (*Commands[n].CmdHand)(strtok(NULL_CP,NULL_CP));
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdCO(l)
- char *l;
- /*
- ** Get new copyright notice and place it into the current footer
- */
- {
- void UpdateFooter();
-
- strncpy(Copyright,l,CO_LEN);
- UpdateFooter();
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdHS(l)
- char *l;
- /*
- ** Change character used to draw the headline/footer divider
- */
- {
- void UpdateDividers();
- char *InitDivider();
-
- if(*l) {
- LineChar = *l;
- Divider = InitDivider(Divider,LineChar);
- UpdateDividers();
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdRS(l)
- char *l;
- /*
- ** Change character used to draw the reference item divider
- */
- {
- void UpdateDividers();
- char *InitDivider();
-
- if(*l) {
- RefSepChar = *l;
- RefSep = InitDivider(RefSep,RefSepChar);
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdSE(l)
- char *l;
- /*
- ** Start new section. This action includes the "End of Reference Section"
- ** and "Page Break" commands.
- */
- {
- void CmdER();
-
- CmdER();
- strncpy(SectionHeader,l,LineLength);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdPL(l)
- char *l;
- /*
- ** Adjust page length. This command is ignored whenever it is encountered
- ** in the middle of a page.
- */
- {
- void InitLayout();
- void ClearPage();
-
- if(*l && Line==TEXTSTART) { /* Only at beginning of page */
- sscanf(l,"%d",&PageLength);
- InitLayout();
- ClearPage();
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdPA()
- /*
- ** Unconditional page break, even if the current page is empty
- */
- {
- void PageBreak();
-
- LayoutChanged = TRUE;
- PageBreak();
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdID(l)
- char *l;
- /*
- ** Change number of characters, each line (including dividers, headers...)
- ** is indented
- */
- {
- if(*l)
- sscanf(l,"%d",&Indent);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdML(l)
- char *l;
- /*
- ** Whenever the end of a reference entry is encountered, this value is
- ** used to decide, whether it is wise to start the next entry on the
- ** current page. If less than MinLines+3 lines are free, a page break
- ** is inserted and the new entry starts on the following page.
- */
- {
- if(*l)
- sscanf(l,"%d",&MinLines);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdRM(l)
- char *l;
- /*
- ** Change number of characters to be left free at the right of each line
- */
- {
- if(*l)
- sscanf(l,"%d",&RightMargin);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdLL(l)
- char *l;
- /*
- ** Adjust the number of characters per line
- */
- {
- if(*l && Line==TEXTSTART) { /* Only at beginning of page */
- sscanf(l,"%d",&LineLength);
- InitLayout();
- Divider = InitDivider(Divider,LineChar);
- RefSep = InitDivider(RefSep,RefSepChar);
- ClearPage();
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdRE(l)
- char *l;
- /*
- ** Start of Reference-Entry. This command implies the end of the
- ** previous entry if no "End of Reference Entry" command has been
- ** processed so far.
- */
- {
- void CmdEE();
-
- if(!IgnoreLine && *RefItems)
- CmdEE();
- IgnoreLine = FALSE;
-
- strcpy(LastRefItem,strtok(l,TOKSEP));
- if(*RefItems) {
- strcat(RefItems," / ");
- strcat(RefItems,LastRefItem);
- }
- else
- strcpy(RefItems,LastRefItem);
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdEE()
- /*
- ** End of Reference Entry. For page break handling, please refer to
- ** the description of the ML-command.
- */
- {
- void PageBreak();
-
- IgnoreLine = TRUE;
- *LastRefItem = '\0';
-
- if(!LayoutChanged) { /* Entry just fitted on the last page! */
- *RefItems = '\0';
- return;
- }
-
- if(LINES_REM < MIN_LINES) /* See if we'd better insert a page break */
- PageBreak();
- else {
- INDENT(LAYLINE(Line+1));
- strcat(LAYLINE(Line+1),RefSep);
- Line += 3;
- }
- }
-
- /*
- ** ----------------------------------------------------------------------
- */
-
- void CmdER()
- /*
- ** End of Reference Section. This implies a page break.
- */
- {
- void PageBreak();
-
- IgnoreLine = FALSE;
- *LastRefItem = '\0';
- PageBreak();
- }
-
- /*
- ** --------------------------------------------------------------------------
- ** -------------------------- ENDE DES MODULS ------------------------------
- ** --------------------------------------------------------------------------
- */
-