Pristine Ack-5.5
[Ack-5.5.git] / lang / fortran / comp / niceprintf.c
1 /****************************************************************
2 Copyright 1990, 1991 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;
102 static char *next_slot;
103 static char *string_start;
104
105 static char *word_start = NULL;
106 static int cursor_pos = 0;
107 static int In_string = 0;
108
109  void
110 np_init()
111 {
112         next_slot = output_buf = Alloc(MAX_OUTPUT_SIZE);
113         memset(output_buf, 0, MAX_OUTPUT_SIZE);
114         }
115
116  static char *
117 adjust_pointer_in_string(pointer)
118  register char *pointer;
119 {
120         register char *s, *s1, *se, *s0;
121
122         /* arrange not to break \002 */
123         s1 = string_start ? string_start : output_buf;
124         for(s = s1; s < pointer; s++) {
125                 s0 = s1;
126                 s1 = s;
127                 if (*s == '\\') {
128                         se = s++ + 4;
129                         if (se > pointer)
130                                 break;
131                         if (*s < '0' || *s > '7')
132                                 continue;
133                         while(++s < se)
134                                 if (*s < '0' || *s > '7')
135                                         break;
136                         --s;
137                         }
138                 }
139         return s0 - 1;
140         }
141
142 /* ANSI says strcpy's behavior is undefined for overlapping args,
143  * so we roll our own fwd_strcpy: */
144
145  static void
146 fwd_strcpy(t, s)
147  register char *t, *s;
148 { while(*t++ = *s++); }
149
150 /* isident -- true iff character could belong to a unit.  C allows
151    letters, numbers and underscores in identifiers.  This also doubles as
152    a check for numeric constants, since we include the decimal point and
153    minus sign.  The minus has to be here, since the constant "10e-2"
154    cannot be broken up.  The '.' also prevents structure references from
155    being broken, which is a quite acceptable side effect */
156
157 #define isident(x) (Tr[x] & 1)
158 #define isntident(x) (!Tr[x])
159
160 int ind_printf (use_indent, fp, a, b, c, d, e, f, g)
161 int use_indent;
162 FILE *fp;
163 char *a;
164 long b, c, d, e, f, g;
165 {
166     extern int max_line_len;
167     extern FILEP c_file;
168     extern char tr_tab[];       /* in output.c */
169     register char *Tr = tr_tab;
170     int ch, inc, ind;
171     static int extra_indent, last_indent, set_cursor = 1;
172
173     cursor_pos += indent - last_indent;
174     last_indent = indent;
175     sprintf (next_slot, a, b, c, d, e, f, g);
176
177     if (fp != c_file) {
178         fprintf (fp,"%s", next_slot);
179         return 1;
180     } /* if fp != c_file */
181
182     do {
183         char *pointer;
184
185 /* The   for   loop will parse one output line */
186
187         if (set_cursor) {
188                 ind = indent <= MAX_INDENT
189                         ? indent
190                         : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
191                 cursor_pos = ind + extra_indent;
192                 set_cursor = 0;
193                 }
194         if (in_comment)
195                 for (pointer = next_slot; *pointer && *pointer != '\n' &&
196                                 cursor_pos <= max_line_len; pointer++)
197                         cursor_pos++;
198         else
199           for (pointer = next_slot; *pointer && *pointer != '\n' &&
200                 cursor_pos <= max_line_len; pointer++) {
201
202             /* Update state variables here */
203
204             if (In_string) {
205                 switch(*pointer) {
206                         case '\\':
207                                 if (++cursor_pos > max_line_len) {
208                                         cursor_pos -= 2;
209                                         --pointer;
210                                         goto overflow;
211                                         }
212                                 ++pointer;
213                                 break;
214                         case '"':
215                                 In_string = 0;
216                                 word_start = 0;
217                         }
218                 }
219             else switch (*pointer) {
220                 case '"':
221                         if (cursor_pos + 5 > max_line_len) {
222                                 word_start = 0;
223                                 --pointer;
224                                 goto overflow;
225                                 }
226                         In_string = 1;
227                         string_start = word_start = pointer;
228                         break;
229                 case '\'':
230                         if (pointer[1] == '\\')
231                                 if ((ch = pointer[2]) >= '0' && ch <= '7')
232                                         for(inc = 3; pointer[inc] != '\''
233                                                 && ++inc < 5;);
234                                 else
235                                         inc = 3;
236                         else
237                                 inc = 2;
238                         /*debug*/ if (pointer[inc] != '\'')
239                         /*debug*/  fatalstr("Bad character constant %.10s",
240                                         pointer);
241                         if ((cursor_pos += inc) > max_line_len) {
242                                 cursor_pos -= inc;
243                                 word_start = 0;
244                                 --pointer;
245                                 goto overflow;
246                                 }
247                         word_start = pointer;
248                         pointer += inc;
249                         break;
250                 case '\t':
251                     cursor_pos = 8 * ((cursor_pos + 8) / 8) - 1;
252                     break;
253                 default: {
254
255 /* HACK  Assumes that all characters in an atomic C token will be written
256    at the same time.  Must check for tokens first, since '-' is considered
257    part of an identifier; checking isident first would mean breaking up "->" */
258
259                     if (!word_start && isident(*(unsigned char *)pointer))
260                         word_start = pointer;
261                     else if (word_start && isntident(*(unsigned char *)pointer))
262                         word_start = NULL;
263                     break;
264                 } /* default */
265             } /* switch */
266             cursor_pos++;
267         } /* for pointer = next_slot */
268  overflow:
269         if (*pointer == '\0') {
270
271 /* The output line is not complete, so break out and don't output
272    anything.  The current line fragment will be stored in the buffer */
273
274             next_slot = pointer;
275             break;
276         } else {
277             char last_char;
278             int in_string0 = In_string;
279
280 /* If the line was too long, move   pointer   back to the character before
281    the current word.  This allows line breaking on word boundaries.  Make
282    sure that 80 character comment lines get broken up somehow.  We assume
283    that any non-string 80 character identifier must be in a comment.
284 */
285
286             if (word_start && *pointer != '\n' && word_start > output_buf)
287                 if (In_string)
288                         if (string_start && pointer - string_start < 5)
289                                 pointer = string_start - 1;
290                         else {
291                                 pointer = adjust_pointer_in_string(pointer);
292                                 string_start = 0;
293                                 }
294                 else if (word_start == string_start
295                                 && pointer - string_start >= 5) {
296                         pointer = adjust_pointer_in_string(next_slot);
297                         In_string = 1;
298                         string_start = 0;
299                         }
300                 else
301                         pointer = word_start - 1;
302             else if (cursor_pos > max_line_len) {
303                 extern char *strchr();
304                 if (In_string) {
305                         pointer = adjust_pointer_in_string(pointer);
306                         if (string_start && pointer > string_start)
307                                 string_start = 0;
308                         }
309                 else if (strchr("&*+-/<=>|", *pointer)
310                         && strchr("!%&*+-/<=>^|", pointer[-1])) {
311                         pointer -= 2;
312                         if (strchr("<>", *pointer)) /* <<=, >>= */
313                                 pointer--;
314                         }
315                 else
316                         pointer--;
317                 }
318             last_char = *pointer;
319             write_indent(fp, use_indent, extra_indent, output_buf, pointer);
320             next_slot = output_buf;
321             if (In_string && !string_start && Ansi == 1 && last_char != '\n')
322                 *next_slot++ = '"';
323             fwd_strcpy(next_slot, pointer + 1);
324
325 /* insert a line break */
326
327             if (last_char == '\n') {
328                 if (In_string)
329                         last_was_newline = 0;
330                 else {
331                         last_was_newline = 1;
332                         extra_indent = 0;
333                         }
334                 }
335             else {
336                 extra_indent = TOO_LONG_INDENT;
337                 if (In_string && !string_start) {
338                         if (Ansi == 1) {
339                                 fprintf(fp, "\"\n");
340                                 use_indent = 1;
341                                 last_was_newline = 1;
342                                 }
343                         else {
344                                 fprintf(fp, "\\\n");
345                                 last_was_newline = 0;
346                                 }
347                         In_string = in_string0;
348                         }
349                 else {
350                         putc ('\n', fp);
351                         last_was_newline = 1;
352                         }
353             } /* if *pointer != '\n' */
354
355             if (In_string && Ansi != 1 && !string_start)
356                 cursor_pos = 0;
357             else
358                 set_cursor = 1;
359
360             string_start = word_start = NULL;
361
362         } /* else */
363
364     } while (*next_slot);
365
366     return 0;
367 } /* ind_printf */