home *** CD-ROM | disk | FTP | other *** search
/ PC Press 1997 July / Sezamfile97_1.iso / msdos / c / cbase11.a03 / CBASE11.ZIP / MANX / MANX.C < prev    next >
C/C++ Source or Header  |  1993-01-01  |  12KB  |  431 lines

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