home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / prgramer / pascal2c / out.c < prev    next >
C/C++ Source or Header  |  1992-08-03  |  37KB  |  1,581 lines

  1. /* "p2c", a Pascal to C translator.
  2.    Copyright (C) 1989, 1990, 1991 Free Software Foundation.
  3.    Author's address: daveg@csvax.caltech.edu; 256-80 Caltech/Pasadena CA 91125.
  4.  
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation (any version).
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program; see the file COPYING.  If not, write to
  16. the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17.  
  18.  
  19.  
  20.  
  21. /* This needs to go before trans.h (and thus p2c.proto) is read */
  22.  
  23. typedef struct S_paren {
  24.     struct S_paren *next;
  25.     int pos, indent, qmindent, flags;
  26. } Paren;
  27.  
  28.  
  29.  
  30. #define PROTO_OUT_C
  31. #include "trans.h"
  32.  
  33.  
  34. #ifndef USETIME
  35. # if defined(BSD) || defined(hpux)
  36. #  define USETIME 1
  37. # else
  38. #  define USETIME 0
  39. # endif
  40. #endif
  41.  
  42. #if USETIME
  43. # include <sys/time.h>
  44. #else
  45. # include <time.h>
  46. #endif
  47.  
  48.  
  49.  
  50.  
  51. /* Output control characters:
  52.  
  53.    \001  \B  Possible break point
  54.    \002  \X  Break point in parentheses
  55.    \003  \(  Invisible open paren
  56.    \004  \)  Invisible close paren
  57.    \005  \T  Set left margin
  58.    \006  \F  Forced break point
  59.    \007  \A  Preceding paren requires all-or-none breaking
  60.    \010  \[  Invisible open paren, becomes visible if not all on one line
  61.    \011  \S  Break point after last "special argument" of a function
  62.    \012  \n  (newline)
  63.    \013  \E  Preceding break has extra penalty
  64.    \014  \f  (form-feed)
  65.    \015  \H  Hang-indent the preceding operator
  66.    \016  \.  (unused)
  67.    \017  \C  Break point for last : of a ?: construct
  68.  
  69. */
  70.  
  71. char spchars[] = ".BX()TFA[SnEfH.C................";
  72.  
  73.  
  74.  
  75. Static int testinglinebreaker = 0;
  76.  
  77. Static int deltaindent, thisindent, thisfutureindent;
  78. Static int sectionsize, blanklines, codesectsize, hdrsectsize;
  79. Static int codelnum, hdrlnum;
  80.  
  81. #define MAXBREAKS  200
  82. Static int numbreaks, bestnumbreaks;
  83. Static double bestbadness;
  84. Static int breakpos[MAXBREAKS], breakindent[MAXBREAKS];
  85. Static int breakcount[MAXBREAKS], breakparen[MAXBREAKS];
  86. Static int bestbreakpos[MAXBREAKS], bestbreakindent[MAXBREAKS];
  87. Static int breakerrorflag;
  88.  
  89. #define MAXEDITS  200
  90. Static int numedits, bestnumedits;
  91. Static int editpos[MAXEDITS], besteditpos[MAXEDITS];
  92. Static char editold[MAXEDITS], editnew[MAXEDITS];
  93. Static char besteditold[MAXEDITS], besteditnew[MAXEDITS];
  94.  
  95. Static Paren *parenlist;
  96.  
  97. Static long numalts, bestnumalts;
  98. Static int randombreaks;
  99.  
  100. Static char *outbuf;
  101. Static int outbufpos, outbufcount, outbufsize;
  102. Static int suppressnewline, lastlinelength;
  103. Static int eatblanks;
  104. Static int embeddedcode;
  105. Static int showingsourcecode = 0;
  106.  
  107. #define BIGBADNESS  (1e20)
  108.  
  109.  
  110.  
  111. void setup_out()
  112. {
  113.     end_source();
  114.     if (!nobanner)
  115.     fprintf(outf, "/* From input file \"%s\" */\n", infname);
  116.     outf_lnum++;
  117.     hdrlnum = 1;
  118.     outindent = 0;
  119.     deltaindent = 0;
  120.     thisindent = 0;
  121.     thisfutureindent = -1;
  122.     sectionsize = 2;
  123.     blanklines = 0;
  124.     dontbreaklines = 0;
  125.     embeddedcode = 0;
  126.     outputmode = 0;
  127.     suppressnewline = 0;
  128.     eatblanks = 0;
  129.     outbufsize = 1000;
  130.     outbuf = ALLOC(outbufsize, char, misc);
  131.     outbufpos = 0;
  132.     outbufcount = 0;
  133.     srand(17);
  134. }
  135.  
  136.  
  137.  
  138. void select_outfile(fp)
  139. FILE *fp;
  140. {
  141.     if (outf == codef) {
  142.         codesectsize = sectionsize;
  143.     codelnum = outf_lnum;
  144.     } else {
  145.         hdrsectsize = sectionsize;
  146.     hdrlnum = outf_lnum;
  147.     }
  148.     outf = fp;
  149.     if (outf == codef) {
  150.         sectionsize = codesectsize;
  151.     outf_lnum = codelnum;
  152.     } else {
  153.         sectionsize = hdrsectsize;
  154.     outf_lnum = hdrlnum;
  155.     }
  156. }
  157.  
  158.  
  159.  
  160. void start_source()
  161. {
  162.     if (!showingsourcecode) {
  163.     fprintf(outf, "\n#ifdef Pascal\n");
  164.     showingsourcecode = 1;
  165.     }
  166. }
  167.  
  168. void end_source()
  169. {
  170.     if (showingsourcecode) {
  171.     fprintf(outf, "#endif /*Pascal*/\n\n");
  172.     showingsourcecode = 0;
  173.     }
  174. }
  175.  
  176.  
  177.  
  178. int line_start()
  179. {
  180.     return (outbufcount == 0);
  181. }
  182.  
  183.  
  184. int cur_column()
  185. {
  186.     if (outbufpos == 0)
  187.     return outindent;
  188.     else
  189.     return thisindent + outbufcount;
  190. }
  191.  
  192.  
  193.  
  194. int lookback(n)
  195. int n;
  196. {
  197.     if (n <= 0 || n > outbufpos)
  198.     return 0;
  199.     else
  200.     return outbuf[outbufpos - n];
  201. }
  202.  
  203.  
  204. int lookback_prn(n)
  205. int n;
  206. {
  207.     for (;;) {
  208.     if (n <= 0 || n > outbufpos)
  209.         return 0;
  210.     else if (outbuf[outbufpos - n] >= ' ')
  211.         return outbuf[outbufpos - n];
  212.     else
  213.         n++;
  214.     }
  215. }
  216.  
  217.  
  218.  
  219. /* Combine two indentation adjustments */
  220. int adddeltas(d1, d2)
  221. int d1, d2;
  222. {
  223.     if (d2 >= 1000)
  224.     return d2;
  225.     else
  226.     return d1 + d2;
  227. }
  228.  
  229.  
  230. /* Apply an indentation delta */
  231. int applydelta(i, d)
  232. int i, d;
  233. {
  234.     if (d >= 1000)
  235.     return d - 1000;
  236.     else
  237.     return i + d;
  238. }
  239.  
  240.  
  241. /* Adjust the current indentation by delta */
  242. void moreindent(delta)
  243. int delta;
  244. {
  245.     outindent = applydelta(outindent, delta);
  246. }
  247.  
  248.  
  249. /* Adjust indentation for just this line */
  250. void singleindent(delta)
  251. int delta;
  252. {
  253.     deltaindent = adddeltas(deltaindent, delta);
  254. }
  255.  
  256.  
  257. /* Predict indentation for next line */
  258. void futureindent(num)
  259. int num;
  260. {
  261.     thisfutureindent = applydelta(applydelta(outindent, deltaindent), num);
  262. }
  263.  
  264.  
  265. int parsedelta(cp, def)
  266. char *cp;
  267. int def;
  268. {
  269.     if (!cp || !*cp)
  270.     return def;
  271.     if ((*cp == '+' || *cp == '-') && isdigit(cp[1]))
  272.     return atoi(cp);
  273.     if (*cp == '*' && isdigit(cp[1]))
  274.     return 2000 + atoi(cp+1);
  275.     else
  276.     return 1000 + atoi(cp);
  277. }
  278.  
  279.  
  280.  
  281.  
  282. Static void leading_tab(col)
  283. int col;
  284. {
  285.     if (col > maxlinewidth)
  286.     return;    /* something wrong happened! */
  287.     if (phystabsize > 0) {
  288.     while (col >= phystabsize) {
  289.         putc('\t', outf);
  290.         col -= phystabsize;
  291.     }
  292.     }
  293.     while (col > 0) {
  294.     putc(' ', outf);
  295.     col--;
  296.     }
  297. }
  298.  
  299.  
  300.  
  301. void eatblanklines()
  302. {
  303.     eatblanks = 1;
  304. }
  305.  
  306.  
  307.  
  308. Static void flush_outbuf(numbreaks, breakpos, breakindent,
  309.              numedits, editpos, editold, editnew)
  310. int numbreaks, *breakpos, *breakindent, numedits, *editpos;
  311. char *editold, *editnew;
  312. {
  313.     unsigned char ch, ch2;
  314.     char *cp;
  315.     int i, j, linelen = 0, spaces, hashline;
  316.     int editsaves[MAXEDITS];
  317.  
  318.     end_source();
  319.     if (outbufcount > 0) {
  320.     for (i = 0; i < numedits; i++) {
  321.         editsaves[i] = outbuf[editpos[i]];
  322.         outbuf[editpos[i]] = editnew[i];
  323.     }
  324.     leading_tab(thisindent);
  325.     cp = outbuf;
  326.     hashline = (*cp == '#');    /* a preprocessor directive */
  327.     spaces = 0;
  328.     j = 1;
  329.     for (i = 0; i < outbufpos; ) {
  330.         if (j < numbreaks && i == breakpos[j]) {
  331.         if (hashline)
  332.             fprintf(outf, " \\");   /* trailing backslash required */
  333.         putc('\n', outf);
  334.         outf_lnum++;
  335.         leading_tab(breakindent[j]);
  336.         linelen = breakindent[j];
  337.         j++;
  338.         while (i < outbufpos && *cp == ' ')
  339.             i++, cp++;   /* eat leading spaces */
  340.         spaces = 0;      /* eat trailing spaces */
  341.         } else {
  342.         ch = *cp++;
  343.         if (ch == ' ') {
  344.             spaces++;
  345.         } else if (ch > ' ') {
  346.             linelen += spaces;
  347.             while (spaces > 0)
  348.             putc(' ', outf), spaces--;
  349.             linelen++;
  350.             if (ch == '\\' && embeddedcode) {
  351.             if (*cp == '[') {
  352.                 putc('{', outf);
  353.                 cp++, i++;
  354.             } else if (*cp == ']') {
  355.                 putc('}', outf);
  356.                 cp++, i++;
  357.             } else
  358.                 putc(ch, outf);
  359.             } else
  360.             putc(ch, outf);
  361.         } else if (testinglinebreaker >= 3) {
  362.             linelen += spaces;
  363.             while (spaces > 0)
  364.             putc(' ', outf), spaces--;
  365.             linelen++;
  366.             putc('\\', outf);
  367.             ch2 = spchars[ch];
  368.             if (ch2 != '.')
  369.             putc(ch2, outf);
  370.             else {
  371.             putc('0' + ((ch >> 6) & 7), outf);
  372.             putc('0' + ((ch >> 3) & 7), outf);
  373.             putc('0' + (ch & 7), outf);
  374.             }
  375.         }
  376.         i++;
  377.         }
  378.     }
  379.     for (i = 0; i < numedits; i++)
  380.         outbuf[editpos[i]] = editsaves[i];
  381.     eatblanks = 0;
  382.     } else if (eatblanks) {
  383.     return;
  384.     }
  385.     if (suppressnewline) {
  386.     lastlinelength = linelen;
  387.     } else
  388.     putc('\n', outf);
  389.     outf_lnum++;
  390. }
  391.  
  392.  
  393.  
  394. #define ISQUOTE(ch)  ((ch)=='"' || (ch)=='\'')
  395. #define ISOPENP(ch)  ((ch)=='(' || (ch)=='[' || (ch)=='\003' || (ch)=='\010')
  396. #define ISCLOSEP(ch) ((ch)==')' || (ch)==']' || (ch)=='\004')
  397. #define ISBREAK(ch)  ((ch)=='\001' || (ch)=='\002' || (ch)=='\006' || (ch)=='\011' || (ch)=='\017')
  398.  
  399. Static int readquotes(posp, err)
  400. int *posp, err;
  401. {
  402.     int pos;
  403.     char quote;
  404.  
  405.     pos = *posp;
  406.     quote = outbuf[pos++];
  407.     while (pos < outbufpos && outbuf[pos] != quote) {
  408.     if (outbuf[pos] == '\\')
  409.         pos++;
  410.     pos++;
  411.     }
  412.     if (pos >= outbufpos) {
  413.     if (err && breakerrorflag) {
  414.         intwarning("output", "Mismatched quotes [248]");
  415.         breakerrorflag = 0;
  416.     }
  417.     return 0;
  418.     } else {
  419.     *posp = pos;
  420.     return 1;
  421.     }    
  422. }
  423.  
  424.  
  425. Static int maxdepth;
  426.  
  427. Static int readparens(posp, err)
  428. int *posp, err;
  429. {
  430.     char ch, closing;
  431.     int pos, level;
  432.  
  433.     pos = *posp;
  434.     switch (outbuf[pos]) {
  435.       case '(':
  436.     closing = ')';
  437.     break;
  438.       case '[':
  439.     closing = ']';
  440.     break;
  441.       case '\003':
  442.       case '\010':
  443.     closing = '\004';
  444.     break;
  445.       default:
  446.     closing = 0;
  447.     break;
  448.     }
  449.     level = 0;
  450.     for (;;) {
  451.     pos++;
  452.     if (pos >= outbufpos)
  453.         break;
  454.     ch = outbuf[pos];
  455.     if (ISOPENP(ch)) {
  456.         level++;
  457.         if (level > maxdepth)
  458.         maxdepth = level;
  459.     } else if (ISCLOSEP(ch)) {
  460.         level--;
  461.         if (level < 0) {
  462.         if (closing && outbuf[pos] != closing)
  463.             break;
  464.         *posp = pos;
  465.         return 1;
  466.         }
  467.     } else if (ISQUOTE(ch)) {
  468.         if (!readquotes(&pos, err))
  469.         return 0;
  470.     }
  471.     }
  472.     if (err && breakerrorflag) {
  473.     switch (closing) {
  474.       case ')':
  475.         intwarning("output", "Mismatched parentheses [249]");
  476.         break;
  477.       case ']':
  478.         intwarning("output", "Mismatched brackets [249]");
  479.         break;
  480.       default:
  481.         intwarning("output", "Mismatched clauses [250]");
  482.         break;
  483.     }
  484.     breakerrorflag = 0;
  485.     }
  486.     return 0;
  487. }
  488.  
  489.  
  490.  
  491. Static int measurechars(first, last)
  492. int first, last;
  493. {
  494.     int count = 0;
  495.  
  496.     while (first <= last) {
  497.     if (outbuf[first] >= ' ')
  498.         count++;
  499.     first++;
  500.     }
  501.     return count;
  502. }
  503.  
  504.  
  505.  
  506. Static void makeedit(pos, ch)
  507. int pos, ch;
  508. {
  509.     editpos[numedits] = pos;
  510.     editold[numedits] = outbuf[pos];
  511.     editnew[numedits] = ch;
  512.     outbuf[pos] = ch;
  513.     numedits++;
  514. }
  515.  
  516. Static void unedit()
  517. {
  518.     numedits--;
  519.     outbuf[editpos[numedits]] = editold[numedits];
  520. }
  521.  
  522.  
  523. Static int parencount(par)
  524. Paren *par;
  525. {
  526.     int count = 0;
  527.  
  528.     while (par) {
  529.     count++;
  530.     par = par->next;
  531.     }
  532.     return count;
  533. }
  534.  
  535.  
  536.  
  537.  
  538.  
  539. /* The following routine explores the tree of all possible line breaks,
  540.    pruning according to the fact that "badness" and "extra" are
  541.    increasing functions.  The object is to find the set of breaks and
  542.    indentation with the least total badness.
  543.    (The basic idea was borrowed from Donald Knuth's "TeX".)
  544. */
  545.  
  546. /* As an additional optimization, the concept of a "simple" line is used,
  547.    i.e., a line with a structure such that the best break is sure to be
  548.    the straightforward left-to-right fill used by a simple word processor.
  549.    (For example, a long line with nothing but comma-breakpoints is simple.)
  550.  
  551.    Also, if the line is very long a few initial random passes are made just
  552.    to scope out an estimate of the eventual badness of the line.  This
  553.    combined with the badness cull helps keep the breaker from using up its
  554.    quota of tries before even considering a key break point!  Note that
  555.    when randombreaks==1, each call to trybreakline is fast since only one
  556.    branch is taken at each decision point.
  557. */
  558.  
  559.  
  560. #define randtest(lim)  (!randombreaks ? -1    \
  561.             : randombreaks > 0    \
  562.                 ? parencount(parens) < randombreaks-1   \
  563.             : randombreaks == -2  \
  564.                 ? 0 \
  565.             : (rand() & 0xfff) < (lim))
  566.  
  567. #define TB_BRKCOUNT   0x0ff
  568. #define TB_FORCEBRK   0x100
  569. #define TB_NOBREAK    0x200
  570. #define TB_ALREADYBRK 0x400
  571. #define TB_ALLORNONE  0x800
  572. #define TB_EXTRAIND   0x1000
  573. #define TB_EXTRAIND2  0x2000
  574.  
  575. #define TBR_ABORT     0x1
  576. #define TBR_SIMPLE    0x2
  577. #define TBR_REACHED   0x4
  578.  
  579. Static int trybreakline(pos, count, indent, badness, flags, parens)
  580. int pos, count, indent, flags;
  581. double badness;
  582. Paren *parens;
  583. {
  584.     int edited;
  585.     int i, j, jmask, f, pos2, r;
  586.     char ch, ch2, closing;
  587.     double extra, penalty;
  588.     Paren *pp;
  589.  
  590. #if 0
  591.     { static double save = -1;
  592.       if (showbadlimit != save) printf("Showbadlimit = %g\n", showbadlimit);
  593.       save = showbadlimit;
  594.     }
  595. #endif
  596.  
  597.     if (numalts >= maxalts)
  598.     return TBR_ABORT;
  599.     jmask = -1;
  600.     for (;;) {
  601.     if (numbreaks >= MAXBREAKS) {   /* must leave rest of line alone */
  602.         count += measurechars(pos, outbufpos-1);
  603.         pos = outbufpos;
  604.     }
  605.     i = count - breakcount[numbreaks-1] +
  606.         breakindent[numbreaks-1] - linewidth;
  607.     if (i <= 0)
  608.         extra = 0;
  609.     else {
  610.         if (i + linewidth >= maxlinewidth || randombreaks == -2)
  611.         return 0;   /* absolutely too long! */
  612.         extra = overwidepenalty + ((long)i*i)*overwideextrapenalty;
  613.         jmask &= ~TBR_SIMPLE;
  614.         if (extra < 0)
  615.         extra = 0;
  616.     }
  617.     if ((testinglinebreaker > 1 && showbadlimit > 0) ?
  618.         (badness + extra >= showbadlimit) :
  619.         (badness + extra >= bestbadness)) {
  620.         numalts++;
  621.         return 0;   /* no point in going on, badness will only increase */
  622.     }
  623.     if (pos >= outbufpos)
  624.         break;
  625.     if (parens && pos >= parens->pos) {
  626.         indent = parens->indent;
  627.         flags = parens->flags;
  628.         parens = parens->next;
  629.     }
  630.     ch = outbuf[pos++];
  631.     if (ch >= ' ')
  632.         count++;
  633.     switch (ch) {
  634.  
  635.       case '(':
  636.       case '[':
  637.       case '\003':     /* "invisible open paren" */
  638.       case '\010':     /* "semi-invisible open paren" */
  639.         pos2 = pos - 1;
  640.         if (!readparens(&pos2, 1))
  641.         break;
  642.         i = measurechars(pos, pos2);
  643.         if (count + i - breakcount[numbreaks-1] +
  644.         breakindent[numbreaks-1] <= linewidth) {
  645.         /* it fits, so leave it on one line */
  646. #if 0  /* I don't think this is necessary */
  647.         while (pos <= pos2) {
  648.             if (outbuf[pos] == '\002') {
  649.             jmask &= ~TBR_SIMPLE;
  650.             pos = pos2 + 1;
  651.             break;
  652.             }
  653.             pos++;
  654.         }
  655. #else
  656.         pos = pos2 + 1;
  657. #endif
  658.         count += i;
  659.         break;
  660.         }
  661.         pp = ALLOC(1, Paren, parens);   /* doesn't fit, try poss breaks */
  662.         pp->next = parens;
  663.         pp->pos = pos2;
  664.         pp->indent = indent;
  665.         pp->qmindent = indent;
  666.         pp->flags = flags;
  667.         parens = pp;
  668.         flags = 0;
  669.         if (ch == '\010' &&       /* change to real parens when broken */
  670.         numedits+1 < MAXEDITS) {    /* (assume it will be broken!) */
  671.         makeedit(pos-1, '(');
  672.         makeedit(pos2, ')');
  673.         count++;    /* count the new open paren */
  674.         edited = 1;
  675.         } else
  676.         edited = 0;
  677.         i = breakindent[numbreaks-1] + count - breakcount[numbreaks-1];
  678.         if (i <= thisindent)
  679.         r = 0;  /* e.g., don't break top-level assignments */
  680.         else if (i == indent + extraindent)
  681.         r = 1;  /* don't waste time on identical operations */
  682.         else
  683.         r = randtest(0xc00);
  684.         if (r != 0) {
  685.         j = trybreakline(pos, count, i,
  686.                  badness + MAX(- extraindentpenalty,0),
  687.                  flags, parens);
  688.         } else
  689.         j = 0;
  690.         if (r != 1) {
  691.         j &= trybreakline(pos, count, indent + extraindent,
  692.                   badness + MAX(extraindentpenalty,0),
  693.                   flags | TB_EXTRAIND, parens);
  694.         }
  695.         if (!randombreaks && bumpindent != 0) {
  696.         if (i == thisfutureindent) {
  697.             j &= trybreakline(pos, count, i + bumpindent,
  698.                       badness + MAX(- extraindentpenalty,0)
  699.                               + bumpindentpenalty,
  700.                       flags, parens);
  701.         } else if (indent + extraindent == thisfutureindent) {
  702.             j &= trybreakline(pos, count,
  703.                       indent + extraindent + bumpindent,
  704.                       badness + MAX(extraindentpenalty,0)
  705.                               + bumpindentpenalty,
  706.                       flags | TB_EXTRAIND, parens);
  707.         }
  708.         }
  709.         if (edited) {
  710.         unedit();
  711.         unedit();
  712.         }
  713.         FREE(pp);
  714.         return j & jmask;
  715.  
  716.       case '\005':   /* "set left margin" */
  717.         indent = breakindent[numbreaks-1] +
  718.              count - breakcount[numbreaks-1];
  719.         break;
  720.  
  721.       case '\007':   /* "all-or-none breaking" */
  722.         flags |= TB_ALLORNONE;
  723.         break;
  724.  
  725.       case '\001':   /* "possible break point" */
  726.       case '\002':   /* "break point in parens" */
  727.       case '\006':   /* "forced break point" */
  728.       case '\011':   /* "break point after special args" */
  729.       case '\017':   /* "break point for final : operator" */
  730.         /* first try the non-breaking case */
  731.         if (ch != '\001' && ch != '\006')
  732.         jmask &= ~TBR_SIMPLE;
  733.         if ((flags & TB_BRKCOUNT) != TB_BRKCOUNT)
  734.         flags++;   /* increment TB_BRKCOUNT field */
  735.         if (outbuf[pos] == '?' && parens)
  736.         parens->qmindent = breakindent[numbreaks-1] +
  737.                            count - breakcount[numbreaks-1];
  738.         j = TBR_REACHED;
  739.         if (ch == '\006' || (flags & TB_FORCEBRK)) {
  740.         /* don't try the non-breaking case */
  741.         } else {
  742.         if (ch == '\011') {
  743.             i = breakindent[numbreaks-1] +
  744.             count - breakcount[numbreaks-1] + 2;
  745.         } else {
  746.             i = indent;
  747.         }
  748.         f = flags;
  749.         if (f & TB_ALLORNONE)
  750.             f |= TB_NOBREAK;
  751.         r = randtest(0x800);
  752.         if (r != 1 || (flags & TB_NOBREAK)) {
  753.             j = trybreakline(pos, count, i, badness, f, parens) &
  754.             jmask;
  755.             if (randombreaks == -2 && !(j & TBR_REACHED)) {
  756.             r = -1;
  757.             j |= TBR_REACHED;
  758.             }
  759.             if (r == 0 || (j & TBR_SIMPLE))
  760.             flags |= TB_NOBREAK;
  761.         }
  762.         }
  763.         if (flags & TB_NOBREAK)
  764.         return j;
  765.         if (flags & TB_ALLORNONE)
  766.         flags |= TB_FORCEBRK;
  767.         if (flags & TB_EXTRAIND) {
  768.         flags &= ~TB_EXTRAIND;
  769.         flags |= TB_EXTRAIND2;
  770.         }
  771.         /* now try breaking here */
  772.         if (ch == '\017')
  773.         indent = parens->qmindent;
  774.         if (indent < 0)
  775.         indent = 0;
  776.         breakpos[numbreaks] = pos;
  777.         breakcount[numbreaks] = count;
  778.         breakindent[numbreaks] = indent;
  779.         breakparen[numbreaks] = parens ? parens->pos : 0;
  780.         numbreaks++;
  781.         penalty = extra;
  782.         if (indent == thisfutureindent) {
  783.         i = pos;
  784.         while (i < outbufpos-1 && outbuf[i] <= ' ')
  785.             i++;
  786.         ch2 = outbuf[i];   /* first character on next line */
  787.         if (ch2 != '(' && ch2 != '!' && ch2 != '~' && ch2 != '-')
  788.             penalty += nobumpindentpenalty;
  789.         }
  790.         switch (ch) {
  791.           case '\001':
  792.         penalty += commabreakpenalty;
  793.         if (flags & TB_ALREADYBRK)
  794.             penalty += morebreakpenalty;
  795.         break;
  796.           case '\011':
  797.         i = parencount(parens);
  798.         penalty += specialargbreakpenalty + commabreakextrapenalty*i;
  799.         break;
  800.           case '\002':
  801.           case '\017':
  802.         i = parencount(parens);
  803.         if (outbuf[pos-2] == '(')
  804.             penalty += parenbreakpenalty + parenbreakextrapenalty*i;
  805.         else if (outbuf[pos-2] == ',')
  806.             penalty += commabreakpenalty + commabreakextrapenalty*i;
  807.         else if (((outbuf[pos] == '&' || outbuf[pos] == '|') &&
  808.               outbuf[pos+1] == outbuf[pos]) ||
  809.              ((outbuf[pos-3] == '&' || outbuf[pos-3] == '|') &&
  810.               outbuf[pos-3] == outbuf[pos-2]))
  811.             penalty += logbreakpenalty + logbreakextrapenalty*i;
  812.         else if (((outbuf[pos] == '<' || outbuf[pos] == '>') &&
  813.               outbuf[pos+1] != outbuf[pos]) ||
  814.              ((outbuf[pos] == '=' || outbuf[pos] == '!') &&
  815.               outbuf[pos+1] == '=') ||
  816.              ((outbuf[pos-2] == '<' || outbuf[pos-2] == '>') &&
  817.               outbuf[pos-3] != outbuf[pos-2]) ||
  818.              ((outbuf[pos-3] == '<' || outbuf[pos-3] == '>' ||
  819.                outbuf[pos-3] == '=' || outbuf[pos-3] == '!') &&
  820.               outbuf[pos-2] == '='))
  821.             penalty += relbreakpenalty + relbreakextrapenalty*i;
  822.         else if (outbuf[pos-2] == '=')
  823.             penalty += assignbreakpenalty + assignbreakextrapenalty*i;
  824.         else if (outbuf[pos] == '?') {
  825.             penalty += qmarkbreakpenalty + qmarkbreakextrapenalty*i;
  826.             if (parens)
  827.             parens->qmindent = breakindent[numbreaks-1] +
  828.                                count - breakcount[numbreaks-1];
  829.         } else
  830.             penalty += opbreakpenalty + opbreakextrapenalty*i;
  831.         if (outbuf[pos-2] == '-')
  832.             penalty += exhyphenpenalty;
  833.         if (flags & TB_ALREADYBRK)
  834.             penalty += morebreakpenalty + morebreakextrapenalty*i;
  835.         break;
  836.           default:
  837.         break;
  838.         }
  839.         while (pos < outbufpos && outbuf[pos] == '\013') {
  840.         penalty += wrongsidepenalty;
  841.         pos++;
  842.         }
  843.         penalty -= earlybreakpenalty*(flags & TB_BRKCOUNT);
  844.         /* the following test is not quite right, but it's not too bad. */
  845.         if (breakindent[numbreaks-2] == breakindent[numbreaks-1] &&
  846.         breakparen[numbreaks-2] != breakparen[numbreaks-1])
  847.         penalty += sameindentpenalty;
  848. #if 0
  849.         else if (ch == '\002' && parens &&  /*don't think this is needed*/
  850.              parens->indent == breakindent[numbreaks-1] &&
  851.              parens->pos != breakparen[numbreaks-1])
  852.         penalty += sameindentpenalty + 0.001;   /***/
  853. #endif
  854.         penalty += (breakindent[numbreaks-1] - thisindent) *
  855.                indentamountpenalty;
  856.         if (penalty < 1) penalty = 1;
  857.         pos2 = pos;
  858.         while (pos2 < outbufpos && outbuf[pos2] == ' ')
  859.         pos2++;
  860.         flags |= TB_ALREADYBRK;
  861.         j = trybreakline(pos2, count, indent, badness + penalty,
  862.                  flags, parens) & jmask;
  863.         numbreaks--;
  864.         return j;
  865.         
  866.       case '\015':    /* "hang-indent operator" */
  867.         if (count <= breakcount[numbreaks-1] + 2 &&
  868.         !(flags & TB_EXTRAIND2)) {
  869.         breakindent[numbreaks-1] -= count - breakcount[numbreaks-1];
  870.         pos2 = pos;
  871.         while (pos2 < outbufpos && outbuf[pos2] <= ' ') {
  872.             if (outbuf[pos2] == ' ')
  873.             breakindent[numbreaks-1]--;
  874.             pos2++;
  875.         }
  876.         }
  877.         break;
  878.  
  879.       case '"':
  880.       case '\'':
  881.         closing = ch;
  882.         while (pos < outbufpos && outbuf[pos] != closing) {
  883.         if (outbuf[pos] == '\\')
  884.             pos++, count++;
  885.         pos++;
  886.         count++;
  887.         }
  888.         if (pos >= outbufpos) {
  889.         intwarning("output", "Mismatched quotes [248]");
  890.         continue;
  891.         }
  892.         pos++;
  893.         count++;
  894.         break;
  895.  
  896.       case '/':
  897.         if (pos < outbufpos && (outbuf[pos] == '*' ||
  898.                     (outbuf[pos] == '/' && cplus > 0))) {
  899.         count += measurechars(pos, outbufpos-1);
  900.         pos = outbufpos;   /* assume comment is at end of line */
  901.         }
  902.         break;
  903.  
  904.     }
  905.     }
  906.     numalts++;
  907.     badness += extra;
  908.     if (testinglinebreaker > 1) {
  909.     if (badness >= bestbadness &&
  910.         (badness < showbadlimit || showbadlimit == 0)) {
  911.         fprintf(outf, "\n#if 0   /* rejected #%ld, badness = %g >= %g */\n", numalts, badness, bestbadness);
  912.         flush_outbuf(numbreaks, breakpos, breakindent,
  913.              numedits, editpos, editold, editnew);
  914.         fprintf(outf, "#endif\n");
  915.         return TBR_SIMPLE & jmask;
  916.     } else if ((bestbadness < showbadlimit || showbadlimit == 0) &&
  917.            bestnumalts > 0) {
  918.         fprintf(outf, "\n#if 0   /* rejected #%ld, badness = %g > %g */\n", bestnumalts, bestbadness, badness);
  919.         flush_outbuf(bestnumbreaks, bestbreakpos, bestbreakindent,
  920.              bestnumedits, besteditpos,
  921.              besteditold, besteditnew);
  922.         fprintf(outf, "#endif\n");
  923.     }
  924.     }
  925.     bestbadness = badness;
  926.     bestnumbreaks = numbreaks;
  927.     bestnumalts = numalts;
  928.     for (i = 0; i < numbreaks; i++) {
  929.     bestbreakpos[i] = breakpos[i];
  930.     bestbreakindent[i] = breakindent[i];
  931.     }
  932.     bestnumedits = numedits;
  933.     for (i = 0; i < numedits; i++) {
  934.     besteditpos[i] = editpos[i];
  935.     besteditold[i] = editold[i];
  936.     besteditnew[i] = editnew[i];
  937.     }
  938.     return TBR_SIMPLE & jmask;
  939. }
  940.  
  941.  
  942.  
  943.  
  944. int parse_breakstr(cp)
  945. char *cp;
  946. {
  947.     short val = 0;
  948.  
  949.     if (isdigit(*cp))
  950.     return atoi(cp);
  951.     while (*cp && !isspace(*cp) && *cp != '}') {
  952.     switch (toupper(*cp++)) {
  953.  
  954.       case 'N':
  955.       case '=':
  956.         break;
  957.  
  958.       case 'L':
  959.         val |= BRK_LEFT;
  960.         break;
  961.  
  962.       case 'R':
  963.         val |= BRK_RIGHT;
  964.         break;
  965.  
  966.       case 'H':
  967.         val |= BRK_HANG | BRK_LEFT;
  968.         break;
  969.  
  970.       case '>':
  971.         if (val & BRK_LEFT)
  972.         val |= BRK_LPREF;
  973.         else if (val & BRK_RIGHT)
  974.         val |= BRK_RPREF;
  975.         else
  976.         return -1;
  977.         break;
  978.  
  979.       case '<':
  980.         if (val & BRK_LEFT)
  981.         val |= BRK_RPREF;
  982.         else if (val & BRK_RIGHT)
  983.         val |= BRK_LPREF;
  984.         else
  985.         return -1;
  986.         break;
  987.  
  988.       case 'A':
  989.         val |= BRK_ALLNONE;
  990.         break;
  991.  
  992.       default:
  993.         return -1;
  994.  
  995.     }
  996.     }
  997.     return val;
  998. }
  999.  
  1000.  
  1001.  
  1002.  
  1003. long getcurtime()
  1004. {
  1005. #if USETIME
  1006.     static unsigned long starttime = 0;
  1007.     struct timeval t;
  1008.     struct timezone tz;
  1009.  
  1010.     gettimeofday(&t, &tz);
  1011.     if (starttime == 0)
  1012.     starttime = t.tv_sec;
  1013.     t.tv_sec -= starttime;
  1014.     return (t.tv_sec*1000 + t.tv_usec/1000);
  1015. #else
  1016.     static unsigned long starttime = 0;
  1017.     if (!starttime) starttime = time(NULL);
  1018.     return (time(NULL) - starttime) * 1000;
  1019. #endif
  1020. }
  1021.  
  1022.  
  1023.  
  1024. void output(msg)
  1025. register char *msg;
  1026. {
  1027.     unsigned char ch;
  1028.     double savelimit;
  1029.     int i, savemaxlw, maxdp;
  1030.     long alts;
  1031.     long time0, time0a, time1;
  1032.  
  1033.     debughook();
  1034.     if (outputmode) {
  1035.     end_source();
  1036.     while ((ch = *msg++) != 0) {
  1037.         if (ch >= ' ') {
  1038.         putc(ch, outf);
  1039.         } else if (ch == '\n') {
  1040.         putc('\n', outf);
  1041.         outf_lnum++;
  1042.         }
  1043.     }
  1044.     return;
  1045.     }
  1046.     while ((ch = *msg++) != 0) {
  1047.     if (ch == '\n') {
  1048.         if (outbufpos == 0) {      /* blank line */
  1049.         thisfutureindent = -1;
  1050.         blanklines++;
  1051.         continue;
  1052.         }
  1053.         if (sectionsize > blanklines)
  1054.         blanklines = sectionsize;
  1055.         sectionsize = 0;
  1056.         if (eatblanks)
  1057.         blanklines = 0;
  1058.             while (blanklines > 0) {
  1059.                 blanklines--;
  1060.         end_source();
  1061.                 putc('\n', outf);
  1062.         outf_lnum++;
  1063.             }
  1064.         if (thisindent + outbufcount >= linewidth && !dontbreaklines) {
  1065.         numbreaks = 1;
  1066.         bestnumbreaks = 0;
  1067.         bestbadness = BIGBADNESS;
  1068.         breakpos[0] = 0;
  1069.         breakindent[0] = thisindent;
  1070.         breakcount[0] = 0;
  1071.         breakerrorflag = 1;
  1072.         numedits = 0;
  1073.         bestnumedits = 0;
  1074.         savelimit = showbadlimit;
  1075.         numalts = 0;
  1076.         bestnumalts = 0;
  1077.         savemaxlw = maxlinewidth;
  1078.         time0 = time0a = getcurtime();
  1079.         if (regression)
  1080.             srand(17);
  1081.         if (thisindent + outbufcount > linewidth*3/2) {
  1082.             i = 0;
  1083.             maxdepth = 0;
  1084.             readparens(&i, 0);
  1085.             maxdp = maxdepth;
  1086.             for (;;) {    /* try some simple fixed methods first... */
  1087.             for (i = 1; i <= 20; i++) {
  1088.                 randombreaks = -1;
  1089.                 trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1090.             }
  1091.             randombreaks = -2;
  1092.             trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1093.             for (i = 0; i <= maxdp+1; i++) {
  1094.                 randombreaks = i+1;
  1095.                 trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1096.             }
  1097.             if (bestbadness == BIGBADNESS && maxlinewidth < 9999) {
  1098.                 maxlinewidth = 9999;   /* no choice but to relax */
  1099.                 numalts = 0;
  1100.             } else
  1101.                 break;
  1102.             }
  1103.             time0a = getcurtime();
  1104.         }
  1105.         randombreaks = 0;
  1106.         trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1107.         if (bestbadness == BIGBADNESS && maxlinewidth < 9999) {
  1108.             numalts = 0;
  1109.             maxlinewidth = 9999;   /* no choice but to relax this */
  1110.             trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1111.         }
  1112.         time1 = getcurtime() - time0;
  1113.         alts = numalts;
  1114.         if (testinglinebreaker) {
  1115.             if (savelimit < 0 && testinglinebreaker > 1) {
  1116.             showbadlimit = bestbadness * (-savelimit);
  1117.             numalts = 0;
  1118.             bestnumalts = 0;
  1119.             trybreakline(0, 0, thisindent, 0.0, 0, NULL);
  1120.             }
  1121.             fprintf(outf, "\n#if 1   /* accepted #%ld, badness = %g, tried %ld in %.3f sec */\n", bestnumalts, bestbadness, alts, time1/1000.0);
  1122.         }
  1123.         showbadlimit = savelimit;
  1124.         maxlinewidth = savemaxlw;
  1125.         flush_outbuf(bestnumbreaks, bestbreakpos, bestbreakindent,
  1126.                  bestnumedits, besteditpos,
  1127.                  besteditold, besteditnew);
  1128.         if (((USETIME && time1 > 1000) || alts >= maxalts) &&
  1129.             !regression) {
  1130.             sprintf(outbuf, "Line breaker spent %.1f",
  1131.                 (time1 + time0 - time0a) / 1000.0);
  1132.             if (time0 != time0a)
  1133.             sprintf(outbuf + strlen(outbuf),
  1134.                 "+%.2f", (time0a - time0) / 1000.0);
  1135.             sprintf(outbuf + strlen(outbuf),
  1136.                 " seconds, %ld tries on line %d [251]", alts, outf_lnum);
  1137.             note(outbuf);
  1138.         } else if (verbose) {
  1139.             fprintf(logf, "%s, %d/%d: Line breaker spent %ld tries\n",
  1140.                 infname, inf_lnum, outf_lnum, alts);
  1141.         }
  1142.         if (testinglinebreaker)
  1143.             fprintf(outf, "#endif\n\n");
  1144.         } else {
  1145.         if (testinglinebreaker < 2)
  1146.             flush_outbuf(0, NULL, NULL, 0, NULL, NULL, NULL);
  1147.         }
  1148.         thisfutureindent = -1;
  1149.         outbufpos = 0;
  1150.         outbufcount = 0;
  1151.     } else {
  1152.         if (outbufpos == 0) {
  1153.         if (ch == ' ' && !dontbreaklines)    /* eat leading spaces */
  1154.             continue;
  1155.         thisindent = applydelta(outindent, deltaindent);
  1156.         deltaindent = 0;
  1157.         }
  1158.         if (outbufpos == outbufsize) {
  1159.         outbufsize *= 2;
  1160.         outbuf = REALLOC(outbuf, outbufsize, char);
  1161.         }
  1162.         outbuf[outbufpos++] = ch;
  1163.         if (ch >= ' ')
  1164.         outbufcount++;
  1165.     }
  1166.     }
  1167. }
  1168.  
  1169.  
  1170.  
  1171. void out_n_spaces(n)
  1172. int n;
  1173. {
  1174.     while (--n >= 0)
  1175.     output(" ");
  1176. }
  1177.  
  1178.  
  1179.  
  1180. void out_spaces(spc, over, len, delta)
  1181. int spc, over, len, delta;
  1182. {
  1183.     int n;
  1184.  
  1185.     if (spc == -999)
  1186.     spc = commentindent;
  1187.     if (spc < 0) {               /* right-justify */
  1188.     n = (-spc) - cur_column() - len;
  1189.     if (n < minspcthresh)
  1190.         n = minspacing;
  1191.     else
  1192.         over = 1000;
  1193.     } else if (spc >= 2000) {    /* tab to multiple */
  1194.     spc -= 2000;
  1195.     n = (spc-1) - ((cur_column()+spc-1) % spc);
  1196.     if (n < minspcthresh)
  1197.         n += spc;
  1198.     } else if (spc >= 1000) {    /* absolute column */
  1199.     spc -= 1000;
  1200.     n = spc - cur_column();
  1201.     if (n < minspcthresh)
  1202.         n = minspacing;
  1203.     } else                       /* relative spacing */
  1204.     n = spc;
  1205.     if (line_start()) {
  1206.     singleindent(n);
  1207.     } else if (len > 0 && over != 1000 && cur_column() + n + len > linewidth) {
  1208.     output("\n");
  1209.     out_spaces(over, 1000, len, 0);
  1210.     singleindent(delta);
  1211.     } else {
  1212.     out_n_spaces(n);
  1213.     }
  1214. }
  1215.  
  1216.  
  1217.  
  1218.  
  1219. void testlinebreaker(lev, fn)
  1220. int lev;
  1221. char *fn;
  1222. {
  1223.     char buf[256], *bp, *cp;
  1224.     int first, indent;
  1225.  
  1226.     testinglinebreaker = lev;
  1227.     if (!fn)
  1228.     return;
  1229.     inf = fopen(fn, "r");
  1230.     if (!inf) {
  1231.     perror(fn);
  1232.     exit(1);
  1233.     }
  1234.     sprintf(buf, "%s.br", fn);
  1235.     outf = fopen(buf, "w");
  1236.     if (!outf) {
  1237.     perror(buf);
  1238.     exit(1);
  1239.     }
  1240.     setup_out();
  1241.     outindent = 4;
  1242.     first = 1;
  1243.     while (fgets(buf, 256, inf)) {
  1244.     cp = buf + strlen(buf) - 2;
  1245.     if (cp >= buf) {
  1246.         bp = buf;
  1247.         indent = 0;
  1248.         while (isspace(*bp))
  1249.         if (*bp++ == '\t')
  1250.             indent += 8;
  1251.         else
  1252.             indent++;
  1253.         if (first) {
  1254.         first = 0;
  1255.         outindent = indent;
  1256.         }
  1257.         if (!(*cp == '{' ||
  1258.           *cp == ')' ||
  1259.           *cp == ';') ||
  1260.           (*cp == '/' && cp[-1] == '*')) {
  1261.         cp[1] = '\001';   /* eat the \n */
  1262.         } else {
  1263.         first = 1;
  1264.         }
  1265.         output(bp);
  1266.     }
  1267.     }
  1268.     fclose(outf);
  1269.     fclose(inf);
  1270. }
  1271.  
  1272.  
  1273.  
  1274.  
  1275.  
  1276. void outsection(size)
  1277. int size;
  1278. {
  1279.     if (size > sectionsize)
  1280.         sectionsize = size;
  1281. }
  1282.  
  1283.  
  1284.  
  1285. int isembedcomment(cmt)
  1286. Strlist *cmt;
  1287. {
  1288.     int len = strlen(embedcomment);
  1289.     return (cmt && len > 0 && !strncmp(cmt->s, embedcomment, len) &&
  1290.         (isspace(cmt->s[len]) ||
  1291.          (!cmt->s[len] && cmt->next &&
  1292.           (*cmt->next->s == '\002' || *cmt->next->s == '\003'))));
  1293. }
  1294.  
  1295.  
  1296. Strlist *outcomments(cmt)
  1297. Strlist *cmt;
  1298. {
  1299.     char *cp;
  1300.     int saveindent = outindent, savesingle = deltaindent, theindent;
  1301.     int saveeat = eatcomments;
  1302.     int i = 0;
  1303.  
  1304.     if (!cmt)
  1305.     return NULL;
  1306.     if (!commentvisible(cmt)) {
  1307.     setcommentkind(cmt, CMT_DONE);
  1308.     return cmt->next;
  1309.     }
  1310.     if (*cmt->s == '\001') {
  1311.     if (cmtdebug)
  1312.         output(format_sd("[]  [%s:%d]",
  1313.                  CMT_NAMES[getcommentkind(cmt)],
  1314.                  cmt->value & CMT_MASK));
  1315.     for (cp = cmt->s; *cp; cp++) {
  1316.         output("\n");
  1317.         if (cmtdebug && cp[1])
  1318.         output("[]");
  1319.     }
  1320.     setcommentkind(cmt, CMT_DONE);
  1321.     return cmt->next;
  1322.     }
  1323.     dontbreaklines++;
  1324.     if (isembedcomment(cmt)) {
  1325.     embeddedcode = 1;
  1326.     eatcomments = 0;
  1327.     if (!strcmp(cmt->s, embedcomment)) {
  1328.         cmt = cmt->next;
  1329.         theindent = 0;
  1330.         cp = cmt/*->next*/->s + 1;
  1331.         while (*cp++ == ' ')
  1332.         theindent++;
  1333.     } else {
  1334.         strcpy(cmt->s, cmt->s + strlen(embedcomment) + 1);
  1335.         moreindent(deltaindent);
  1336.         theindent = outindent;
  1337.         deltaindent = 0;
  1338.     }
  1339.     } else {
  1340.     moreindent(deltaindent);
  1341.     if (cmt->s[0] == '\004')
  1342.         outindent = 0;
  1343.     theindent = outindent;
  1344.     deltaindent = 0;
  1345.     output("/*");
  1346.     }
  1347.     cp = cmt->s;
  1348.     for (;;) {
  1349.     if (*cp == '\002')
  1350.         cp++;
  1351.     else if (*cp == '\003' || *cp == '\004') {
  1352.         outindent = 0;
  1353.         cp++;
  1354.     }
  1355.     if (embeddedcode) {
  1356.         for (i = 0; *cp == ' ' && i < theindent; i++)
  1357.         cp++;
  1358.         i = *cp;
  1359.         if (*cp == '#')
  1360.         outindent = 0;
  1361.     }
  1362.     output(cp);
  1363.     if (cmtdebug)
  1364.         output(format_sd(" [%s:%d] ",
  1365.                  CMT_NAMES[getcommentkind(cmt)],
  1366.                  cmt->value & CMT_MASK));
  1367.     setcommentkind(cmt, CMT_DONE);
  1368.     cmt = cmt->next;
  1369.     if (!cmt || !commentvisible(cmt))
  1370.         break;
  1371.     cp = cmt->s;
  1372.     if (*cp != '\002' && *cp != '\003')
  1373.         break;
  1374.     output("\n");
  1375.     if (!embeddedcode) {
  1376.         outindent = (*cp == '\002') ? theindent : 0;
  1377.         deltaindent = 0;
  1378.     }
  1379.     }
  1380.     if (embeddedcode) {
  1381.     embeddedcode = 0;
  1382.     if (i) {   /* eat final blank line */
  1383.         output("\n");
  1384.     }
  1385.     } else {
  1386.     output("*/\n");
  1387.     }
  1388.     outindent = saveindent;
  1389.     deltaindent = savesingle;
  1390.     dontbreaklines--;
  1391.     eatcomments = saveeat;
  1392.     return cmt;
  1393. }
  1394.  
  1395.  
  1396.  
  1397. void outcomment(cmt)
  1398. Strlist *cmt;
  1399. {
  1400.     Strlist *savenext;
  1401.     
  1402.     if (cmt) {
  1403.     savenext = cmt->next;
  1404.     cmt->next = NULL;
  1405.     outcomments(cmt);
  1406.     cmt->next = savenext;
  1407.     }
  1408. }
  1409.  
  1410.  
  1411.  
  1412. void outtrailcomment(cmt, serial, indent)
  1413. Strlist *cmt;
  1414. int serial, indent;
  1415. {
  1416.     int savedelta = deltaindent;
  1417.  
  1418. #if 0
  1419.     suppressnewline = 1;
  1420.     output("\n");
  1421.     suppressnewline = 0;
  1422. #endif
  1423.     cmt = findcomment(cmt, CMT_TRAIL, serial);
  1424.     if (commentvisible(cmt)) {
  1425.     out_spaces(indent, commentoverindent, commentlen(cmt), 0);
  1426.     outcomment(cmt);
  1427.     deltaindent = savedelta;
  1428.     } else
  1429.     output("\n");
  1430. }
  1431.  
  1432.  
  1433.  
  1434. void flushcomments(cmt, kind, serial)
  1435. Strlist **cmt;
  1436. int kind, serial;
  1437. {
  1438.     Strlist *cmt2, *cmt3;
  1439.     int saveindent, savesingle, saveeat;
  1440.  
  1441.     if (!cmt)
  1442.     cmt = &curcomments;
  1443.     cmt2 = extractcomment(cmt, kind, serial);
  1444.     saveindent = outindent;
  1445.     savesingle = deltaindent;
  1446.     moreindent(deltaindent);
  1447.     deltaindent = 0;
  1448.     saveeat = eatcomments;
  1449.     if (eatcomments == 2)
  1450.     eatcomments = 0;
  1451.     cmt3 = cmt2;
  1452.     while (cmt3)
  1453.     cmt3 = outcomments(cmt3);
  1454.     eatcomments = saveeat;
  1455.     outindent = saveindent;
  1456.     deltaindent = savesingle;
  1457.     strlist_empty(&cmt2);
  1458. }
  1459.  
  1460.  
  1461.  
  1462.  
  1463.  
  1464. char *rawCstring(fmt, s, len, special)
  1465. char *fmt;
  1466. register char *s;
  1467. int len, special;
  1468. {
  1469.     char buf[500];
  1470.     register char *cp;
  1471.     register unsigned char ch;
  1472.  
  1473.     cp = buf;
  1474.     while (--len >= 0) {
  1475.         ch = *((unsigned char *) s);
  1476.         s++;
  1477.         if (ch == 0 && (len == 0 || !isdigit(*s))) {
  1478.             *cp++ = '\\';
  1479.             *cp++ = '0';
  1480.         } else if (ch == '\n') {
  1481.             *cp++ = '\\';
  1482.             *cp++ = 'n';
  1483.         } else if (ch == '\b') {
  1484.             *cp++ = '\\';
  1485.             *cp++ = 'b';
  1486.         } else if (ch == '\t') {
  1487.             *cp++ = '\\';
  1488.             *cp++ = 't';
  1489.         } else if (ch == '\f') {
  1490.             *cp++ = '\\';
  1491.             *cp++ = 'f';
  1492. #if 0
  1493.         } else if (ch == '\r') {
  1494.             *cp++ = '\\';
  1495.             *cp++ = 'r';
  1496. #endif
  1497.         } else if (ch < ' ' || ch >= 127) {
  1498.             *cp++ = '\\';
  1499.             *cp++ = '0' + (ch>>6);
  1500.             *cp++ = '0' + ((ch>>3) & 7);
  1501.             *cp++ = '0' + (ch & 7);
  1502.         } else if (ch == special) {
  1503.             switch (ch) {
  1504.                 case '%':
  1505.                     *cp++ = ch;
  1506.                     *cp++ = ch;
  1507.                     break;
  1508.             }
  1509.         } else {
  1510.             if (ch == '"' || ch == '\\')
  1511.                 *cp++ = '\\';
  1512.             *cp++ = ch;
  1513.         }
  1514.     }
  1515.     *cp = 0;
  1516.     return format_s(fmt, buf);
  1517. }
  1518.  
  1519.  
  1520. char *makeCstring(s, len)
  1521. register char *s;
  1522. int len;
  1523. {
  1524.     return rawCstring("\"%s\"", s, len, 0);
  1525. }
  1526.  
  1527.  
  1528.  
  1529. char *makeCchar(ich)
  1530. int ich;
  1531. {
  1532.     char buf[500];
  1533.     register char *cp;
  1534.     register unsigned char ch = (ich & 0xff);
  1535.  
  1536.     if (ich < 0 || ich > 255 || (ich == 0 && !nullcharconst))
  1537.         return format_d("%d", ich);
  1538.     cp = buf;
  1539.     if (ch == 0) {
  1540.         *cp++ = '\\';
  1541.         *cp++ = '0';
  1542.     } else if (ch == '\n') {
  1543.         *cp++ = '\\';
  1544.         *cp++ = 'n';
  1545.     } else if (ch == '\b') {
  1546.         *cp++ = '\\';
  1547.         *cp++ = 'b';
  1548.     } else if (ch == '\t') {
  1549.         *cp++ = '\\';
  1550.         *cp++ = 't';
  1551.     } else if (ch == '\f') {
  1552.         *cp++ = '\\';
  1553.         *cp++ = 'f';
  1554. #if 0
  1555.     } else if (ch == '\r') {
  1556.         *cp++ = '\\';
  1557.         *cp++ = 'r';
  1558. #endif
  1559.     } else if (ch < ' ' || ch >= 127) {
  1560.         *cp++ = '\\';
  1561.         *cp++ = '0' + (ch>>6);
  1562.         *cp++ = '0' + ((ch>>3) & 7);
  1563.         *cp++ = '0' + (ch & 7);
  1564.     } else {
  1565.         if (ch == '\'' || ch == '\\')
  1566.             *cp++ = '\\';
  1567.         *cp++ = ch;
  1568.     }
  1569.     *cp = 0;
  1570.     return format_s("'%s'", buf);
  1571. }
  1572.  
  1573.  
  1574.  
  1575.  
  1576.  
  1577.  
  1578. /* End. */
  1579.  
  1580.  
  1581.