Added upstream from http://ftp.icm.edu.pl/pub/loglan/
[loglan.git] / sources / f2c / nicepr.c
1 /****************************************************************
2 Copyright 1990 by AT&T Bell Laboratories and Bellcore.
3
4 Permission to use, copy, modify, and distribute this software
5 and its documentation for any purpose and without fee is hereby
6 granted, provided that the above copyright notice appear in all
7 copies and that both that the copyright notice and this
8 permission notice and warranty disclaimer appear in supporting
9 documentation, and that the names of AT&T Bell Laboratories or
10 Bellcore or any of their entities not be used in advertising or
11 publicity pertaining to distribution of the software without
12 specific, written prior permission.
13
14 AT&T and Bellcore disclaim all warranties with regard to this
15 software, including all implied warranties of merchantability
16 and fitness.  In no event shall AT&T or Bellcore be liable for
17 any special, indirect or consequential damages or any damages
18 whatsoever resulting from loss of use, data or profits, whether
19 in an action of contract, negligence or other tortious action,
20 arising out of or in connection with the use or performance of
21 this software.
22 ****************************************************************/
23
24 #include "defs.h"
25 #include "names.h"
26 #include "output.h"
27
28 #define TOO_LONG_INDENT (2 * tab_size)
29 #define MAX_INDENT 44
30 #define MIN_INDENT 22
31 static int last_was_newline = 0;
32 int indent = 0;
33 int in_comment = 0;
34
35  static int
36 write_indent(fp, use_indent, extra_indent, start, end)
37  FILE *fp;
38  int use_indent, extra_indent;
39  char *start, *end;
40 {
41     int ind, tab;
42
43     if (last_was_newline && use_indent) {
44         if (*start == '\n') do {
45                 putc('\n', fp);
46                 if (++start > end)
47                         return;
48                 }
49                 while(*start == '\n');
50
51         ind = indent <= MAX_INDENT
52                 ? indent
53                 : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
54
55         tab = ind + extra_indent;
56
57         while (tab > 7) {
58             putc ('\t', fp);
59             tab -= 8;
60         } /* while */
61
62         while (tab-- > 0)
63             putc (' ', fp);
64     } /* if last_was_newline */
65
66     while (start <= end)
67         putc (*start++, fp);
68 } /* write_indent */
69
70
71 /*VARARGS2*/
72 int margin_printf (fp, a, b, c, d, e, f, g)
73 FILE *fp;
74 char *a;
75 long b, c, d, e, f, g;
76 {
77     ind_printf (0, fp, a, b, c, d, e, f, g);
78 } /* margin_printf */
79
80 /*VARARGS2*/
81 int nice_printf (fp, a, b, c, d, e, f, g)
82 FILE *fp;
83 char *a;
84 long b, c, d, e, f, g;
85 {
86     ind_printf (1, fp, a, b, c, d, e, f, g);
87 } /* nice_printf */
88
89
90 #define  max_line_len c_output_line_length
91                 /* 74Number of characters allowed on an output
92                                    line.  This assumes newlines are handled
93                                    nicely, i.e. a newline after a full text
94                                    line on a terminal is ignored */
95
96 /* output_buf   holds the text of the next line to be printed.  It gets
97    flushed when a newline is printed.   next_slot   points to the next
98    available location in the output buffer, i.e. where the next call to
99    nice_printf will have its output stored */
100
101 static char output_buf[MAX_OUTPUT_SIZE] = "";
102 static char *next_slot = output_buf;
103 static char *string_start;
104
105 static char *word_start = NULL;
106 static int in_char = 0;
107 static int cursor_pos = 0;
108
109  static char *
110 adjust_pointer_in_string(pointer)
111  register char *pointer;
112 {
113         register char *s, *s1, *se, *s0;
114
115         /* arrange not to break \002 */
116         s1 = string_start ? string_start : output_buf;
117         for(s = s1; s < pointer; s++) {
118                 s0 = s1;
119                 s1 = s;
120                 if (*s == '\\') {
121                         se = s++ + 4;
122                         if (se > pointer)
123                                 break;
124                         if (*s < '0' || *s > '7')
125                                 continue;
126                         while(++s < se)
127                                 if (*s < '0' || *s > '7')
128                                         break;
129                         --s;
130                         }
131                 }
132         return s0 - 1;
133         }
134
135 /* isident -- true iff character could belong to a unit.  C allows
136    letters, numbers and underscores in identifiers.  This also doubles as
137    a check for numeric constants, since we include the decimal point and
138    minus sign.  The minus has to be here, since the constant "10e-2"
139    cannot be broken up.  The '.' also prevents structure references from
140    being broken, which is a quite acceptable side effect */
141
142 #define isident(x) (Tr[x] & 1)
143 #define isntident(x) (!Tr[x])
144
145 int ind_printf (use_indent, fp, a, b, c, d, e, f, g)
146 int use_indent;
147 FILE *fp;
148 char *a;
149 long b, c, d, e, f, g;
150 {
151     extern int max_line_len;
152     extern FILEP c_file;
153     extern char tr_tab[];       /* in output.c */
154     register char *Tr = tr_tab;
155     int ind;
156     static int extra_indent, last_indent, set_cursor = 1;
157
158     cursor_pos += indent - last_indent;
159     last_indent = indent;
160     sprintf (next_slot, a, b, c, d, e, f, g);
161
162     if (fp != c_file) {
163         fprintf (fp,"%s", next_slot);
164         return 1;
165     } /* if fp != c_file */
166
167     do {
168         char *pointer;
169
170 /* The   for   loop will parse one output line */
171
172         if (set_cursor) {
173                 ind = indent <= MAX_INDENT
174                         ? indent
175                         : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
176                 cursor_pos = ind + extra_indent;
177                 set_cursor = 0;
178                 }
179         if (in_string)
180                 for (pointer = next_slot; *pointer && *pointer != '\n' &&
181                                 cursor_pos <= max_line_len; pointer++)
182                         cursor_pos++;
183         else
184           for (pointer = next_slot; *pointer && *pointer != '\n' &&
185                 cursor_pos <= max_line_len; pointer++) {
186
187             /* Update state variables here */
188
189             switch (*pointer) {
190                 case '"':
191                     if (!in_char && !in_comment)
192                         /* Ignore double quotes in char constants */
193                         string_start = word_start = pointer;
194                     break;
195                 case '\'':
196                     if (!in_comment) {
197                         word_start = in_char ? NULL : pointer;
198                         in_char = !in_char;
199                         }
200                     break;
201                 case '\\':
202                     if (in_char) {
203                         pointer++;
204                         cursor_pos++;
205                     }
206                     break;
207                 case '\t':
208                     cursor_pos = 8 * ((cursor_pos + 8) / 8) - 1;
209                     break;
210                 default: {
211
212                     if (in_char)
213                         break;
214
215 /* HACK  Assumes that all characters in an atomic C token will be written
216    at the same time.  Must check for tokens first, since '-' is considered
217    part of an identifier; checking isident first would mean breaking up "->" */
218
219                     if (!word_start && isident(*(unsigned char *)pointer))
220                         word_start = pointer;
221                     else if (word_start && isntident(*(unsigned char *)pointer))
222                         word_start = NULL;
223                     break;
224                 } /* default */
225             } /* switch */
226             cursor_pos++;
227         } /* for pointer = next_slot */
228         if (*pointer == '\0') {
229
230 /* The output line is not complete, so break out and don't output
231    anything.  The current line fragment will be stored in the buffer */
232
233             next_slot = pointer;
234             break;
235         } else {
236             char *safe_strncpy ();
237             char last_char;
238             int in_string0 = in_string;
239
240 /* If the line was too long, move   pointer   back to the character before
241    the current word.  This allows line breaking on word boundaries.  Make
242    sure that 80 character comment lines get broken up somehow.  We assume
243    that any non-string 80 character identifier must be in a comment.
244 */
245
246             if (word_start && *pointer != '\n' && word_start > output_buf)
247                 if (in_string)
248                         if (string_start && pointer - string_start < 5)
249                                 pointer = string_start - 1;
250                         else {
251                                 pointer = adjust_pointer_in_string(pointer);
252                                 string_start = 0;
253                                 }
254                 else if (word_start == string_start) {
255                         pointer = adjust_pointer_in_string(next_slot);
256                         in_string = 1;
257                         string_start = 0;
258                         }
259                 else
260                         pointer = word_start - 1;
261             else if (cursor_pos > max_line_len) {
262                 extern char *strchr();
263                 if (in_string)
264                         pointer = adjust_pointer_in_string(pointer);
265                 else if (strchr("&*+-/<=>|", *pointer)
266                         && strchr("!%&*+-/<=>^|", pointer[-1])) {
267                         pointer -= 2;
268                         if (strchr("<>", *pointer)) /* <<=, >>= */
269                                 pointer--;
270                         }
271                 else
272                         pointer--;
273                 }
274             last_char = *pointer;
275             write_indent(fp, use_indent, extra_indent, output_buf, pointer);
276             next_slot = output_buf;
277             if (in_string && !string_start && Ansi == 1 && last_char != '\n')
278                 *next_slot++ = '"';
279             (void) safe_strncpy (next_slot, pointer + 1, sizeof(output_buf)-1);
280             in_char = 0;
281
282 /* insert a line break */
283
284             if (last_char == '\n') {
285                 if (in_string)
286                         last_was_newline = 0;
287                 else {
288                         last_was_newline = 1;
289                         extra_indent = 0;
290                         }
291                 }
292             else {
293                 extra_indent = TOO_LONG_INDENT;
294                 if (in_string && !string_start) {
295                         if (Ansi == 1) {
296                                 fprintf(fp, "\"\n");
297                                 use_indent = 1;
298                                 last_was_newline = 1;
299                                 }
300                         else {
301                                 fprintf(fp, "\\\n");
302                                 last_was_newline = 0;
303                                 }
304                         in_string = in_string0;
305                         }
306                 else {
307                         putc ('\n', fp);
308                         last_was_newline = 1;
309                         }
310             } /* if *pointer != '\n' */
311
312             if (in_string && Ansi != 1 && !string_start)
313                 cursor_pos = 0;
314             else
315                 set_cursor = 1;
316
317             string_start = word_start = NULL;
318
319         } /* else */
320
321     } while (*next_slot);
322
323     return 0;
324 } /* ind_printf */