1 /****************************************************************
2 Copyright 1990, 1991, 1993, 1994, 2000 by AT&T, Lucent Technologies 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,
10 Lucent or Bellcore or any of their entities not be used in
11 advertising or publicity pertaining to distribution of the
12 software without specific, written prior permission.
13
14 AT&T, Lucent and Bellcore disclaim all warranties with regard to
15 this software, including all implied warranties of
16 merchantability and fitness. In no event shall AT&T, Lucent or
17 Bellcore be liable for any special, indirect or consequential
18 damages or any damages whatsoever resulting from loss of use,
19 data or profits, whether in an action of contract, negligence or
20 other tortious action, arising out of or in connection with the
21 use or performance of this software.
22 ****************************************************************/
23
24 #include "defs.h"
25 #include "names.h"
26 #include "output.h"
27 #ifndef KR_headers
28 #include "stdarg.h"
29 #endif
30
31 #define TOO_LONG_INDENT (2 * tab_size)
32 #define MAX_INDENT 44
33 #define MIN_INDENT 22
34 static int last_was_newline = 0;
35 int sharp_line = 0;
36 int indent = 0;
37 int in_comment = 0;
38 int in_define = 0;
39 extern int gflag1;
40 extern char filename[];
41
42 static void ind_printf Argdcl((int, FILE*, const char*, va_list));
43
44 static void
45 #ifdef KR_headers
write_indent(fp,use_indent,extra_indent,start,end)46 write_indent(fp, use_indent, extra_indent, start, end)
47 FILE *fp;
48 int use_indent;
49 int extra_indent;
50 char *start;
51 char *end;
52 #else
53 write_indent(FILE *fp, int use_indent, int extra_indent, char *start, char *end)
54 #endif
55 {
56 int ind, tab;
57
58 if (sharp_line) {
59 fprintf(fp, "#line %ld \"%s\"\n", lineno, filename);
60 sharp_line = 0;
61 }
62 if (in_define == 1) {
63 in_define = 2;
64 use_indent = 0;
65 }
66 if (last_was_newline && use_indent) {
67 if (*start == '\n') do {
68 putc('\n', fp);
69 if (++start > end)
70 return;
71 }
72 while(*start == '\n');
73
74 ind = indent <= MAX_INDENT
75 ? indent
76 : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
77
78 tab = ind + extra_indent;
79
80 while (tab > 7) {
81 putc ('\t', fp);
82 tab -= 8;
83 } /* while */
84
85 while (tab-- > 0)
86 putc (' ', fp);
87 } /* if last_was_newline */
88
89 while (start <= end)
90 putc (*start++, fp);
91 } /* write_indent */
92
93 #ifdef KR_headers
94 /*VARARGS2*/
95 void
margin_printf(fp,a,b,c,d,e,f,g)96 margin_printf (fp, a, b, c, d, e, f, g)
97 FILE *fp;
98 char *a;
99 long b, c, d, e, f, g;
100 {
101 ind_printf (0, fp, a, b, c, d, e, f, g);
102 } /* margin_printf */
103
104 /*VARARGS2*/
105 void
nice_printf(fp,a,b,c,d,e,f,g)106 nice_printf (fp, a, b, c, d, e, f, g)
107 FILE *fp;
108 char *a;
109 long b, c, d, e, f, g;
110 {
111 ind_printf (1, fp, a, b, c, d, e, f, g);
112 } /* nice_printf */
113 #define SPRINTF(x,a,b,c,d,e,f,g) sprintf(x,a,b,c,d,e,f,g)
114
115 #else /* if (!defined(KR_HEADERS)) */
116
117 #define SPRINTF(x,a,b,c,d,e,f,g) vsprintf(x,a,ap)
118
119 void
margin_printf(FILE * fp,const char * fmt,...)120 margin_printf(FILE *fp, const char *fmt, ...)
121 {
122 va_list ap;
123 va_start(ap,fmt);
124 ind_printf(0, fp, fmt, ap);
125 va_end(ap);
126 }
127
128 void
nice_printf(FILE * fp,const char * fmt,...)129 nice_printf(FILE *fp, const char *fmt, ...)
130 {
131 va_list ap;
132 va_start(ap,fmt);
133 ind_printf(1, fp, fmt, ap);
134 va_end(ap);
135 }
136 #endif
137
138 #define max_line_len c_output_line_length
139 /* 74Number of characters allowed on an output
140 line. This assumes newlines are handled
141 nicely, i.e. a newline after a full text
142 line on a terminal is ignored */
143
144 /* output_buf holds the text of the next line to be printed. It gets
145 flushed when a newline is printed. next_slot points to the next
146 available location in the output buffer, i.e. where the next call to
147 nice_printf will have its output stored */
148
149 static char *output_buf;
150 static char *next_slot;
151 static char *string_start;
152
153 static char *word_start = NULL;
154 static int cursor_pos = 0;
155 static int In_string = 0;
156
157 void
np_init(Void)158 np_init(Void)
159 {
160 next_slot = output_buf = Alloc(MAX_OUTPUT_SIZE);
161 memset(output_buf, 0, MAX_OUTPUT_SIZE);
162 }
163
164 static char *
165 #ifdef KR_headers
adjust_pointer_in_string(pointer)166 adjust_pointer_in_string(pointer)
167 register char *pointer;
168 #else
169 adjust_pointer_in_string(register char *pointer)
170 #endif
171 {
172 register char *s, *s1, *se, *s0;
173
174 /* arrange not to break \002 */
175 s1 = string_start ? string_start : output_buf;
176 for(s = s1; s < pointer; s++) {
177 s0 = s1;
178 s1 = s;
179 if (*s == '\\') {
180 se = s++ + 4;
181 if (se > pointer)
182 break;
183 if (*s < '0' || *s > '7')
184 continue;
185 while(++s < se)
186 if (*s < '0' || *s > '7')
187 break;
188 --s;
189 }
190 }
191 return s0 - 1;
192 }
193
194 /* ANSI says strcpy's behavior is undefined for overlapping args,
195 * so we roll our own fwd_strcpy: */
196
197 static void
198 #ifdef KR_headers
fwd_strcpy(t,s)199 fwd_strcpy(t, s)
200 register char *t;
201 register char *s;
202 #else
203 fwd_strcpy(register char *t, register char *s)
204 #endif
205 { while(*t++ = *s++); }
206
207 /* isident -- true iff character could belong to a unit. C allows
208 letters, numbers and underscores in identifiers. This also doubles as
209 a check for numeric constants, since we include the decimal point and
210 minus sign. The minus has to be here, since the constant "10e-2"
211 cannot be broken up. The '.' also prevents structure references from
212 being broken, which is a quite acceptable side effect */
213
214 #define isident(x) (Tr[x] & 1)
215 #define isntident(x) (!Tr[x])
216
217 static void
218 #ifdef KR_headers
ind_printf(use_indent,fp,a,b,c,d,e,f,g)219 ind_printf (use_indent, fp, a, b, c, d, e, f, g)
220 int use_indent;
221 FILE *fp;
222 char *a;
223 long b, c, d, e, f, g;
224 #else
225 ind_printf (int use_indent, FILE *fp, const char *a, va_list ap)
226 #endif
227 {
228 extern int max_line_len;
229 extern FILEP c_file;
230 extern char tr_tab[]; /* in output.c */
231 register char *Tr = tr_tab;
232 int ch, cmax, inc, ind;
233 static int extra_indent, last_indent, set_cursor = 1;
234
235 cursor_pos += indent - last_indent;
236 last_indent = indent;
237 SPRINTF (next_slot, a, b, c, d, e, f, g);
238
239 if (fp != c_file) {
240 fprintf (fp,"%s", next_slot);
241 return;
242 } /* if fp != c_file */
243
244 do {
245 char *pointer;
246
247 /* The for loop will parse one output line */
248
249 if (set_cursor) {
250 ind = indent <= MAX_INDENT
251 ? indent
252 : MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
253 cursor_pos = extra_indent;
254 if (use_indent)
255 cursor_pos += ind;
256 set_cursor = 0;
257 }
258 if (in_comment) {
259 cmax = max_line_len + 32; /* let comments be wider */
260 for (pointer = next_slot; *pointer && *pointer != '\n' &&
261 cursor_pos <= cmax; pointer++)
262 cursor_pos++;
263 }
264 else
265 for (pointer = next_slot; *pointer && *pointer != '\n' &&
266 cursor_pos <= max_line_len; pointer++) {
267
268 /* Update state variables here */
269
270 if (In_string) {
271 switch(*pointer) {
272 case '\\':
273 if (++cursor_pos > max_line_len) {
274 cursor_pos -= 2;
275 --pointer;
276 goto overflow;
277 }
278 ++pointer;
279 break;
280 case '"':
281 In_string = 0;
282 word_start = 0;
283 }
284 }
285 else switch (*pointer) {
286 case '"':
287 if (cursor_pos + 5 > max_line_len) {
288 word_start = 0;
289 --pointer;
290 goto overflow;
291 }
292 In_string = 1;
293 string_start = word_start = pointer;
294 break;
295 case '\'':
296 if (pointer[1] == '\\')
297 if ((ch = pointer[2]) >= '0' && ch <= '7')
298 for(inc = 3; pointer[inc] != '\''
299 && ++inc < 5;);
300 else
301 inc = 3;
302 else
303 inc = 2;
304 /*debug*/ if (pointer[inc] != '\'')
305 /*debug*/ fatalstr("Bad character constant %.10s",
306 pointer);
307 if ((cursor_pos += inc) > max_line_len) {
308 cursor_pos -= inc;
309 word_start = 0;
310 --pointer;
311 goto overflow;
312 }
313 word_start = pointer;
314 pointer += inc;
315 break;
316 case '\t':
317 cursor_pos = 8 * ((cursor_pos + 8) / 8) - 1;
318 break;
319 default: {
320
321 /* HACK Assumes that all characters in an atomic C token will be written
322 at the same time. Must check for tokens first, since '-' is considered
323 part of an identifier; checking isident first would mean breaking up "->" */
324
325 if (word_start) {
326 if (isntident(*(unsigned char *)pointer))
327 word_start = NULL;
328 }
329 else if (isident(*(unsigned char *)pointer))
330 word_start = pointer;
331 break;
332 } /* default */
333 } /* switch */
334 cursor_pos++;
335 } /* for pointer = next_slot */
336 overflow:
337 if (*pointer == '\0') {
338
339 /* The output line is not complete, so break out and don't output
340 anything. The current line fragment will be stored in the buffer */
341
342 next_slot = pointer;
343 break;
344 } else {
345 char last_char;
346 int in_string0 = In_string;
347
348 /* If the line was too long, move pointer back to the character before
349 the current word. This allows line breaking on word boundaries. Make
350 sure that 80 character comment lines get broken up somehow. We assume
351 that any non-string 80 character identifier must be in a comment.
352 */
353
354 if (*pointer == '\n')
355 in_define = 0;
356 else if (word_start && word_start > output_buf)
357 if (In_string)
358 if (string_start && pointer - string_start < 5)
359 pointer = string_start - 1;
360 else {
361 pointer = adjust_pointer_in_string(pointer);
362 string_start = 0;
363 }
364 else if (word_start == string_start
365 && pointer - string_start >= 5) {
366 pointer = adjust_pointer_in_string(next_slot);
367 In_string = 1;
368 string_start = 0;
369 }
370 else
371 pointer = word_start - 1;
372 else if (cursor_pos > max_line_len) {
373 #ifndef ANSI_Libraries
374 extern char *strchr();
375 #endif
376 if (In_string) {
377 pointer = adjust_pointer_in_string(pointer);
378 if (string_start && pointer > string_start)
379 string_start = 0;
380 }
381 else if (strchr("&*+-/<=>|", *pointer)
382 && strchr("!%&*+-/<=>^|", pointer[-1])) {
383 pointer -= 2;
384 if (strchr("<>", *pointer)) /* <<=, >>= */
385 pointer--;
386 }
387 else {
388 if (word_start)
389 while(isident(*(unsigned char *)pointer))
390 pointer++;
391 pointer--;
392 }
393 }
394 last_char = *pointer;
395 write_indent(fp, use_indent, extra_indent, output_buf, pointer);
396 next_slot = output_buf;
397 if (In_string && !string_start && Ansi == 1 && last_char != '\n')
398 *next_slot++ = '"';
399 fwd_strcpy(next_slot, pointer + 1);
400
401 /* insert a line break */
402
403 if (last_char == '\n') {
404 if (In_string)
405 last_was_newline = 0;
406 else {
407 last_was_newline = 1;
408 extra_indent = 0;
409 sharp_line = gflag1;
410 }
411 }
412 else {
413 extra_indent = TOO_LONG_INDENT;
414 if (In_string && !string_start) {
415 if (Ansi == 1) {
416 fprintf(fp, gflag1 ? "\"\\\n" : "\"\n");
417 use_indent = 1;
418 last_was_newline = 1;
419 }
420 else {
421 fprintf(fp, "\\\n");
422 last_was_newline = 0;
423 }
424 In_string = in_string0;
425 }
426 else {
427 if (in_define/* | gflag1*/)
428 putc('\\', fp);
429 putc ('\n', fp);
430 last_was_newline = 1;
431 }
432 } /* if *pointer != '\n' */
433
434 if (In_string && Ansi != 1 && !string_start)
435 cursor_pos = 0;
436 else
437 set_cursor = 1;
438
439 string_start = word_start = NULL;
440
441 } /* else */
442
443 } while (*next_slot);
444
445 } /* ind_printf */
446