1/*
2 * Copyright (c) 1985 Sun Microsystems, Inc.
3 * Copyright (c) 1980, 1993
4 *	The Regents of the University of California.  All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#if 0
37#ifndef lint
38static char sccsid[] = "@(#)io.c	8.1 (Berkeley) 6/6/93";
39#endif /* not lint */
40#endif
41
42#include <sys/cdefs.h>
43__FBSDID("$FreeBSD$");
44
45#include <ctype.h>
46#include <err.h>
47#include <stdio.h>
48#include <stdlib.h>
49#include <string.h>
50#include "indent_globs.h"
51#include "indent.h"
52
53int         comment_open;
54static int  paren_target;
55static int pad_output(int current, int target);
56
57void
58dump_line(void)
59{				/* dump_line is the routine that actually
60				 * effects the printing of the new source. It
61				 * prints the label section, followed by the
62				 * code section with the appropriate nesting
63				 * level, followed by any comments */
64    int cur_col,
65                target_col = 1;
66    static int  not_first_line;
67
68    if (ps.procname[0]) {
69	if (troff) {
70	    if (comment_open) {
71		comment_open = 0;
72		fprintf(output, ".*/\n");
73	    }
74	    fprintf(output, ".Pr \"%s\"\n", ps.procname);
75	}
76	ps.ind_level = 0;
77	ps.procname[0] = 0;
78    }
79    if (s_code == e_code && s_lab == e_lab && s_com == e_com) {
80	if (suppress_blanklines > 0)
81	    suppress_blanklines--;
82	else {
83	    ps.bl_line = true;
84	    n_real_blanklines++;
85	}
86    }
87    else if (!inhibit_formatting) {
88	suppress_blanklines = 0;
89	ps.bl_line = false;
90	if (prefix_blankline_requested && not_first_line) {
91	    if (swallow_optional_blanklines) {
92		if (n_real_blanklines == 1)
93		    n_real_blanklines = 0;
94	    }
95	    else {
96		if (n_real_blanklines == 0)
97		    n_real_blanklines = 1;
98	    }
99	}
100	while (--n_real_blanklines >= 0)
101	    putc('\n', output);
102	n_real_blanklines = 0;
103	if (ps.ind_level == 0)
104	    ps.ind_stmt = 0;	/* this is a class A kludge. dont do
105				 * additional statement indentation if we are
106				 * at bracket level 0 */
107
108	if (e_lab != s_lab || e_code != s_code)
109	    ++code_lines;	/* keep count of lines with code */
110
111
112	if (e_lab != s_lab) {	/* print lab, if any */
113	    if (comment_open) {
114		comment_open = 0;
115		fprintf(output, ".*/\n");
116	    }
117	    while (e_lab > s_lab && (e_lab[-1] == ' ' || e_lab[-1] == '\t'))
118		e_lab--;
119	    cur_col = pad_output(1, compute_label_target());
120	    if (s_lab[0] == '#' && (strncmp(s_lab, "#else", 5) == 0
121				    || strncmp(s_lab, "#endif", 6) == 0)) {
122		char *s = s_lab;
123		if (e_lab[-1] == '\n') e_lab--;
124		do putc(*s++, output);
125		while (s < e_lab && 'a' <= *s && *s<='z');
126		while ((*s == ' ' || *s == '\t') && s < e_lab)
127		    s++;
128		if (s < e_lab)
129		    fprintf(output, s[0]=='/' && s[1]=='*' ? "\t%.*s" : "\t/* %.*s */",
130			    (int)(e_lab - s), s);
131	    }
132	    else fprintf(output, "%.*s", (int)(e_lab - s_lab), s_lab);
133	    cur_col = count_spaces(cur_col, s_lab);
134	}
135	else
136	    cur_col = 1;	/* there is no label section */
137
138	ps.pcase = false;
139
140	if (s_code != e_code) {	/* print code section, if any */
141	    char *p;
142
143	    if (comment_open) {
144		comment_open = 0;
145		fprintf(output, ".*/\n");
146	    }
147	    target_col = compute_code_target();
148	    {
149		int i;
150
151		for (i = 0; i < ps.p_l_follow; i++)
152		    if (ps.paren_indents[i] >= 0)
153			ps.paren_indents[i] = -(ps.paren_indents[i] + target_col);
154	    }
155	    cur_col = pad_output(cur_col, target_col);
156	    for (p = s_code; p < e_code; p++)
157		if (*p == (char) 0200)
158		    fprintf(output, "%d", target_col * 7);
159		else
160		    putc(*p, output);
161	    cur_col = count_spaces(cur_col, s_code);
162	}
163	if (s_com != e_com) {
164	    if (troff) {
165		int         all_here = 0;
166		char *p;
167
168		if (e_com[-1] == '/' && e_com[-2] == '*')
169		    e_com -= 2, all_here++;
170		while (e_com > s_com && e_com[-1] == ' ')
171		    e_com--;
172		*e_com = 0;
173		p = s_com;
174		while (*p == ' ')
175		    p++;
176		if (p[0] == '/' && p[1] == '*')
177		    p += 2, all_here++;
178		else if (p[0] == '*')
179		    p += p[1] == '/' ? 2 : 1;
180		while (*p == ' ')
181		    p++;
182		if (*p == 0)
183		    goto inhibit_newline;
184		if (comment_open < 2 && ps.box_com) {
185		    comment_open = 0;
186		    fprintf(output, ".*/\n");
187		}
188		if (comment_open == 0) {
189		    if ('a' <= *p && *p <= 'z')
190			*p = *p + 'A' - 'a';
191		    if (e_com - p < 50 && all_here == 2) {
192			char *follow = p;
193			fprintf(output, "\n.nr C! \\w\1");
194			while (follow < e_com) {
195			    switch (*follow) {
196			    case '\n':
197				putc(' ', output);
198			    case 1:
199				break;
200			    case '\\':
201				putc('\\', output);
202			    default:
203				putc(*follow, output);
204			    }
205			    follow++;
206			}
207			putc(1, output);
208		    }
209		    fprintf(output, "\n./* %dp %d %dp\n",
210			    ps.com_col * 7,
211			    (s_code != e_code || s_lab != e_lab) - ps.box_com,
212			    target_col * 7);
213		}
214		comment_open = 1 + ps.box_com;
215		while (*p) {
216		    if (*p == BACKSLASH)
217			putc(BACKSLASH, output);
218		    putc(*p++, output);
219		}
220	    }
221	    else {		/* print comment, if any */
222		int target = ps.com_col;
223		char *com_st = s_com;
224
225		target += ps.comment_delta;
226		while (*com_st == '\t')
227		    com_st++, target += 8;	/* ? */
228		while (target <= 0)
229		    if (*com_st == ' ')
230			target++, com_st++;
231		    else if (*com_st == '\t')
232			target = ((target - 1) & ~7) + 9, com_st++;
233		    else
234			target = 1;
235		if (cur_col > target) {	/* if comment can't fit on this line,
236					 * put it on next line */
237		    putc('\n', output);
238		    cur_col = 1;
239		    ++ps.out_lines;
240		}
241		while (e_com > com_st && isspace(e_com[-1]))
242		    e_com--;
243		cur_col = pad_output(cur_col, target);
244		if (!ps.box_com) {
245		    if (star_comment_cont && (com_st[1] != '*' || e_com <= com_st + 1)) {
246			if (com_st[1] == ' ' && com_st[0] == ' ' && e_com > com_st + 1)
247			    com_st[1] = '*';
248			else
249			    fwrite(" * ", com_st[0] == '\t' ? 2 : com_st[0] == '*' ? 1 : 3, 1, output);
250		    }
251		}
252		fwrite(com_st, e_com - com_st, 1, output);
253		ps.comment_delta = ps.n_comment_delta;
254		cur_col = count_spaces(cur_col, com_st);
255		++ps.com_lines;	/* count lines with comments */
256	    }
257	}
258	if (ps.use_ff)
259	    putc('\014', output);
260	else
261	    putc('\n', output);
262inhibit_newline:
263	++ps.out_lines;
264	if (ps.just_saw_decl == 1 && blanklines_after_declarations) {
265	    prefix_blankline_requested = 1;
266	    ps.just_saw_decl = 0;
267	}
268	else
269	    prefix_blankline_requested = postfix_blankline_requested;
270	postfix_blankline_requested = 0;
271    }
272    ps.decl_on_line = ps.in_decl;	/* if we are in the middle of a
273					 * declaration, remember that fact for
274					 * proper comment indentation */
275    ps.ind_stmt = ps.in_stmt & ~ps.in_decl;	/* next line should be
276						 * indented if we have not
277						 * completed this stmt and if
278						 * we are not in the middle of
279						 * a declaration */
280    ps.use_ff = false;
281    ps.dumped_decl_indent = 0;
282    *(e_lab = s_lab) = '\0';	/* reset buffers */
283    *(e_code = s_code) = '\0';
284    *(e_com = s_com) = '\0';
285    ps.ind_level = ps.i_l_follow;
286    ps.paren_level = ps.p_l_follow;
287    paren_target = -ps.paren_indents[ps.paren_level - 1];
288    not_first_line = 1;
289}
290
291int
292compute_code_target(void)
293{
294    int target_col = ps.ind_size * ps.ind_level + 1;
295
296    if (ps.paren_level)
297	if (!lineup_to_parens)
298	    target_col += continuation_indent
299		* (2 * continuation_indent == ps.ind_size ? 1 : ps.paren_level);
300	else {
301	    int w;
302	    int t = paren_target;
303
304	    if ((w = count_spaces(t, s_code) - max_col) > 0
305		    && count_spaces(target_col, s_code) <= max_col) {
306		t -= w + 1;
307		if (t > target_col)
308		    target_col = t;
309	    }
310	    else
311		target_col = t;
312	}
313    else if (ps.ind_stmt)
314	target_col += continuation_indent;
315    return target_col;
316}
317
318int
319compute_label_target(void)
320{
321    return
322	ps.pcase ? (int) (case_ind * ps.ind_size) + 1
323	: *s_lab == '#' ? 1
324	: ps.ind_size * (ps.ind_level - label_offset) + 1;
325}
326
327
328/*
329 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
330 *
331 * All rights reserved
332 *
333 *
334 * NAME: fill_buffer
335 *
336 * FUNCTION: Reads one block of input into input_buffer
337 *
338 * HISTORY: initial coding 	November 1976	D A Willcox of CAC 1/7/77 A
339 * Willcox of CAC	Added check for switch back to partly full input
340 * buffer from temporary buffer
341 *
342 */
343void
344fill_buffer(void)
345{				/* this routine reads stuff from the input */
346    char *p;
347    int i;
348    FILE *f = input;
349
350    if (bp_save != 0) {		/* there is a partly filled input buffer left */
351	buf_ptr = bp_save;	/* dont read anything, just switch buffers */
352	buf_end = be_save;
353	bp_save = be_save = 0;
354	if (buf_ptr < buf_end)
355	    return;		/* only return if there is really something in
356				 * this buffer */
357    }
358    for (p = in_buffer;;) {
359	if (p >= in_buffer_limit) {
360	    int size = (in_buffer_limit - in_buffer) * 2 + 10;
361	    int offset = p - in_buffer;
362	    in_buffer = realloc(in_buffer, size);
363	    if (in_buffer == NULL)
364		errx(1, "input line too long");
365	    p = in_buffer + offset;
366	    in_buffer_limit = in_buffer + size - 2;
367	}
368	if ((i = getc(f)) == EOF) {
369		*p++ = ' ';
370		*p++ = '\n';
371		had_eof = true;
372		break;
373	}
374	*p++ = i;
375	if (i == '\n')
376		break;
377    }
378    buf_ptr = in_buffer;
379    buf_end = p;
380    if (p[-2] == '/' && p[-3] == '*') {
381	if (in_buffer[3] == 'I' && strncmp(in_buffer, "/**INDENT**", 11) == 0)
382	    fill_buffer();	/* flush indent error message */
383	else {
384	    int         com = 0;
385
386	    p = in_buffer;
387	    while (*p == ' ' || *p == '\t')
388		p++;
389	    if (*p == '/' && p[1] == '*') {
390		p += 2;
391		while (*p == ' ' || *p == '\t')
392		    p++;
393		if (p[0] == 'I' && p[1] == 'N' && p[2] == 'D' && p[3] == 'E'
394			&& p[4] == 'N' && p[5] == 'T') {
395		    p += 6;
396		    while (*p == ' ' || *p == '\t')
397			p++;
398		    if (*p == '*')
399			com = 1;
400		    else if (*p == 'O') {
401			if (*++p == 'N')
402			    p++, com = 1;
403			else if (*p == 'F' && *++p == 'F')
404			    p++, com = 2;
405		    }
406		    while (*p == ' ' || *p == '\t')
407			p++;
408		    if (p[0] == '*' && p[1] == '/' && p[2] == '\n' && com) {
409			if (s_com != e_com || s_lab != e_lab || s_code != e_code)
410			    dump_line();
411			if (!(inhibit_formatting = com - 1)) {
412			    n_real_blanklines = 0;
413			    postfix_blankline_requested = 0;
414			    prefix_blankline_requested = 0;
415			    suppress_blanklines = 1;
416			}
417		    }
418		}
419	    }
420	}
421    }
422    if (inhibit_formatting) {
423	p = in_buffer;
424	do
425	    putc(*p, output);
426	while (*p++ != '\n');
427    }
428}
429
430/*
431 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
432 *
433 * All rights reserved
434 *
435 *
436 * NAME: pad_output
437 *
438 * FUNCTION: Writes tabs and spaces to move the current column up to the desired
439 * position.
440 *
441 * ALGORITHM: Put tabs and/or blanks into pobuf, then write pobuf.
442 *
443 * PARAMETERS: current		integer		The current column target
444 * nteger		The desired column
445 *
446 * RETURNS: Integer value of the new column.  (If current >= target, no action is
447 * taken, and current is returned.
448 *
449 * GLOBALS: None
450 *
451 * CALLS: write (sys)
452 *
453 * CALLED BY: dump_line
454 *
455 * HISTORY: initial coding 	November 1976	D A Willcox of CAC
456 *
457 */
458static int
459pad_output(int current, int target)
460			        /* writes tabs and blanks (if necessary) to
461				 * get the current output position up to the
462				 * target column */
463    /* current: the current column value */
464    /* target: position we want it at */
465{
466    int curr;		/* internal column pointer */
467    int tcur;
468
469    if (troff)
470	fprintf(output, "\\h'|%dp'", (target - 1) * 7);
471    else {
472	if (current >= target)
473	    return (current);	/* line is already long enough */
474	curr = current;
475        if (use_tabs) {
476            while ((tcur = ((curr - 1) & tabmask) + tabsize + 1) <= target) {
477                putc('\t', output);
478                curr = tcur;
479            }
480        }
481        while (curr++ < target)
482	    putc(' ', output);	/* pad with final blanks */
483    }
484    return (target);
485}
486
487/*
488 * Copyright (C) 1976 by the Board of Trustees of the University of Illinois
489 *
490 * All rights reserved
491 *
492 *
493 * NAME: count_spaces
494 *
495 * FUNCTION: Find out where printing of a given string will leave the current
496 * character position on output.
497 *
498 * ALGORITHM: Run thru input string and add appropriate values to current
499 * position.
500 *
501 * RETURNS: Integer value of position after printing "buffer" starting in column
502 * "current".
503 *
504 * HISTORY: initial coding 	November 1976	D A Willcox of CAC
505 *
506 */
507int
508count_spaces(int current, char *buffer)
509/*
510 * this routine figures out where the character position will be after
511 * printing the text in buffer starting at column "current"
512 */
513{
514    char *buf;		/* used to look thru buffer */
515    int cur;		/* current character counter */
516
517    cur = current;
518
519    for (buf = buffer; *buf != '\0'; ++buf) {
520	switch (*buf) {
521
522	case '\n':
523	case 014:		/* form feed */
524	    cur = 1;
525	    break;
526
527	case '\t':
528	    cur = ((cur - 1) & tabmask) + tabsize + 1;
529	    break;
530
531	case 010:		/* backspace */
532	    --cur;
533	    break;
534
535	default:
536	    ++cur;
537	    break;
538	}			/* end of switch */
539    }				/* end of for loop */
540    return (cur);
541}
542
543void
544diag4(int level, const char *msg, int a, int b)
545{
546    if (level)
547	found_err = 1;
548    if (output == stdout) {
549	fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
550	fprintf(stdout, msg, a, b);
551	fprintf(stdout, " */\n");
552    }
553    else {
554	fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
555	fprintf(stderr, msg, a, b);
556	fprintf(stderr, "\n");
557    }
558}
559
560void
561diag3(int level, const char *msg, int a)
562{
563    if (level)
564	found_err = 1;
565    if (output == stdout) {
566	fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
567	fprintf(stdout, msg, a);
568	fprintf(stdout, " */\n");
569    }
570    else {
571	fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
572	fprintf(stderr, msg, a);
573	fprintf(stderr, "\n");
574    }
575}
576
577void
578diag2(int level, const char *msg)
579{
580    if (level)
581	found_err = 1;
582    if (output == stdout) {
583	fprintf(stdout, "/**INDENT** %s@%d: ", level == 0 ? "Warning" : "Error", line_no);
584	fprintf(stdout, "%s", msg);
585	fprintf(stdout, " */\n");
586    }
587    else {
588	fprintf(stderr, "%s@%d: ", level == 0 ? "Warning" : "Error", line_no);
589	fprintf(stderr, "%s", msg);
590	fprintf(stderr, "\n");
591    }
592}
593
594void
595writefdef(struct fstate *f, int nm)
596{
597    fprintf(output, ".ds f%c %s\n.nr s%c %d\n",
598	    nm, f->font, nm, f->size);
599}
600
601char *
602chfont(struct fstate *of, struct fstate *nf, char *s)
603{
604    if (of->font[0] != nf->font[0]
605	    || of->font[1] != nf->font[1]) {
606	*s++ = '\\';
607	*s++ = 'f';
608	if (nf->font[1]) {
609	    *s++ = '(';
610	    *s++ = nf->font[0];
611	    *s++ = nf->font[1];
612	}
613	else
614	    *s++ = nf->font[0];
615    }
616    if (nf->size != of->size) {
617	*s++ = '\\';
618	*s++ = 's';
619	if (nf->size < of->size) {
620	    *s++ = '-';
621	    *s++ = '0' + of->size - nf->size;
622	}
623	else {
624	    *s++ = '+';
625	    *s++ = '0' + nf->size - of->size;
626	}
627    }
628    return s;
629}
630
631void
632parsefont(struct fstate *f, const char *s0)
633{
634    const char *s = s0;
635    int         sizedelta = 0;
636
637    bzero(f, sizeof *f);
638    while (*s) {
639	if (isdigit(*s))
640	    f->size = f->size * 10 + *s - '0';
641	else if (isupper(*s))
642	    if (f->font[0])
643		f->font[1] = *s;
644	    else
645		f->font[0] = *s;
646	else if (*s == 'c')
647	    f->allcaps = 1;
648	else if (*s == '+')
649	    sizedelta++;
650	else if (*s == '-')
651	    sizedelta--;
652	else {
653	    errx(1, "bad font specification: %s", s0);
654	}
655	s++;
656    }
657    if (f->font[0] == 0)
658	f->font[0] = 'R';
659    if (bodyf.size == 0)
660	bodyf.size = 11;
661    if (f->size == 0)
662	f->size = bodyf.size + sizedelta;
663    else if (sizedelta > 0)
664	f->size += bodyf.size;
665    else
666	f->size = bodyf.size - f->size;
667}
668