home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / indent / io.c < prev    next >
C/C++ Source or Header  |  1999-05-21  |  23KB  |  997 lines

  1. /* Copyright (c) 1992, Free Software Foundation, Inc.  All rights reserved.
  2.  
  3.    Copyright (c) 1985 Sun Microsystems, Inc. Copyright (c) 1980 The Regents
  4.    of the University of California. Copyright (c) 1976 Board of Trustees of
  5.    the University of Illinois. All rights reserved.
  6.  
  7.    Redistribution and use in source and binary forms are permitted
  8.    provided that
  9.    the above copyright notice and this paragraph are duplicated in all such
  10.    forms and that any documentation, advertising materials, and other
  11.    materials related to such distribution and use acknowledge that the
  12.    software was developed by the University of California, Berkeley, the
  13.    University of Illinois, Urbana, and Sun Microsystems, Inc.  The name of
  14.    either University or Sun Microsystems may not be used to endorse or
  15.    promote products derived from this software without specific prior written
  16.    permission. THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.    IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
  18.    OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */
  19.  
  20.  
  21. #include "sys.h"
  22. #include "indent.h"
  23. #include <ctype.h>
  24.  
  25. /* POSIX says that <fcntl.h> should exist.  Some systems might need to use
  26.    <sys/fcntl.h> or <sys/file.h> instead.  */
  27. #include <fcntl.h>
  28.  
  29. #ifdef AMIGA
  30. #include <exec/types.h>
  31. #include <libraries/dos.h>
  32. #include <proto/dos.h>
  33. #else /* !AMIGA */
  34. #include <sys/types.h>
  35. #include <sys/stat.h>
  36. #endif /* !AMIGA */
  37.  
  38. /* number of levels a label is placed to left of code */
  39. #define LABEL_OFFSET 2
  40.  
  41.  
  42. /* Stuff that needs to be shared with the rest of indent. Documented in
  43.    indent.h.  */
  44. char *in_prog;
  45. char *in_prog_pos;
  46. char *cur_line;
  47. unsigned long in_prog_size;
  48. FILE *output;
  49. char *buf_ptr;
  50. char *buf_end;
  51. int had_eof;
  52. int out_lines;
  53. int com_lines;
  54.  
  55. int suppress_blanklines = 0;
  56. static int comment_open;
  57.  
  58. int paren_target;
  59.  
  60. /* Use `perror' to print the system error message
  61.    caused by OFFENDER. */
  62.  
  63. static char *errbuf;
  64.  
  65. void
  66. sys_error (offender)
  67.      char *offender;
  68. {
  69.   int size = strlen (offender);
  70.   static int buffer_size;
  71.  
  72.   if (errbuf == 0)
  73.     {
  74.       buffer_size = size + 10;    /* Extra for random unix lossage */
  75.       errbuf = (char *) xmalloc (buffer_size);
  76.     }
  77.   else if (size + 10 > buffer_size)
  78.     {
  79.       buffer_size = size + 10;
  80.       errbuf = xrealloc (errbuf, buffer_size);
  81.     }
  82.   sprintf (errbuf, "indent: %s", offender);
  83.   perror (errbuf);
  84.   exit (1);
  85. }
  86.  
  87. /* true if INDENT OFF is in effect */
  88. static int inhibit_formatting;
  89.  
  90. void
  91. dump_line ()
  92. {                /* dump_line is the routine that actually
  93.                    effects the printing of the new source. It
  94.                    prints the label section, followed by the
  95.                    code section with the appropriate nesting
  96.                    level, followed by any comments */
  97.   register int cur_col;
  98.   register int target_col = 0;
  99.   static not_first_line;
  100.  
  101.   if (parser_state_tos->procname[0])
  102.     {
  103.       if (troff)
  104.     {
  105.       if (comment_open)
  106.         {
  107.           comment_open = 0;
  108.           fprintf (output, ".*/\n");
  109.         }
  110.       fprintf (output, ".Pr \"%.*s\"\n",
  111.            parser_state_tos->procname_end - parser_state_tos->procname,
  112.            parser_state_tos->procname);
  113.     }
  114.       parser_state_tos->ind_level = 0;
  115.       parser_state_tos->procname = "\0";
  116.     }
  117.  
  118.   /* A blank line */
  119.   if (s_code == e_code && s_lab == e_lab && s_com == e_com)
  120.     {
  121.       /* If we have a formfeed on a blank line, we should just output it,
  122.          rather than treat it as a normal blank line.  */
  123.       if (parser_state_tos->use_ff)
  124.     {
  125.       putc ('\014', output);
  126.       parser_state_tos->use_ff = false;
  127.     }
  128.       else
  129.     {
  130.       if (suppress_blanklines > 0)
  131.         suppress_blanklines--;
  132.       else
  133.         {
  134.           parser_state_tos->bl_line = true;
  135.           n_real_blanklines++;
  136.         }
  137.     }
  138.     }
  139.   else if (!inhibit_formatting)
  140.     {
  141.       suppress_blanklines = 0;
  142.       parser_state_tos->bl_line = false;
  143.       if (prefix_blankline_requested
  144.       && not_first_line
  145.       && n_real_blanklines == 0)
  146.     n_real_blanklines = 1;
  147.       else if (swallow_optional_blanklines && n_real_blanklines > 1)
  148.     n_real_blanklines = 1;
  149.  
  150.       while (--n_real_blanklines >= 0)
  151.     putc (EOL, output);
  152.       n_real_blanklines = 0;
  153.       if (parser_state_tos->ind_level == 0)
  154.     parser_state_tos->ind_stmt = 0;    /* this is a class A kludge. dont do
  155.                        additional statement indentation
  156.                        if we are at bracket level 0 */
  157.  
  158.       if (e_lab != s_lab || e_code != s_code)
  159.     ++code_lines;        /* keep count of lines with code */
  160.  
  161.  
  162.       if (e_lab != s_lab)
  163.     {            /* print lab, if any */
  164.       if (comment_open)
  165.         {
  166.           comment_open = 0;
  167.           fprintf (output, ".*/\n");
  168.         }
  169.       while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == TAB))
  170.         e_lab--;
  171.       cur_col = pad_output (1, compute_label_target ());
  172.       if (s_lab[0] == '#' && (strncmp (s_lab, "#else", 5) == 0
  173.                   || strncmp (s_lab, "#endif", 6) == 0))
  174.         {
  175.           /* Treat #else and #endif as a special case because any text
  176.              after #else or #endif should be converted to a comment.  */
  177.           register char *s = s_lab;
  178.           if (e_lab[-1] == EOL)
  179.         e_lab--;
  180.           do
  181.         putc (*s++, output);
  182.           while (s < e_lab && 'a' <= *s && *s <= 'z');
  183.           while ((*s == ' ' || *s == TAB) && s < e_lab)
  184.         s++;
  185.           if (s < e_lab)
  186.         {
  187.           if (s[0] == '/' && (s[1] == '*' || s[1] == '/'))
  188.             fprintf (output, (tabsize > 1 ? "\t%.*s" : "  %.*s"),
  189.                  e_lab - s, s);
  190.           else
  191.             fprintf (output, (tabsize > 1
  192.                       ? "\t/* %.*s */"
  193.                       : "  /* %.*s */"),
  194.                  e_lab - s, s);
  195.         }
  196.         }
  197.       else
  198.         fprintf (output, "%.*s", e_lab - s_lab, s_lab);
  199.       cur_col = count_spaces (cur_col, s_lab);
  200.     }
  201.       else
  202.     cur_col = 1;        /* there is no label section */
  203.  
  204.       parser_state_tos->pcase = false;
  205.  
  206.       if (s_code != e_code)
  207.     {            /* print code section, if any */
  208.       register char *p;
  209.       register i;
  210.  
  211.       if (comment_open)
  212.         {
  213.           comment_open = 0;
  214.           fprintf (output, ".*/\n");
  215.         }
  216.       target_col = compute_code_target ();
  217.       /* If a line ends in an lparen character, the following line should
  218.          not line up with the parenthesis, but should be indented by the
  219.          usual amount.  */
  220.       if (parser_state_tos->last_token == lparen)
  221.         {
  222.           parser_state_tos->paren_indents[parser_state_tos->p_l_follow - 1]
  223.         += ind_size - 1;
  224.         }
  225.  
  226.       for (i = 0; i < parser_state_tos->p_l_follow; i++)
  227.         if (parser_state_tos->paren_indents[i] >= 0)
  228.           parser_state_tos->paren_indents[i]
  229.         = -(parser_state_tos->paren_indents[i] + target_col);
  230.  
  231.       cur_col = pad_output (cur_col, target_col);
  232.       for (p = s_code; p < e_code; p++)
  233.         {
  234.           if (*p == (char) 0200)
  235.         fprintf (output, "%d", (int) (target_col * 7));
  236.           else if (tabsize > 1)
  237.         putc (*p, output);
  238.           else
  239.         {
  240.           int width = 1;
  241.           if (*p == TAB)
  242.             width = (tabsize - ((cur_col - 1) % tabsize));
  243.           cur_col += width;
  244.           while (width--)
  245.             putc (*p, output);
  246.         }
  247.         }
  248.       cur_col = count_spaces (cur_col, s_code);
  249.     }
  250.  
  251.       if (s_com != e_com)
  252.     {
  253.       if (troff)
  254.         {
  255.           int all_here = 0;
  256.           register char *p;
  257.  
  258.           if (e_com[-1] == '/' && e_com[-2] == '*')
  259.         e_com -= 2, all_here++;
  260.           while (e_com > s_com && e_com[-1] == ' ')
  261.         e_com--;
  262.           *e_com = 0;
  263.           p = s_com;
  264.           while (*p == ' ')
  265.         p++;
  266.           if (p[0] == '/' && p[1] == '*')
  267.         p += 2, all_here++;
  268.           else if (p[0] == '*')
  269.         p += p[1] == '/' ? 2 : 1;
  270.           while (*p == ' ')
  271.         p++;
  272.           if (*p == 0)
  273.         goto inhibit_newline;
  274.           if (comment_open < 2 && parser_state_tos->box_com)
  275.         {
  276.           comment_open = 0;
  277.           fprintf (output, ".*/\n");
  278.         }
  279.           if (comment_open == 0)
  280.         {
  281.           if ('a' <= *p && *p <= 'z')
  282.             *p = *p + 'A' - 'a';
  283.           if (e_com - p < 50 && all_here == 2)
  284.             {
  285.               register char *follow = p;
  286.               fprintf (output, "\n.nr C! \\w\1");
  287.               while (follow < e_com)
  288.             {
  289.               switch (*follow)
  290.                 {
  291.                 case EOL:
  292.                   putc (' ', output);
  293.                 case 1:
  294.                   break;
  295.                 case '\\':
  296.                   putc ('\\', output);
  297.                 default:
  298.                   putc (*follow, output);
  299.                 }
  300.               follow++;
  301.             }
  302.               putc (1, output);
  303.             }
  304.           fprintf (output, "\n./* %dp %d %dp\n",
  305.                (int) (parser_state_tos->com_col * 7),
  306.                (int) ((s_code != e_code || s_lab != e_lab)
  307.                   - parser_state_tos->box_com),
  308.                (int) (target_col * 7));
  309.         }
  310.           comment_open = 1 + parser_state_tos->box_com;
  311.           while (*p)
  312.         {
  313.           if (*p == BACKSLASH)
  314.             putc (BACKSLASH, output);
  315.           putc (*p++, output);
  316.         }
  317.         }
  318.       else
  319.         {
  320.           /* Here for comment printing */
  321.           register target = parser_state_tos->com_col;
  322.           register char *com_st = s_com;
  323.  
  324. #ifdef NEW_COMMENTS
  325.     /* Here is the beginning of the new code.  Simpler, isn't it? */
  326.           if (cur_col > target)
  327.         {
  328.           putc (EOL, output);
  329.           cur_col = 1;
  330.           ++out_lines;
  331.         }
  332.  
  333.           cur_col = pad_output (cur_col, target);
  334.           fwrite (com_st, e_com - com_st, 1, output);
  335.           cur_col += e_com - com_st;
  336.           com_lines++;
  337.  
  338. #else
  339.           target += parser_state_tos->comment_delta;
  340.           while (*com_st == TAB)
  341.         com_st++, target += tabsize;
  342.  
  343.           while (target <= 0)
  344.         if (*com_st == ' ')
  345.           target++, com_st++;
  346.         else if (*com_st == TAB)
  347.           {
  348.             target = ((target - 1) & ~(tabsize - 1)) + (tabsize + 1);
  349.             com_st++;
  350.           }
  351.         else
  352.           target = 1;
  353.  
  354.           if (cur_col > target)
  355.         {        /* if comment cant fit on this line, put it
  356.                    on next line */
  357.           putc (EOL, output);
  358.           cur_col = 1;
  359.           ++out_lines;
  360.         }
  361.  
  362.           while (e_com > com_st && isspace (e_com[-1]))
  363.         e_com--;
  364.  
  365.           cur_col = pad_output (cur_col, target);
  366.           if (!parser_state_tos->box_com)
  367.         {
  368.           if (star_comment_cont
  369.               && (com_st[1] != '*' || e_com <= com_st + 1))
  370.             if (com_st[1] == ' '
  371.             && com_st[0] == ' ' && e_com > com_st + 1)
  372.               com_st[1] = '*';
  373.             else
  374.               fwrite (" * ", (com_st[0] == TAB
  375.                       ? 2 : (com_st[0] == '*' ? 1 : 3)),
  376.                   1, output);
  377.         }
  378.           fwrite (com_st, e_com - com_st, 1, output);
  379.           parser_state_tos->comment_delta
  380.         = parser_state_tos->n_comment_delta;
  381.           cur_col = count_spaces (cur_col, com_st);
  382.           ++com_lines;    /* count lines with comments */
  383. #endif
  384.         }
  385.     }
  386.       else if (embedded_comment_on_line)
  387.     com_lines++;
  388.       embedded_comment_on_line = 0;
  389.  
  390.       if (parser_state_tos->use_ff)
  391.     {
  392.       putc ('\014', output);
  393.       parser_state_tos->use_ff = false;
  394.     }
  395.       else
  396.     putc (EOL, output);
  397.  
  398.     inhibit_newline:
  399.       ++out_lines;
  400.       if (parser_state_tos->just_saw_decl == 1
  401.       && blanklines_after_declarations)
  402.     {
  403.       prefix_blankline_requested = 1;
  404.       parser_state_tos->just_saw_decl = 0;
  405.     }
  406.       else
  407.     prefix_blankline_requested = postfix_blankline_requested;
  408.       postfix_blankline_requested = 0;
  409.     }
  410.  
  411.   /* if we are in the middle of a declaration, remember that fact
  412.      for proper comment indentation */
  413.   parser_state_tos->decl_on_line = parser_state_tos->in_decl;
  414.  
  415.   /* next line should be indented if we have not completed this
  416.      stmt and if we are not in the middle of a declaration */
  417.   parser_state_tos->ind_stmt = (parser_state_tos->in_stmt
  418.                 & ~parser_state_tos->in_decl);
  419.  
  420.   parser_state_tos->dumped_decl_indent = 0;
  421.   *(e_lab  = s_lab) = '\0';    /* reset buffers */
  422.   *(e_code = s_code) = '\0';
  423.   *(e_com  = s_com) = '\0';
  424.   parser_state_tos->ind_level = parser_state_tos->i_l_follow;
  425.   parser_state_tos->paren_level = parser_state_tos->p_l_follow;
  426.   if (parser_state_tos->paren_level > 0)
  427.     paren_target
  428.       = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
  429.   else
  430.     paren_target = 0;
  431.   not_first_line = 1;
  432.  
  433.   return;
  434. }
  435.  
  436. /* Figure out where we should put the code in codebuf. Return the column
  437.    number in spaces.  */
  438.  
  439. INLINE int
  440. compute_code_target ()
  441. {
  442.   register target_col = parser_state_tos->ind_level + 1;
  443.  
  444.   if (parser_state_tos->paren_level)
  445.     if (!lineup_to_parens)
  446.       target_col += continuation_indent * parser_state_tos->paren_level;
  447.     else
  448.       {
  449.     register w;
  450.     register t = paren_target;
  451.  
  452.     if ((w = count_spaces (t, s_code) - max_col) > 0
  453.         && count_spaces (target_col, s_code) <= max_col)
  454.       {
  455.         t -= w + 1;
  456.         if (t > target_col)
  457.           target_col = t;
  458.       }
  459.     else
  460.       target_col = t;
  461.       }
  462.   else if (parser_state_tos->ind_stmt)
  463.     target_col += continuation_indent;
  464.   return target_col;
  465. }
  466.  
  467. INLINE int
  468. compute_label_target ()
  469. {
  470.   return
  471.   parser_state_tos->pcase ? case_ind + 1
  472.   : *s_lab == '#' ? 1
  473.   : parser_state_tos->ind_level - LABEL_OFFSET + 1;
  474. }
  475.  
  476. /* Read file FILENAME into a `fileptr' structure, and return a pointer to
  477.    that structure. */
  478.  
  479. static struct file_buffer fileptr;
  480.  
  481. struct file_buffer *
  482. read_file (filename)
  483.      char *filename;
  484. {
  485.   int fd;
  486. #ifndef AMIGA
  487.   struct stat file_stats;
  488. #endif /* !AMIGA */
  489.   int namelen = strlen (filename);
  490. #ifdef AMIGA
  491.   BPTR in_fh;
  492.   struct FileInfoBlock __aligned in_fib;
  493. #endif
  494.  
  495. #ifdef AMIGA
  496.   in_fh = Lock (filename, SHARED_LOCK);
  497.   if (in_fh == 0)
  498.     sys_error (filename);
  499.  
  500.   if (Examine (in_fh, &in_fib) == 0)
  501.     sys_error (filename);
  502.  
  503.   if (fileptr.data != 0)
  504.     free (fileptr.data);
  505.   fileptr.size = in_fib.fib_Size;
  506.   fileptr.data = (char *) xmalloc (fileptr.size + 3);
  507.  
  508.   UnLock (in_fh);
  509.  
  510.   fd = open (filename, O_RDONLY, 0777);
  511.   if (fd < 0)
  512.     sys_error (filename);
  513. #else /* !AMIGA */
  514.   fd = open (filename, O_RDONLY, 0777);
  515.   if (fd < 0)
  516.     sys_error (filename);
  517.  
  518.   if (fstat (fd, &file_stats) < 0)
  519.     sys_error (filename);
  520.  
  521.   if (fileptr.data != 0)
  522.     free (fileptr.data);
  523.   fileptr.size = file_stats.st_size;
  524.   fileptr.data = (char *) xmalloc (file_stats.st_size + 1);
  525. #endif /* !AMIGA */
  526.  
  527.   if (read (fd, fileptr.data, fileptr.size) < 0)
  528.     sys_error (filename);
  529.  
  530.   if (close (fd) < 0)
  531.     sys_error (filename);
  532.  
  533.   fileptr.name = (char *) xmalloc (namelen + 1);
  534.   memcpy (fileptr.name, filename, namelen);
  535.   fileptr.name[namelen] = '\0';
  536.  
  537.   fileptr.data[fileptr.size] = '\0';
  538.  
  539.   return &fileptr;
  540. }
  541.  
  542. /* This should come from stdio.h and be some system-optimal number */
  543. #ifndef BUFSIZ
  544. #define BUFSIZ 1024
  545. #endif
  546.  
  547. /* Suck the standard input into a file_buffer structure, and
  548.    return a pointer to that structure. */
  549.  
  550. struct file_buffer stdinptr;
  551.  
  552. struct file_buffer *
  553. read_stdin ()
  554. {
  555.   unsigned int size = 15 * BUFSIZ;
  556.   int ch;
  557.   register char *p;
  558. #ifdef AMIGA
  559.   char *in_prog;
  560.   int in_prog_size;
  561. #endif /* AMIGA */
  562.  
  563.   if (stdinptr.data != 0)
  564.     free (stdinptr.data);
  565.  
  566. /* The following code had to be changed, because you can't assume, that
  567.    xrealloc() always returns the original pointer. By the way: the original
  568.    code violates the GNU coding standards!!! */
  569.  
  570. #ifdef AMIGA
  571.   in_prog = (char *) xmalloc (size + 1);
  572.   in_prog_size = 0;
  573.   do
  574.     {
  575.       for (; in_prog_size < size; in_prog_size++)
  576.     {
  577.       ch = getc (stdin);
  578.       if (ch == EOF)
  579.         break;
  580.       in_prog[in_prog_size] = ch;
  581.     }
  582.  
  583.       if (ch != EOF)
  584.     {
  585.       size += (2 * BUFSIZ);
  586.       in_prog = xrealloc (in_prog, size);
  587.     }
  588.     }
  589.   while (ch != EOF);
  590.  
  591.   stdinptr.data = in_prog;
  592.   stdinptr.size = in_prog_size;
  593.   stdinptr.name = "Standard Input";
  594.  
  595.   stdinptr.data[stdinptr.size] = '\0';
  596. #else /* !AMIGA */
  597.   stdinptr.data = (char *) xmalloc (size + 1);
  598.   stdinptr.size = 0;
  599.   p = stdinptr.data;
  600.   do
  601.     {
  602.       while (stdinptr.size < size)
  603.     {
  604.       ch = getc (stdin);
  605.       if (ch == EOF)
  606.         break;
  607.  
  608.       *p++ = ch;
  609.       stdinptr.size++;
  610.     }
  611.  
  612.       if (ch != EOF)
  613.     {
  614.       size += (2 * BUFSIZ);
  615.       stdinptr.data = xrealloc (stdinptr.data, size);
  616.       p = stdinptr.data + stdinptr.size;
  617.     }
  618.     }
  619.   while (ch != EOF);
  620.  
  621.   stdinptr.name = "Standard Input";
  622.  
  623.   stdinptr.data[stdinptr.size] = '\0';
  624. #endif /* !AMIGA */
  625.  
  626.   return &stdinptr;
  627. }
  628.  
  629. /* Advance buf_ptr so that it points to the next line of input.  Skip over
  630.    indent errors (comments beginning with *INDENT**), ignoring them.  Process
  631.    INDENT ON and INDENT OFF. (Note: the name of this function is a historical
  632.    artifact from before the time that indent kept the whole source file in
  633.    memory). */
  634.  
  635. INLINE void
  636. fill_buffer ()
  637. {
  638.   register char *p, *q;
  639.   register char c;
  640.   register int column;
  641.  
  642.   enum
  643.     {
  644.       None, Indent_on, Indent_off
  645.     } com;
  646.  
  647.   /* indent() may be saving the text between "if (...)" and the following
  648.      statement.  To do so, it uses another buffer (`save_com').  Switch
  649.      back to the previous buffer here. */
  650.   if (bp_save != 0)
  651.     {
  652.       buf_ptr = bp_save;
  653.       buf_end = be_save;
  654.       bp_save = be_save = 0;
  655.  
  656.       /* only return if there is really something in this buffer */
  657.       if (buf_ptr < buf_end)
  658.     return;
  659.     }
  660.  
  661. fill_it:
  662.  
  663.   cur_line = in_prog_pos;
  664.   buf_ptr = in_prog_pos;
  665.   if (*buf_ptr == '\0')
  666.     {
  667.       had_eof = true;
  668.       return;
  669.     }
  670.  
  671.   /* Find the end of line (or null character) */
  672.   p = buf_ptr;
  673.   do
  674.     {
  675.       c = *p;
  676.       p++;
  677.     }
  678.   while (c != '\0' && c != EOL);
  679.   buf_end = p;
  680.   in_prog_pos = buf_end;
  681.  
  682. #if 0
  683.   p = buf_ptr;
  684.   while (*p == ' ' || *p == TAB)
  685.     p++;
  686.  
  687.   /* Look for *INDENT** or INDENT ON or INDENT OFF embedded in comments. */
  688.   if (*p == '/' && p[1] == '*')
  689.     {
  690.       p += 2;
  691.       if (p[1] == 'I' && strncmp (p, "*INDENT**", 9) == 0)
  692.     goto fill_it;
  693.  
  694.       while (*p == ' ' || *p == TAB)
  695.     p++;
  696.       com = None;
  697.       if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
  698.       && p[4] == 'N' && p[5] == 'T')
  699.     /* Found INDENT.  Now look for ON or OFF. */
  700.     {
  701.       p += 6;
  702.       while (*p == ' ' || *p == TAB)
  703.         p++;
  704.       if (*p == '*')
  705.         com = Indent_on;
  706.       else if (*p == 'O')
  707.         if (*++p == 'N')
  708.           p++, com = Indent_on;
  709.         else if (*p == 'F' && *++p == 'F')
  710.           p++, com = Indent_off;
  711.       while (*p == ' ' || *p == TAB)
  712.         p++;
  713.       if (p[0] == '*' && p[1] == '/' && p[2] == EOL && com)
  714.         {
  715.           if (s_com != e_com || s_lab != e_lab || s_code != e_code)
  716.         dump_line ();
  717.           if (!(inhibit_formatting = (int) com - 1))
  718.         {
  719.           n_real_blanklines = 0;
  720.           postfix_blankline_requested = 0;
  721.           prefix_blankline_requested = 0;
  722.           suppress_blanklines = 1;
  723.         }
  724.         }
  725.     }
  726.     }
  727.  
  728.   if (inhibit_formatting)
  729.     {
  730.       p = buf_ptr;
  731.       do
  732.     putc (*p, output);
  733.       while (*p++ != EOL);
  734.     }
  735. #endif
  736. }
  737.  
  738.  
  739. INLINE int
  740. current_column ()
  741. {
  742.   char *p;
  743.   int column = 1;
  744.  
  745.   if (buf_ptr >= save_com.ptr && buf_ptr <= save_com.end)
  746.     p = save_com.ptr;
  747.   else
  748.     p = cur_line;
  749.  
  750. #if 0
  751.   /* Paranoia */
  752.   if (! (buf_ptr >= cur_line && buf_ptr < in_prog_pos))
  753.     abort ();
  754. #endif
  755.  
  756.   column = 1;
  757.   while (p < buf_ptr)
  758.     switch (*p++)
  759.       {
  760.       case TAB:
  761.     column += tabsize - (column % tabsize) + 1;
  762.     break;
  763.       case '\b':
  764.     column--;
  765.     break;
  766.       default:
  767.     column++;
  768.       }
  769.  
  770.   return column;
  771. }
  772.  
  773. /* Fill the output line with whitespace up to TARGET_COLUMN, given that
  774.    the line is currently in column CURRENT_COLUMN.  Returns the ending
  775.    column. */
  776.  
  777. INLINE int
  778. pad_output (current_column, target_column)
  779.   register int current_column;
  780.   register int target_column;
  781. {
  782.   if (troff)
  783.     {
  784.       fprintf (output, "\\h'|%dp'", (int) ((target_column - 1) * 7));
  785.       return 0;
  786.     }
  787.  
  788.   if (current_column >= target_column)
  789.     return current_column;
  790.  
  791.   if (tabsize > 1)
  792.     {
  793.       register int offset;
  794.  
  795.       offset = tabsize - (current_column - 1) % tabsize;
  796.       while (current_column + offset <= target_column)
  797.     {
  798.       putc (TAB, output);
  799.       current_column += offset;
  800.       offset = tabsize;
  801.     }
  802.     }
  803.  
  804.   while (current_column < target_column)
  805.     {
  806.       putc (' ', output);
  807.       current_column++;
  808.     }
  809.  
  810.   return current_column;
  811. }
  812.  
  813. /* Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  814.  
  815. All rights reserved
  816.  
  817.  
  818. NAME: count_spaces
  819.  
  820. FUNCTION: Find out where printing of a given string will leave the current
  821.    character position on output.
  822.  
  823. ALGORITHM: Run thru input string and add appropriate values to current
  824.    position.
  825.  
  826. RETURNS: Integer value of position after printing "buffer" starting in column
  827.    "current".
  828.  
  829. HISTORY: initial coding     November 1976    D A Willcox of CAC */
  830.  
  831. INLINE int
  832. count_spaces (current, buffer)
  833.      /* this routine figures out where the character position will be after
  834.         printing the text in buffer starting at column "current" */
  835.      int current;
  836.      char *buffer;
  837. {
  838.   register char *buf;        /* used to look thru buffer */
  839.   register int cur;        /* current character counter */
  840.  
  841.   cur = current;
  842.  
  843.   for (buf = buffer; *buf != '\0'; ++buf)
  844.     {
  845.       switch (*buf)
  846.     {
  847.  
  848.     case EOL:
  849.     case 014:        /* form feed */
  850.       cur = 1;
  851.       break;
  852.  
  853.     case TAB:
  854.       cur = cur + tabsize - (cur - 1) % tabsize;
  855.       break;
  856.  
  857.     case 010:        /* backspace */
  858.       --cur;
  859.       break;
  860.  
  861.     default:
  862.       ++cur;
  863.       break;
  864.     }            /* end of switch */
  865.     }                /* end of for loop */
  866.   return (cur);
  867. }
  868.  
  869. /* Nonzero if we have found an error (not a warning).  */
  870. int found_err;
  871.  
  872. /* Signal an error.  LEVEL is nonzero if it is an error (as opposed to a
  873.    warning.  MSG is a printf-style format string.  Additional arguments are
  874.    additional arguments for printf.  */
  875. /* VARARGS2 */
  876. diag (level, msg, a, b)
  877.      int level;
  878.      unsigned int a, b;
  879.      char *msg;
  880. {
  881.   if (level)
  882.     found_err = 1;
  883.  
  884.   fprintf (stderr, "indent:%s:%d: %s: ", in_name, (int) line_no,
  885.        level == 0 ? "Warning" : "Error");
  886.  
  887.   if (msg)
  888.     fprintf (stderr, msg, a, b);
  889.  
  890.   fprintf (stderr, "\n");
  891. }
  892.  
  893. writefdef (f, nm)
  894.      register struct fstate *f;
  895.      unsigned int nm;
  896. {
  897.   fprintf (output, ".ds f%c %s\n.nr s%c %d\n",
  898.        (int) nm, f->font, nm, (int) f->size);
  899. }
  900.  
  901. /* Write characters starting at S to change the font from OF to NF.  Return a
  902.    pointer to the character after the last character written. For troff mode
  903.    only.  */
  904. char *
  905. chfont (of, nf, s)
  906.      register struct fstate *of, *nf;
  907.      char *s;
  908. {
  909.   if (of->font[0] != nf->font[0]
  910.       || of->font[1] != nf->font[1])
  911.     {
  912.       *s++ = '\\';
  913.       *s++ = 'f';
  914.       if (nf->font[1])
  915.     {
  916.       *s++ = '(';
  917.       *s++ = nf->font[0];
  918.       *s++ = nf->font[1];
  919.     }
  920.       else
  921.     *s++ = nf->font[0];
  922.     }
  923.   if (nf->size != of->size)
  924.     {
  925.       *s++ = '\\';
  926.       *s++ = 's';
  927.       if (nf->size < of->size)
  928.     {
  929.       *s++ = '-';
  930.       *s++ = '0' + of->size - nf->size;
  931.     }
  932.       else
  933.     {
  934.       *s++ = '+';
  935.       *s++ = '0' + nf->size - of->size;
  936.     }
  937.     }
  938.   return s;
  939. }
  940.  
  941. void
  942. parsefont (f, s0)
  943.      register struct fstate *f;
  944.      char *s0;
  945. {
  946.   register char *s = s0;
  947.   int sizedelta = 0;
  948.   int i;
  949.  
  950.   f->size = 0;
  951.   f->allcaps = 1;
  952.   for (i = 0; i < 4; i++)
  953.     f->font[i] = 0;
  954.  
  955.   while (*s)
  956.     {
  957.       if (isdigit (*s))
  958.     f->size = f->size * 10 + *s - '0';
  959.       else if (isupper (*s))
  960.     if (f->font[0])
  961.       f->font[1] = *s;
  962.     else
  963.       f->font[0] = *s;
  964.       else if (*s == 'c')
  965.     f->allcaps = 1;
  966.       else if (*s == '+')
  967.     sizedelta++;
  968.       else if (*s == '-')
  969.     sizedelta--;
  970.       else
  971.     {
  972.       fprintf (stderr, "indent: bad font specification: %s\n", s0);
  973.       exit (1);
  974.     }
  975.       s++;
  976.     }
  977.   if (f->font[0] == 0)
  978.     f->font[0] = 'R';
  979.   if (bodyf.size == 0)
  980.     bodyf.size = 11;
  981.   if (f->size == 0)
  982.     f->size = bodyf.size + sizedelta;
  983.   else if (sizedelta > 0)
  984.     f->size += bodyf.size;
  985.   else
  986.     f->size = bodyf.size - f->size;
  987. }
  988.  
  989. #ifdef DEBUG
  990. void
  991. dump_debug_line ()
  992. {
  993.   fprintf (output, "\n*** Debug output marker line ***\n");
  994. }
  995.  
  996. #endif
  997.