home *** CD-ROM | disk | FTP | other *** search
/ ARM Club 1 / ARM_CLUB_CD.iso / contents / apps / program / d / indent / !Indent / c / io < prev    next >
Encoding:
Text File  |  1991-03-17  |  19.8 KB  |  771 lines

  1. /*
  2.  * Copyright (c) 1985 Sun Microsystems, Inc.
  3.  * Copyright (c) 1980 The Regents of the University of California.
  4.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  5.  * All rights reserved.
  6.  *
  7.  * Redistribution and use in source and binary forms are permitted
  8.  * provided that the above copyright notice and this paragraph are
  9.  * duplicated in all such forms and that any documentation,
  10.  * advertising materials, and other materials related to such
  11.  * distribution and use acknowledge that the software was developed
  12.  * by the University of California, Berkeley, the University of Illinois,
  13.  * Urbana, and Sun Microsystems, Inc.  The name of either University
  14.  * or Sun Microsystems may not be used to endorse or promote products
  15.  * derived from this software without specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  17.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  18.  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. static char sccsid[] = "@(#)io.c    5.10 (Berkeley) 9/15/88";
  23. #endif /* not lint */
  24.  
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <errno.h>
  28. #include <ctype.h>
  29.  
  30. #include "externs.h"
  31. #include "io.h"
  32. #include "indent.h" /* for clean_up_heap() */
  33.  
  34. #ifdef __arm /* Little Archimedes tweak to stop off_t being redefined wrongly */
  35. #include <sys/file.h>
  36. #endif
  37.  
  38. /* POSIX says that fcntl.h should exist.  Linking either sys/fcntl.h
  39.    or sys/file.h to fcntl.h should work fine if you don't have fcntl.h */
  40.  
  41.   /* (but for portability you'd be better off sticking to the ANSI C standard
  42.       rather than posix - a simple text filter like this really shouldn't
  43.       have to know about low-level operating system calls :-( */
  44.  
  45. #include <fcntl.h>
  46.  
  47. #include <sys/types.h>
  48.  
  49. #include <sys/stat.h>
  50.  
  51. int suppress_blanklines = 0;
  52. int         comment_open;
  53.  
  54. int paren_target;
  55.  
  56. /* true if INDENT OFF is in effect */
  57. static int inhibit_formatting;
  58.  
  59. void dump_line(void)
  60. {                /* dump_line is the routine that actually
  61.                  * effects the printing of the new source. It
  62.                  * prints the label section, followed by the
  63.                  * code section with the appropriate nesting
  64.                  * level, followed by any comments */
  65.     register int cur_col,
  66.                 target_col;
  67.     static      not_first_line;
  68.  
  69.     if (parser_state_tos->procname[0]) {
  70.     if (troff) {
  71.         if (comment_open) {
  72.         comment_open = 0;
  73.         fprintf(output, ".*/\n");
  74.         }
  75.         fprintf(output, ".Pr \"%.*s\"\n", parser_state_tos->procname_end - parser_state_tos->procname,
  76.             parser_state_tos->procname);
  77.     }
  78.     parser_state_tos->ind_level = 0;
  79.     parser_state_tos->procname = "\0";
  80.     }
  81.     if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
  82.       /* If we have a formfeed on a blank line, we should just output it,
  83.      rather than treat it as a normal blank line.  */
  84.       if (parser_state_tos->use_ff)
  85.     {
  86.       putc('\014',output);
  87.       parser_state_tos->use_ff = false;
  88.     }
  89.       else
  90.     {
  91.       if (suppress_blanklines > 0)
  92.         suppress_blanklines--;
  93.       else {
  94.         parser_state_tos->bl_line = true;
  95.         n_real_blanklines++;
  96.       }
  97.     }
  98.     }
  99.     else if (!inhibit_formatting) {
  100.     suppress_blanklines = 0;
  101.     parser_state_tos->bl_line = false;
  102.     if (prefix_blankline_requested && not_first_line) {
  103.         if (swallow_optional_blanklines) {
  104.         if (n_real_blanklines == 1)
  105.             n_real_blanklines = 0;
  106.         } else { /* another ambiguous dangling else... */
  107.         if (n_real_blanklines == 0)
  108.             n_real_blanklines = 1;
  109.         }
  110.     }
  111.     while (--n_real_blanklines >= 0)
  112.         putc('\n', output);
  113.     n_real_blanklines = 0;
  114.     if (parser_state_tos->ind_level == 0)
  115.         parser_state_tos->ind_stmt = 0;    /* this is a class A kludge. dont do
  116.                  * additional statement indentation if we are
  117.                  * at bracket level 0 */
  118.  
  119.     if (e_lab != s_lab || e_code != s_code)
  120.         ++code_lines;    /* keep count of lines with code */
  121.  
  122.  
  123.     if (e_lab != s_lab) {    /* print lab, if any */
  124.         if (comment_open) {
  125.         comment_open = 0;
  126.         fprintf(output, ".*/\n");
  127.         }
  128.         while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
  129.         e_lab--;
  130.         cur_col = pad_output(1, compute_label_target());
  131.         if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
  132.                     || strncmp(s_lab, "#endif", 6) == 0)) {
  133.             /* Treat #else and #endif as a special case because any
  134.            text after #else or #endif should be converted to
  135.            a comment.  */
  136.         register char *s = s_lab;
  137.         if (e_lab[-1] == '\n') e_lab--;
  138.         do putc(*s++, output);
  139.         while (s < e_lab && 'a' <= *s && *s<='z');
  140.         while ((*s == ' ' || *s == '\t') && s < e_lab)
  141.             s++;
  142.         if (s < e_lab) {
  143. #ifdef NO_TABS /* Don't output hard tabs */
  144.             {                         /* Just one tab, to next tab stop. */
  145.               int target = (cur_col + tabsize) - (cur_col % tabsize);
  146.               do {
  147.                 putc(' ', output); cur_col += 1;
  148.               } while (cur_col < target);
  149.             }
  150.             fprintf(output, s[0]=='/' && s[1]=='*'
  151.               ? "%.*s"
  152.               : "/* %.*s */",
  153.                 e_lab - s, s);
  154. #else /* Not NO_TABS (ie tabs) */
  155.             fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
  156.                 e_lab - s, s);
  157. #endif /* Not NO_TABS */
  158.         }
  159.         }
  160.         else fprintf(output, "%.*s", e_lab - s_lab, s_lab);
  161.         cur_col = count_spaces(cur_col, s_lab);
  162.     }
  163.     else
  164.         cur_col = 1;    /* there is no label section */
  165.  
  166.     parser_state_tos->pcase = false;
  167.  
  168.     if (s_code != e_code) {    /* print code section, if any */
  169.         register char *p;
  170.  
  171.         if (comment_open) {
  172.         comment_open = 0;
  173.         fprintf(output, ".*/\n");
  174.         }
  175.         target_col = compute_code_target();
  176.         /* If a line ends in an lparen character, the following 
  177.            line should not line up with the parenthesis, but
  178.            should be indented by the usual amount.  */
  179.         if (parser_state_tos->last_token == lparen)
  180.           {
  181.         parser_state_tos->paren_indents[parser_state_tos->p_l_follow-1]
  182.           += ind_size - 1;
  183.           }
  184.         {
  185.         register int i;
  186.  
  187.         for (i = 0; i < parser_state_tos->p_l_follow; i++)
  188.             if (parser_state_tos->paren_indents[i] >= 0)
  189.             parser_state_tos->paren_indents[i] = -(parser_state_tos->paren_indents[i] + target_col);
  190.         }
  191.         cur_col = pad_output(cur_col, target_col);
  192.         for (p = s_code; p < e_code; p++)
  193.         if (*p == (char) 0200)                      /* Not 8-bit clean? */
  194.             fprintf(output, "%d", target_col * 7);  /* What is this for? */
  195.         else
  196.             putc(*p, output);
  197.         cur_col = count_spaces(cur_col, s_code);
  198.     }
  199.     if (s_com != e_com)
  200.       {
  201.         if (troff) {
  202.         int         all_here = 0;
  203.         register char *p;
  204.  
  205.         if (e_com[-1] == '/' && e_com[-2] == '*')
  206.             e_com -= 2, all_here++;
  207.         while (e_com > s_com && e_com[-1] == ' ')
  208.             e_com--;
  209.         *e_com = 0;
  210.         p = s_com;
  211.         while (*p == ' ')
  212.             p++;
  213.         if (p[0] == '/' && p[1] == '*')
  214.             p += 2, all_here++;
  215.         else if (p[0] == '*')
  216.             p += p[1] == '/' ? 2 : 1;
  217.         while (*p == ' ')
  218.             p++;
  219.         if (*p == 0)
  220.             goto inhibit_newline;
  221.         if (comment_open < 2 && parser_state_tos->box_com) {
  222.             comment_open = 0;
  223.             fprintf(output, ".*/\n");
  224.         }
  225.         if (comment_open == 0) {
  226.             if ('a' <= *p && *p <= 'z')
  227.             *p = *p + 'A' - 'a';
  228.             if (e_com - p < 50 && all_here == 2) {
  229.             register char *follow = p;
  230.             fprintf(output, "\n.nr C! \\w\1");
  231.             while (follow < e_com) {
  232.                 switch (*follow) {
  233.                 case '\n':
  234.                 putc(' ', output);
  235.                 case 1:
  236.                 break;
  237.                 case '\\':
  238.                 putc('\\', output);
  239.                 default:
  240.                 putc(*follow, output);
  241.                 }
  242.                 follow++;
  243.             }
  244.             putc(1, output);
  245.             }
  246.             fprintf(output, "\n./* %dp %d %dp\n",
  247.                 parser_state_tos->com_col * 7,
  248.                 (s_code != e_code || s_lab != e_lab) - parser_state_tos->box_com,
  249.                 target_col * 7);
  250.         }
  251.         comment_open = 1 + parser_state_tos->box_com;
  252.         while (*p) {
  253.             if (*p == BACKSLASH)
  254.             putc(BACKSLASH, output);
  255.             putc(*p++, output);
  256.         }
  257.         }
  258.         else {        /* print comment, if any */
  259.         register int target = parser_state_tos->com_col;
  260.         register char *com_st = s_com;
  261.  
  262.         target += parser_state_tos->comment_delta;
  263.         while (*com_st == '\t')
  264.             com_st++, target += 8;    /* ? */
  265.         while (target <= 0)
  266.             if (*com_st == ' ')
  267.             target++, com_st++;
  268.             else if (*com_st == '\t')
  269.             target = ((target - 1) & ~7) + 9, com_st++;
  270.             else
  271.             target = 1;
  272.         if (cur_col > target) {    /* if comment cant fit on this line,
  273.                      * put it on next line */
  274.             putc('\n', output);
  275.             cur_col = 1;
  276.             ++parser_state_tos->out_lines;
  277.         }
  278.         while (e_com > com_st && isspace(e_com[-1]))
  279.             e_com--;
  280.         cur_col = pad_output(cur_col, target);
  281.         if (!parser_state_tos->box_com) {
  282.             if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) {
  283.             if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1) {
  284.                 com_st[1] = '*';
  285.             } else {
  286.                 fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
  287.             } /* Ambiguous else */
  288.             }
  289.         }
  290.         fwrite(com_st, e_com - com_st, 1, output);
  291.         parser_state_tos->comment_delta = parser_state_tos->n_comment_delta;
  292.         cur_col = count_spaces(cur_col, com_st);
  293.         ++parser_state_tos->com_lines;    /* count lines with comments */
  294.         }
  295.       }
  296.     if (parser_state_tos->use_ff)
  297.       {
  298.         putc('\014', output);
  299.         parser_state_tos->use_ff = false;
  300.       }
  301.     else
  302.         putc('\n', output);
  303. inhibit_newline:
  304.     ++parser_state_tos->out_lines;
  305.     if (parser_state_tos->just_saw_decl == 1 && blanklines_after_declarations) {
  306.         prefix_blankline_requested = 1;
  307.         parser_state_tos->just_saw_decl = 0;
  308.     }
  309.     else
  310.         prefix_blankline_requested = postfix_blankline_requested;
  311.     postfix_blankline_requested = 0;
  312.     }
  313.     parser_state_tos->decl_on_line = parser_state_tos->in_decl;    /* if we are in the middle of a
  314.                      * declaration, remember that fact for
  315.                      * proper comment indentation */
  316.     parser_state_tos->ind_stmt = parser_state_tos->in_stmt & ~parser_state_tos->in_decl;    /* next line should be
  317.                          * indented if we have not
  318.                          * completed this stmt and if
  319.                          * we are not in the middle of
  320.                          * a declaration */
  321.     parser_state_tos->dumped_decl_indent = 0;
  322.     *(e_lab = s_lab) = '\0';    /* reset buffers */
  323.     *(e_code = s_code) = '\0';
  324.     *(e_com = s_com) = '\0';
  325.     parser_state_tos->ind_level = parser_state_tos->i_l_follow;
  326.     parser_state_tos->paren_level = parser_state_tos->p_l_follow;
  327.     paren_target = -parser_state_tos->paren_indents[parser_state_tos->paren_level - 1];
  328.     not_first_line = 1;
  329.     return;
  330. }
  331.  
  332. /* Figure out where we should put the code in codebuf.
  333.    Return the column number in spaces.  */
  334. int
  335. compute_code_target(void)
  336. {
  337.     register int target_col = parser_state_tos->ind_level + 1;
  338.  
  339.     if (parser_state_tos->paren_level)
  340.     if (!lineup_to_parens)
  341.         target_col += continuation_indent * parser_state_tos->paren_level;
  342.     else {
  343.         register int w;
  344.         register int t = paren_target;
  345.  
  346.         if ((w = count_spaces(t, s_code) - max_col) > 0
  347.             && count_spaces(target_col, s_code) <= max_col) {
  348.         t -= w + 1;
  349.         if (t > target_col)
  350.             target_col = t;
  351.         }
  352.         else
  353.         target_col = t;
  354.     }
  355.     else if (parser_state_tos->ind_stmt)
  356.     target_col += continuation_indent;
  357.     return target_col;
  358. }
  359.  
  360. int
  361. compute_label_target(void)
  362. {
  363.     return
  364.     parser_state_tos->pcase ? case_ind + 1
  365.     : *s_lab == '#' ? 1
  366.     : parser_state_tos->ind_level - label_offset + 1;
  367. }
  368.  
  369. /* Allocate space for FILENAME, read in the file, and set in_prog and 
  370.    in_prog_pos to point to the buffer.  If any errors occur, report an 
  371.    error message and abort.  */
  372. void
  373. read_file(char *filename)
  374. {
  375.   /* File descriptor for the input file */
  376.   int in_fd;
  377.  
  378.   /* File status for the input file */
  379.   struct stat in_stat;
  380.  
  381.   /* buffer used for error messages */
  382.   extern char *errbuf;
  383.  
  384.   if (errbuf == NULL) errbuf = (char *)xmalloc (strlen (filename) + 80);
  385.   sprintf(errbuf,"indent: %s",filename);
  386.  
  387.   in_fd = open(filename,O_RDONLY,0777);
  388.   if (in_fd < 0)
  389.     {
  390.       perror(errbuf);
  391.       clean_up_heap(); exit(1);
  392.     }
  393.  
  394.   if (fstat(in_fd,&in_stat) < 0)
  395.     {
  396.       perror(errbuf);
  397.       clean_up_heap(); exit(1);
  398.     }
  399.   in_prog_size = in_stat.st_size;
  400.   in_prog = xmalloc(in_prog_size + 3); /* 3 for ' ','\n','\0' */
  401.  
  402.   if (read(in_fd,in_prog,in_prog_size) < 0)
  403.     {
  404.       perror(errbuf);
  405.       clean_up_heap(); exit(1);
  406.     }
  407.  
  408.   if (close(in_fd) < 0)
  409.     {
  410.       perror(errbuf);
  411.       clean_up_heap(); exit(1);
  412.     }
  413.  
  414.   in_prog[in_prog_size] = ' ';
  415.   in_prog[in_prog_size+1] = '\n';
  416.   in_prog[in_prog_size+2] = 0;
  417.   in_prog_pos = in_prog;
  418.  
  419.   xfree (errbuf);
  420. }
  421.  
  422. /* Like read_file but read from stdin.  */
  423. void
  424. read_stdin(void)
  425. {
  426.   unsigned int alloc_size = 10000;
  427.   int ch;
  428.  
  429.   in_prog_pos = in_prog = xmalloc(alloc_size);
  430.   in_prog_size = 0;
  431.   do
  432.     {
  433.       /* Copy up until 3 bytes before the end of the buffer,
  434.      (the 3 is for ' \n\0')...  */
  435.       for (; in_prog_size < alloc_size - 3; in_prog_size++)
  436.     {
  437.       ch = getc(stdin);
  438.       if (ch == EOF)
  439.           break;
  440.       in_prog[in_prog_size] = ch;
  441.     }
  442.       /* ...and if that's not enough allocate more.  */
  443.       if (ch != EOF) {
  444.     alloc_size *= 2;
  445.     in_prog = xrealloc(in_prog,alloc_size);
  446.       }
  447.     }
  448.   while (ch != EOF);
  449.   
  450.   in_prog[in_prog_size] = ' ';
  451.   in_prog[in_prog_size+1] = '\n';
  452.   in_prog[in_prog_size+2] = 0;
  453.   in_prog_pos = in_prog;  
  454. }
  455.  
  456. /* Advance buf_ptr so that it points to the next line of input.  Skip 
  457.    over indent errors (comments beginning with *INDENT**), ignoring
  458.    them.  Process INDENT ON and INDENT OFF. (Note: the name of this
  459.    function is a historical artifact from before the time that indent
  460.    kept the whole source file in memory). */
  461.  
  462. void fill_buffer(void)
  463. {
  464.   /* Point various places in the buffer.  */
  465.   char *p;
  466.  
  467.   /* Have we found INDENT ON or INDENT OFF ? */
  468.   enum {None,Indent_on,Indent_off} com;
  469.   
  470.   if (bp_save != 0)
  471.     {        /* there is a partly filled input buffer left */
  472.     buf_ptr = bp_save;    /* dont read anything, just switch buffers */
  473.     buf_end = be_save;
  474.     bp_save = be_save = 0;
  475.     if (buf_ptr < buf_end)
  476.         return;        /* only return if there is really something in
  477.                  * this buffer */
  478.     }
  479.  
  480.   fill_it:
  481.  
  482.   cur_line = in_prog_pos;
  483.   buf_ptr = in_prog_pos;
  484.   for (p = buf_ptr; *p && *p++ != '\n';)
  485.     ;
  486.   
  487.   buf_end = p;
  488.   if (!*p)
  489.     had_eof = true;
  490.  
  491.   p = buf_ptr;
  492.   in_prog_pos = buf_end;
  493.   
  494.   while (*p == ' ' || *p == '\t')
  495.     p++;
  496.   if (*p == '/' && p[1] == '*')
  497.     {
  498.       p += 2;
  499.       if (p[1] == 'I' && strncmp(p,"*INDENT**",9) == 0)
  500.     goto fill_it;
  501.       while (*p == ' ' || *p == '\t')
  502.     p++;
  503.       com = None;
  504.       if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
  505.             && p[4] == 'N' && p[5] == 'T') {
  506.             p += 6;
  507.             while (*p == ' ' || *p == '\t')
  508.             p++;
  509.             if (*p == '*')
  510.             com = Indent_on;
  511.             else if (*p == 'O') {
  512.             if (*++p == 'N') { /* More dangling else's */
  513.                 p++, com = Indent_on;
  514.             } else if (*p == 'F' && *++p == 'F')
  515.                 p++, com = Indent_off;
  516.             }
  517.             while (*p == ' ' || *p == '\t')
  518.             p++;
  519.             if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
  520.             if (s_com != e_com || s_lab != e_lab || s_code != e_code)
  521.                 dump_line();
  522.             if ((inhibit_formatting = (int)com - 1) == 0) {
  523.                 n_real_blanklines = 0;
  524.                 postfix_blankline_requested = 0;
  525.                 prefix_blankline_requested = 0;
  526.                 suppress_blanklines = 1;
  527.             }
  528.             }
  529.           }
  530.     }
  531.   if (inhibit_formatting)
  532.     {
  533.       p = buf_ptr;
  534.       do
  535.     putc(*p,output);
  536.       while (*p++ != '\n');
  537.     }
  538.       
  539. }
  540.   
  541.       
  542.   
  543. /*
  544.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  545.  * 
  546.  * All rights reserved
  547.  * 
  548.  * 
  549.  * NAME: pad_output
  550.  * 
  551.  * FUNCTION: Writes tabs and spaces to move the current column up to the desired
  552.  * position.
  553.  * 
  554.  * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
  555.  * 
  556.  * PARAMETERS: current        integer        The current column target
  557.  * nteger        The desired column
  558.  * 
  559.  * RETURNS: Integer value of the new column.  (If current >= target, no action is
  560.  * taken, and current is returned.
  561.  * 
  562.  * GLOBALS: None
  563.  * 
  564.  * CALLS: write (sys)
  565.  * 
  566.  * CALLED BY: dump_line
  567.  * 
  568.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  569.  * 
  570.  */
  571. int pad_output(int current, int target)
  572. /* position we want it at */
  573. {
  574.     register int curr;        /* internal column pointer */
  575.     register int tcur;
  576.  
  577.     if (troff)
  578.     fprintf(output, "\\h'|%dp'", (target - 1) * 7);
  579.     else {
  580.     if (current >= target)
  581.         return (current);    /* line is already long enough */
  582.     curr = current;
  583. #ifdef NO_TABS
  584.     while ((tcur = curr + 1) <= target) {   /* Possibly none */
  585.         putc(' ', output);
  586.         curr = tcur;
  587.     }
  588. #else /* Not NO_TABS */
  589.     while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
  590.         putc('\t', output);
  591.         curr = tcur;
  592.     }
  593. #endif /* Not NO_TABS */
  594.     while (curr++ < target)
  595.         putc(' ', output);    /* pad with final blanks */
  596.     }
  597.     return (target);
  598. }
  599.  
  600. /*
  601.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
  602.  * 
  603.  * All rights reserved
  604.  * 
  605.  * 
  606.  * NAME: count_spaces
  607.  * 
  608.  * FUNCTION: Find out where printing of a given string will leave the current
  609.  * character position on output.
  610.  * 
  611.  * ALGORITHM: Run thru input string and add appropriate values to current
  612.  * position.
  613.  * 
  614.  * RETURNS: Integer value of position after printing "buffer" starting in column
  615.  * "current".
  616.  * 
  617.  * HISTORY: initial coding     November 1976    D A Willcox of CAC
  618.  * 
  619.  */
  620. int
  621. count_spaces(int current, char *buffer)
  622. {
  623.     register char *buf;        /* used to look thru buffer */
  624.     register int cur;        /* current character counter */
  625.  
  626.     cur = current;
  627.  
  628.     for (buf = buffer; *buf != '\0'; ++buf) {
  629.     switch (*buf) {
  630.  
  631.     case '\n':
  632.     case 014:        /* form feed */
  633.         cur = 1;
  634.         break;
  635.  
  636.     case '\t':
  637.         cur = ((cur - 1) & tabmask) + tabsize + 1;
  638.         break;
  639.  
  640.     case 010:        /* backspace */
  641.         --cur;
  642.         break;
  643.  
  644.     default:
  645.         ++cur;
  646.         break;
  647.     }            /* end of switch */
  648.     }                /* end of for loop */
  649.     return (cur);
  650. }
  651.  
  652. /* Nonzero if we have found an error (not a warning).  */
  653. int    found_err;
  654.  
  655. /* Signal an error.  LEVEL is nonzero if it is an error (as opposed to 
  656.    a warning.  MSG is a printf-style format string.
  657.    Optional arguments removed as an aid to portability. It was
  658.    either that or three very hairy sets of ifdefs for this style,
  659.    varargs, and stdargs.  */
  660.  
  661. void diag2(int level, char *msg, int a, int b)
  662. {
  663.     if (level)
  664.     found_err = 1;
  665.     if (output == stdout) {
  666.     fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
  667.     fprintf(stdout, msg, a, b);
  668.     fprintf(stdout, " */\n");
  669.     }
  670.     else {
  671.     fprintf(stderr, "%s: %d: ", in_name, line_no);
  672.     fprintf(stderr, msg, a, b);
  673.     fprintf(stderr, "\n");
  674.     }
  675. }
  676.  
  677. void diag1(int level, char *msg, int a)
  678. {
  679.     diag2(level, msg, a, 0);
  680. }
  681.  
  682. void diag(int level, char *msg)
  683. {
  684.     diag2(level, msg, 0, 0);
  685. }
  686.  
  687. void writefdef(register struct fstate *f, int nm)
  688. {
  689.     fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
  690.         nm, f->font, nm, f->size);
  691. }
  692.  
  693. /* Write characters starting at S to change the font from OF to NF.  Return
  694.    a pointer to the character after the last character written.
  695.    For troff mode only.  */
  696. char *
  697. chfont(register struct fstate *of, 
  698.        register struct fstate 
  699.                *nf, char *s)
  700. {
  701.     if (of->font[0] != nf->font[0]
  702.         || of->font[1] != nf->font[1]) {
  703.     *s++ = '\\';
  704.     *s++ = 'f';
  705.     if (nf->font[1]) {
  706.         *s++ = '(';
  707.         *s++ = nf->font[0];
  708.         *s++ = nf->font[1];
  709.     }
  710.     else
  711.         *s++ = nf->font[0];
  712.     }
  713.     if (nf->size != of->size) {
  714.     *s++ = '\\';
  715.     *s++ = 's';
  716.     if (nf->size < of->size) {
  717.         *s++ = '-';
  718.         *s++ = '0' + of->size - nf->size;
  719.     }
  720.     else {
  721.         *s++ = '+';
  722.         *s++ = '0' + nf->size - of->size;
  723.     }
  724.     }
  725.     return s;
  726. }
  727.  
  728.  
  729. void parsefont(register struct fstate *f, char *s0)
  730. {
  731.     register char *s = s0;
  732.     int         sizedelta = 0;
  733.     int i;
  734.     
  735.     f->size = 0;
  736.     f->allcaps = 1;
  737.     for (i = 0; i < 4; i++)
  738.       f->font[i] = 0;
  739.     
  740.     while (*s) {
  741.     if (isdigit(*s))
  742.         f->size = f->size * 10 + *s - '0';
  743.     else if (isupper(*s))
  744.         if (f->font[0])
  745.         f->font[1] = *s;
  746.         else
  747.         f->font[0] = *s;
  748.     else if (*s == 'c')
  749.         f->allcaps = 1;
  750.     else if (*s == '+')
  751.         sizedelta++;
  752.     else if (*s == '-')
  753.         sizedelta--;
  754.     else {
  755.         fprintf(stderr, "indent: bad font specification: %s\n", s0);
  756.         exit(1);
  757.     }
  758.     s++;
  759.     }
  760.     if (f->font[0] == 0)
  761.     f->font[0] = 'R';
  762.     if (bodyf.size == 0)
  763.     bodyf.size = 11;
  764.     if (f->size == 0)
  765.     f->size = bodyf.size + sizedelta;
  766.     else if (sizedelta > 0)
  767.     f->size += bodyf.size;
  768.     else
  769.     f->size = bodyf.size - f->size;
  770. }
  771.