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