home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / CBASE101.ZIP / BLKIO112.ZIP / MANX111.ZIP / MANX.C < prev    next >
Text File  |  1990-04-18  |  11KB  |  399 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "@(#)manx.c    1.3 - 90/04/18" */
  5.  
  6. #if __STDC__ == 1
  7. #include <errno.h>
  8. #include <limits.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12.  
  13. static int manputs(const char *cs, FILE *fp);
  14. #else
  15. #include <errno.h>
  16. #include <limits.h>
  17. #include <stdio.h>
  18. void exit();            /* stdlib.h */
  19. long strtol();
  20. #ifndef EXIT_SUCCESS
  21. #define EXIT_SUCCESS    (0)
  22. #define EXIT_FAILURE    (1)
  23. #endif
  24. char *strstr();            /* string.h */
  25. int strcmp();
  26. int strncmp();
  27.  
  28. static int manputs();
  29. #endif    /* #if __STDC__ == 1 */
  30.  
  31. #define PAGELEN        (60)    /* default page length */
  32. #define BACKSLASH    ('\\')    /* char to begin escape sequence */
  33. #define PAGINATOR    ("\f")    /* string to use as page separator */
  34. #define LINELEN_MAX    (256)    /* maximum line length */
  35.  
  36. typedef struct {        /* language definition structure */
  37.     char option[11];    /* language command line option */
  38.     char begin[21];        /* marker for beginning of manual entry */
  39.     char end[21];        /* marker for end of manual entry */
  40.     char comment[11];    /* character sequence that begins comment */
  41.     int  flags;        /* flags */
  42. } lang_t;
  43.  
  44. /* lang_t bit flags */
  45. #define LINECMT        (1)
  46. #define BLOCKCMT    (2)
  47.  
  48. /* language definitions */
  49. lang_t langs[] = {
  50.     {"a",  "--man", "--end", "--", LINECMT},    /* Ada */
  51.     {"as", ";man",  ";end",  ";",  LINECMT},    /* ASM */
  52.     {"c",  "/*man", "*/",    "/*", BLOCKCMT},    /* C */
  53.     {"f",  "Cman", "Cend",   "C",  LINECMT},    /* Fortran */
  54.     {"l",  ";man", ";end",   ";",  LINECMT},    /* Lisp */
  55.     {"m",  "(*man", "*)",    "(*", BLOCKCMT},    /* Modula-2 */
  56.     {"p",  "{man",  "}",     "{",  BLOCKCMT},    /* Pascal */
  57.     {"pl", "\"man", "\"",    "\"", BLOCKCMT},    /* Prolog */
  58.     {"st", "\"man", "\"",    "\"", BLOCKCMT}    /* Smalltalk */
  59. };
  60.  
  61. /* index into langs array for each language */
  62. #define ADA        (1)
  63. #define ASM        (2)
  64. #define C        (3)
  65. #define FORTRAN        (4)
  66. #define LISP        (5)
  67. #define MODULA_2    (6)
  68. #define PASCAL        (7)
  69. #define PROLOG        (8)
  70. #define SMALLTALK    (9)
  71.  
  72. #define LANG        C        /* default language */
  73.  
  74. /* command syntax */
  75. #define USAGE        ("Usage: manx [language] [page-length]")
  76.  
  77. /*man---------------------------------------------------------------------------
  78. NAME
  79.      manx - manual entry extracter
  80.  
  81. SYNOPSIS
  82.      manx [language] [page-length]
  83.  
  84. DESCRIPTION
  85.      The manx command extracts manual entries from source files.  The
  86.      source files are read from stdin and the manual entries are
  87.      written to stdout.  Each individual manual entry is separated
  88.      into pages by form feeds and terminated with a form feed.
  89.  
  90.      The language option specifies the language of the source file.
  91.      The languages supported are:
  92.  
  93.                            Ada           -a
  94.                            assembly      -as
  95.                            C             -c
  96.                            Fortran       -f
  97.                            Lisp          -l
  98.                            Modula-2      -m
  99.                            Pascal        -p
  100.                            Prolog        -pl
  101.                            Smalltalk     -st
  102.  
  103.      The default language is C.
  104.  
  105.      The page-length argument can be used to set the page length.
  106.      Pagination may be disabled by specifying a page length of 0.
  107.      The default page length is 60.
  108.  
  109.      The beginning of a manual entry is marked by the character
  110.      sequence (language dependent) to start a comment immediately
  111.      followed by the characters 'man'.  This marker must appear in the
  112.      leftmost column allowed by the language.  For block comments, the
  113.      end of the manual entry is marked by the end of the comment.  For
  114.      line comments, the end of a manual entry is marked by the
  115.      character sequence to end a comment immediately followed by the
  116.      characters 'end'.  All lines between but not including these
  117.      constitute the manual entry.
  118.  
  119.      The following escape sequences can be used within a manual entry:
  120.  
  121.                   audible alert       BEL       \\a
  122.                   backspace           BS        \\b
  123.                   carriage return     CR        \\r
  124.                   horizontal tab      HT        \\t
  125.                   backslash           \\         \\\\
  126.  
  127. EXAMPLE
  128.      On a UNIX system, the following command would extract the manual
  129.      pages from all C files in the current UNIX directory, paginate
  130.      them to 52 lines, and place the results in a file called manual.
  131.  
  132.           $ cat *.c | manx -c 52 > manual
  133.  
  134.      Catenating files is much for difficult in MS-DOS.  For that
  135.      system, the following sequence of commands is required.
  136.  
  137.           > copy file.c/a+file2.c+file3.c+file4.c tmp
  138.           > type tmp | manx -c 52 > manual
  139.           > del tmp
  140.  
  141.      manx works particularly well when used in conjunction with a make
  142.      utility.  Below are the relevant parts of the UNIX makefile of an
  143.      actual C library for which manx is used to extract the reference
  144.      manual.
  145.  
  146.           LIB     = blkio
  147.           MAN     = $(LIB).man
  148.  
  149.           MANFILES=blkio.h                               \\
  150.                   bclose.c bexit.c  bflpop.c  bflpush.c  \\
  151.                   bflush.c bgetb.c  bgetbf.c  bgeth.c    \\
  152.                   bgethf.c bopen.c  bputb.c   bputbf.c   \\
  153.                   bputh.c  bputhf.c bsetbuf.c bsetvbuf.c \\
  154.                   bsync.c  lockb.c
  155.  
  156.           man:    $(MANFILES)
  157.                   cat $(MANFILES) | manx > $(MAN)
  158.  
  159.      The reference manual for this library is generated simply by
  160.      entering
  161.  
  162.           make man
  163.  
  164. ------------------------------------------------------------------------------*/
  165. #if __STDC__ == 1
  166. int main(int argc, char *argv[])
  167. #else
  168. int main(argc, argv)
  169. int argc;
  170. char *argv[];
  171. #endif
  172. {
  173.     char *    endptr        = NULL;        /* pointer for strtol fct */
  174.     int    i        = 0;        /* loop index */
  175.     int    lang        = LANG;        /* default language */
  176.     long    line        = 0;        /* line number */
  177.     int    page        = 0;        /* page number */
  178.     long    pagelen        = PAGELEN;    /* default page length */
  179.     char    s[LINELEN_MAX + 1];        /* input line */
  180.  
  181.     /* process command line options and arguments */
  182.     /* language option */
  183.     if ((argc > 1) && (*argv[1] == '-')) {
  184.         --argc;
  185.         ++argv;
  186.         lang = 0;
  187.         for (i = 0; i < sizeof(langs)/sizeof(*langs); ++i) {
  188.             if (strcmp(*argv + 1, langs[i].option) == 0) {
  189.                 lang = i + 1;
  190.                 break;
  191.             }
  192.         }
  193.         if (lang == 0) {
  194.             puts("manx: invalid language option");
  195.             puts(USAGE);
  196.             exit(EXIT_FAILURE);
  197.         }
  198.     }
  199.     /* page length argument */
  200.     if (argc > 1) {
  201.         --argc;
  202.         ++argv;
  203.         errno = 0;
  204.         pagelen = strtol(*argv, &endptr, 10);
  205.         if (errno == ERANGE) {
  206.             puts("manx: page length argument out of range");
  207.             puts(USAGE);
  208.             exit(EXIT_FAILURE);
  209.         }
  210.         if (endptr != NULL) {
  211.             if (endptr[0] != '\0') {
  212.                 puts(USAGE);
  213.                 exit(EXIT_FAILURE);
  214.             }
  215.         }
  216.         if (pagelen < 0) {
  217.             puts(USAGE);
  218.             exit(EXIT_FAILURE);
  219.         }
  220.     }
  221.     if (argc != 1) {
  222.         puts(USAGE);
  223.         exit(EXIT_FAILURE);
  224.     }
  225.  
  226.     /* main loop */
  227.     for (;;) {
  228.         /* read next line of input */
  229.         if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  230.             if (ferror(stdin) != 0) {
  231.                 fprintf(stderr, "*** Error reading standard input.  Exiting.\n");
  232.                 exit(EXIT_FAILURE);
  233.             }
  234.             break;
  235.         }
  236.         /* check for manual entry marker at beginning of line */
  237.         if (strncmp(s, langs[lang - 1].begin, strlen(langs[lang - 1].begin)) != 0) {
  238.             continue;
  239.         }
  240.         if (langs[lang - 1].flags & BLOCKCMT) {
  241.             if (strstr(s, langs[lang - 1].end) != NULL) {
  242.                 continue;
  243.             }
  244.         }
  245.         /* inner loop */
  246.         line = 0;
  247.         page = 1;
  248.         for (;;) {
  249.             ++line;
  250.             /* read next line of manual entry */
  251.             if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  252.                 if (ferror(stdin) != 0) {
  253.                     fprintf(stderr, "*** Error reading standard input.  Exiting.\n");
  254.                     exit(EXIT_FAILURE);
  255.                 }
  256.                 break;
  257.             }
  258.             /* check for end of entry marker */
  259.             if (langs[lang - 1].flags & LINECMT) {
  260.                 if (strncmp(s, langs[lang - 1].end, strlen(langs[lang - 1].end)) == 0) {
  261.                     break;
  262.                 }
  263.                 if (strncmp(s, langs[lang - 1].comment, strlen(langs[lang - 1].comment)) != 0) {
  264.                     break;
  265.                 }
  266.             } else {
  267.                 if (strstr(s, langs[lang - 1].end) != NULL) {
  268.                     break;
  269.                 }
  270.             }
  271.             if (s[strlen(s) - 1] != '\n') {
  272.                 fprintf(stderr, "*** Warning.  Maximum line length of %d exceeded.  Page %ld, line %ld.\n", (int)(sizeof(s) - 2), page, line);
  273.                 s[strlen(s) - 1] = '\n';
  274.             }
  275.             if (langs[lang - 1].flags & LINECMT) {
  276.                 if (manputs(s + strlen(langs[lang - 1].comment) , stdout) == -1) {
  277.                     fprintf(stderr, "*** Error writing line %ld, of page %ld.  Exiting\n", line, page);
  278.                     exit(EXIT_FAILURE);
  279.                 }
  280.             } else {
  281.                 if (manputs(s, stdout) == -1) {
  282.                     fprintf(stderr, "*** Error writing line %ld, of page %ld.  Exiting\n", line, page);
  283.                     exit(EXIT_FAILURE);
  284.                 }
  285.             }
  286.             if ((line >= pagelen) && (pagelen != 0)) {
  287.                 if (fputs(PAGINATOR, stdout) == EOF) {
  288.                     fprintf(stderr, "*** Error writing paginator to standard output.  Exiting.\n");
  289.                     exit(EXIT_FAILURE);
  290.                 }
  291.                 line = 0;
  292.                 ++page;
  293.             }
  294.         }
  295.         /* write last paginator */
  296.         if ((line != 1) && (pagelen != 0)) {
  297.             if (fputs(PAGINATOR, stdout) == EOF) {
  298.                 fprintf(stderr, "*** Error writing paginator to standard output.  Exiting.\n");
  299.                 exit(EXIT_FAILURE);
  300.             }
  301.             ++page;
  302.         }
  303.         /* check if end of file */
  304.         if (feof(stdin) != 0) {
  305.             break;
  306.         }
  307.     }
  308.  
  309.     exit(EXIT_SUCCESS);
  310. }
  311.  
  312. /*------------------------------------------------------------------------------
  313. DESCRIPTION
  314.      The manputs function writes the null-terminated string pointed to
  315.      by cs to the named output stream.  Any manx escape sequence found
  316.      in the string is converted to the character it represents before
  317.      being output.
  318.  
  319. DIAGNOSTICS
  320.      Upon successful completion, a value of 0 is returned.  Otherwise,
  321.      a value of -1 is returned.
  322.  
  323. ------------------------------------------------------------------------------*/
  324. #if __STDC__ == 1
  325. static int manputs(const char *cs, FILE *fp)
  326. #else
  327. static int manputs(cs, fp)
  328. char *cs;
  329. FILE *fp;
  330. #endif
  331. {
  332.     char t[LINELEN_MAX + 1];    /* target string */
  333.     int i = 0;            /* index into target string */
  334.     char c = '\0';
  335.  
  336.     /* convert string to output format */
  337.     for (i = 0; *cs != '\0'; ++i) {
  338.         if (i > sizeof(t)) {
  339.             return -1;
  340.         }
  341.         c = *cs++;
  342.         /* check for escape sequence */
  343.         if ((c == BACKSLASH) && (*cs != '\0')) {
  344.             c = *cs++;
  345.             switch (c) {
  346.             case 'a':    /* audible alert */
  347.                 c = '\a';
  348.                 break;    /* case 'a': */
  349.             case 'b':    /* backspace */
  350.                 c = '\b';
  351.                 break;    /* case 'b': */
  352.             case 'r':    /* carriage return */
  353.                 c = '\r';
  354.                 break;    /* case 'r': */
  355.             case 't':    /* horizontal tab */
  356.                 c = '\t';
  357.                 break;    /* case 't': */
  358.             case '\\':    /* backslash */
  359.                 c = '\\';
  360.                 break;    /* case '\\': */
  361.             default:    /* ignore backslash */
  362.                 break;    /* default: */
  363.             }
  364.         }
  365.         t[i] = c;
  366.     }
  367.     t[i] = '\0';
  368.  
  369.     /* write converted string to fp */
  370.     if (fputs(t, fp) == EOF) {
  371.         return -1;
  372.     }
  373.  
  374.     return 0;
  375. }
  376.  
  377. #if __STDC__ != 1
  378. static char *strstr(cs, ct)
  379. char *cs;
  380. char *ct;
  381. {
  382.     int ctlen = 0;
  383.  
  384.     if (cs == NULL || ct == NULL) {
  385.         return NULL;
  386.     }
  387.  
  388.     ctlen = strlen(ct);
  389.     while (*cs != '\0') {
  390.         if (strncmp(cs, ct, ctlen) == 0) {
  391.             return cs;
  392.         }
  393.         ++cs;
  394.     }
  395.  
  396.     return NULL;
  397. }
  398. #endif
  399.