368 lines
9.1 KiB
C
368 lines
9.1 KiB
C
|
/****************************************************************
|
||
|
Copyright 1990, 1991 by AT&T Bell Laboratories and Bellcore.
|
||
|
|
||
|
Permission to use, copy, modify, and distribute this software
|
||
|
and its documentation for any purpose and without fee is hereby
|
||
|
granted, provided that the above copyright notice appear in all
|
||
|
copies and that both that the copyright notice and this
|
||
|
permission notice and warranty disclaimer appear in supporting
|
||
|
documentation, and that the names of AT&T Bell Laboratories or
|
||
|
Bellcore or any of their entities not be used in advertising or
|
||
|
publicity pertaining to distribution of the software without
|
||
|
specific, written prior permission.
|
||
|
|
||
|
AT&T and Bellcore disclaim all warranties with regard to this
|
||
|
software, including all implied warranties of merchantability
|
||
|
and fitness. In no event shall AT&T or Bellcore be liable for
|
||
|
any special, indirect or consequential damages or any damages
|
||
|
whatsoever resulting from loss of use, data or profits, whether
|
||
|
in an action of contract, negligence or other tortious action,
|
||
|
arising out of or in connection with the use or performance of
|
||
|
this software.
|
||
|
****************************************************************/
|
||
|
|
||
|
#include "defs.h"
|
||
|
#include "names.h"
|
||
|
#include "output.h"
|
||
|
|
||
|
#define TOO_LONG_INDENT (2 * tab_size)
|
||
|
#define MAX_INDENT 44
|
||
|
#define MIN_INDENT 22
|
||
|
static int last_was_newline = 0;
|
||
|
int indent = 0;
|
||
|
int in_comment = 0;
|
||
|
|
||
|
static int
|
||
|
write_indent(fp, use_indent, extra_indent, start, end)
|
||
|
FILE *fp;
|
||
|
int use_indent, extra_indent;
|
||
|
char *start, *end;
|
||
|
{
|
||
|
int ind, tab;
|
||
|
|
||
|
if (last_was_newline && use_indent) {
|
||
|
if (*start == '\n') do {
|
||
|
putc('\n', fp);
|
||
|
if (++start > end)
|
||
|
return;
|
||
|
}
|
||
|
while(*start == '\n');
|
||
|
|
||
|
ind = indent <= MAX_INDENT
|
||
|
? indent
|
||
|
: MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
|
||
|
|
||
|
tab = ind + extra_indent;
|
||
|
|
||
|
while (tab > 7) {
|
||
|
putc ('\t', fp);
|
||
|
tab -= 8;
|
||
|
} /* while */
|
||
|
|
||
|
while (tab-- > 0)
|
||
|
putc (' ', fp);
|
||
|
} /* if last_was_newline */
|
||
|
|
||
|
while (start <= end)
|
||
|
putc (*start++, fp);
|
||
|
} /* write_indent */
|
||
|
|
||
|
|
||
|
/*VARARGS2*/
|
||
|
int margin_printf (fp, a, b, c, d, e, f, g)
|
||
|
FILE *fp;
|
||
|
char *a;
|
||
|
long b, c, d, e, f, g;
|
||
|
{
|
||
|
ind_printf (0, fp, a, b, c, d, e, f, g);
|
||
|
} /* margin_printf */
|
||
|
|
||
|
/*VARARGS2*/
|
||
|
int nice_printf (fp, a, b, c, d, e, f, g)
|
||
|
FILE *fp;
|
||
|
char *a;
|
||
|
long b, c, d, e, f, g;
|
||
|
{
|
||
|
ind_printf (1, fp, a, b, c, d, e, f, g);
|
||
|
} /* nice_printf */
|
||
|
|
||
|
|
||
|
#define max_line_len c_output_line_length
|
||
|
/* 74Number of characters allowed on an output
|
||
|
line. This assumes newlines are handled
|
||
|
nicely, i.e. a newline after a full text
|
||
|
line on a terminal is ignored */
|
||
|
|
||
|
/* output_buf holds the text of the next line to be printed. It gets
|
||
|
flushed when a newline is printed. next_slot points to the next
|
||
|
available location in the output buffer, i.e. where the next call to
|
||
|
nice_printf will have its output stored */
|
||
|
|
||
|
static char *output_buf;
|
||
|
static char *next_slot;
|
||
|
static char *string_start;
|
||
|
|
||
|
static char *word_start = NULL;
|
||
|
static int cursor_pos = 0;
|
||
|
static int In_string = 0;
|
||
|
|
||
|
void
|
||
|
np_init()
|
||
|
{
|
||
|
next_slot = output_buf = Alloc(MAX_OUTPUT_SIZE);
|
||
|
memset(output_buf, 0, MAX_OUTPUT_SIZE);
|
||
|
}
|
||
|
|
||
|
static char *
|
||
|
adjust_pointer_in_string(pointer)
|
||
|
register char *pointer;
|
||
|
{
|
||
|
register char *s, *s1, *se, *s0;
|
||
|
|
||
|
/* arrange not to break \002 */
|
||
|
s1 = string_start ? string_start : output_buf;
|
||
|
for(s = s1; s < pointer; s++) {
|
||
|
s0 = s1;
|
||
|
s1 = s;
|
||
|
if (*s == '\\') {
|
||
|
se = s++ + 4;
|
||
|
if (se > pointer)
|
||
|
break;
|
||
|
if (*s < '0' || *s > '7')
|
||
|
continue;
|
||
|
while(++s < se)
|
||
|
if (*s < '0' || *s > '7')
|
||
|
break;
|
||
|
--s;
|
||
|
}
|
||
|
}
|
||
|
return s0 - 1;
|
||
|
}
|
||
|
|
||
|
/* ANSI says strcpy's behavior is undefined for overlapping args,
|
||
|
* so we roll our own fwd_strcpy: */
|
||
|
|
||
|
static void
|
||
|
fwd_strcpy(t, s)
|
||
|
register char *t, *s;
|
||
|
{ while(*t++ = *s++); }
|
||
|
|
||
|
/* isident -- true iff character could belong to a unit. C allows
|
||
|
letters, numbers and underscores in identifiers. This also doubles as
|
||
|
a check for numeric constants, since we include the decimal point and
|
||
|
minus sign. The minus has to be here, since the constant "10e-2"
|
||
|
cannot be broken up. The '.' also prevents structure references from
|
||
|
being broken, which is a quite acceptable side effect */
|
||
|
|
||
|
#define isident(x) (Tr[x] & 1)
|
||
|
#define isntident(x) (!Tr[x])
|
||
|
|
||
|
int ind_printf (use_indent, fp, a, b, c, d, e, f, g)
|
||
|
int use_indent;
|
||
|
FILE *fp;
|
||
|
char *a;
|
||
|
long b, c, d, e, f, g;
|
||
|
{
|
||
|
extern int max_line_len;
|
||
|
extern FILEP c_file;
|
||
|
extern char tr_tab[]; /* in output.c */
|
||
|
register char *Tr = tr_tab;
|
||
|
int ch, inc, ind;
|
||
|
static int extra_indent, last_indent, set_cursor = 1;
|
||
|
|
||
|
cursor_pos += indent - last_indent;
|
||
|
last_indent = indent;
|
||
|
sprintf (next_slot, a, b, c, d, e, f, g);
|
||
|
|
||
|
if (fp != c_file) {
|
||
|
fprintf (fp,"%s", next_slot);
|
||
|
return 1;
|
||
|
} /* if fp != c_file */
|
||
|
|
||
|
do {
|
||
|
char *pointer;
|
||
|
|
||
|
/* The for loop will parse one output line */
|
||
|
|
||
|
if (set_cursor) {
|
||
|
ind = indent <= MAX_INDENT
|
||
|
? indent
|
||
|
: MIN_INDENT + indent % (MAX_INDENT - MIN_INDENT);
|
||
|
cursor_pos = ind + extra_indent;
|
||
|
set_cursor = 0;
|
||
|
}
|
||
|
if (in_comment)
|
||
|
for (pointer = next_slot; *pointer && *pointer != '\n' &&
|
||
|
cursor_pos <= max_line_len; pointer++)
|
||
|
cursor_pos++;
|
||
|
else
|
||
|
for (pointer = next_slot; *pointer && *pointer != '\n' &&
|
||
|
cursor_pos <= max_line_len; pointer++) {
|
||
|
|
||
|
/* Update state variables here */
|
||
|
|
||
|
if (In_string) {
|
||
|
switch(*pointer) {
|
||
|
case '\\':
|
||
|
if (++cursor_pos > max_line_len) {
|
||
|
cursor_pos -= 2;
|
||
|
--pointer;
|
||
|
goto overflow;
|
||
|
}
|
||
|
++pointer;
|
||
|
break;
|
||
|
case '"':
|
||
|
In_string = 0;
|
||
|
word_start = 0;
|
||
|
}
|
||
|
}
|
||
|
else switch (*pointer) {
|
||
|
case '"':
|
||
|
if (cursor_pos + 5 > max_line_len) {
|
||
|
word_start = 0;
|
||
|
--pointer;
|
||
|
goto overflow;
|
||
|
}
|
||
|
In_string = 1;
|
||
|
string_start = word_start = pointer;
|
||
|
break;
|
||
|
case '\'':
|
||
|
if (pointer[1] == '\\')
|
||
|
if ((ch = pointer[2]) >= '0' && ch <= '7')
|
||
|
for(inc = 3; pointer[inc] != '\''
|
||
|
&& ++inc < 5;);
|
||
|
else
|
||
|
inc = 3;
|
||
|
else
|
||
|
inc = 2;
|
||
|
/*debug*/ if (pointer[inc] != '\'')
|
||
|
/*debug*/ fatalstr("Bad character constant %.10s",
|
||
|
pointer);
|
||
|
if ((cursor_pos += inc) > max_line_len) {
|
||
|
cursor_pos -= inc;
|
||
|
word_start = 0;
|
||
|
--pointer;
|
||
|
goto overflow;
|
||
|
}
|
||
|
word_start = pointer;
|
||
|
pointer += inc;
|
||
|
break;
|
||
|
case '\t':
|
||
|
cursor_pos = 8 * ((cursor_pos + 8) / 8) - 1;
|
||
|
break;
|
||
|
default: {
|
||
|
|
||
|
/* HACK Assumes that all characters in an atomic C token will be written
|
||
|
at the same time. Must check for tokens first, since '-' is considered
|
||
|
part of an identifier; checking isident first would mean breaking up "->" */
|
||
|
|
||
|
if (!word_start && isident(*(unsigned char *)pointer))
|
||
|
word_start = pointer;
|
||
|
else if (word_start && isntident(*(unsigned char *)pointer))
|
||
|
word_start = NULL;
|
||
|
break;
|
||
|
} /* default */
|
||
|
} /* switch */
|
||
|
cursor_pos++;
|
||
|
} /* for pointer = next_slot */
|
||
|
overflow:
|
||
|
if (*pointer == '\0') {
|
||
|
|
||
|
/* The output line is not complete, so break out and don't output
|
||
|
anything. The current line fragment will be stored in the buffer */
|
||
|
|
||
|
next_slot = pointer;
|
||
|
break;
|
||
|
} else {
|
||
|
char last_char;
|
||
|
int in_string0 = In_string;
|
||
|
|
||
|
/* If the line was too long, move pointer back to the character before
|
||
|
the current word. This allows line breaking on word boundaries. Make
|
||
|
sure that 80 character comment lines get broken up somehow. We assume
|
||
|
that any non-string 80 character identifier must be in a comment.
|
||
|
*/
|
||
|
|
||
|
if (word_start && *pointer != '\n' && word_start > output_buf)
|
||
|
if (In_string)
|
||
|
if (string_start && pointer - string_start < 5)
|
||
|
pointer = string_start - 1;
|
||
|
else {
|
||
|
pointer = adjust_pointer_in_string(pointer);
|
||
|
string_start = 0;
|
||
|
}
|
||
|
else if (word_start == string_start
|
||
|
&& pointer - string_start >= 5) {
|
||
|
pointer = adjust_pointer_in_string(next_slot);
|
||
|
In_string = 1;
|
||
|
string_start = 0;
|
||
|
}
|
||
|
else
|
||
|
pointer = word_start - 1;
|
||
|
else if (cursor_pos > max_line_len) {
|
||
|
extern char *strchr();
|
||
|
if (In_string) {
|
||
|
pointer = adjust_pointer_in_string(pointer);
|
||
|
if (string_start && pointer > string_start)
|
||
|
string_start = 0;
|
||
|
}
|
||
|
else if (strchr("&*+-/<=>|", *pointer)
|
||
|
&& strchr("!%&*+-/<=>^|", pointer[-1])) {
|
||
|
pointer -= 2;
|
||
|
if (strchr("<>", *pointer)) /* <<=, >>= */
|
||
|
pointer--;
|
||
|
}
|
||
|
else
|
||
|
pointer--;
|
||
|
}
|
||
|
last_char = *pointer;
|
||
|
write_indent(fp, use_indent, extra_indent, output_buf, pointer);
|
||
|
next_slot = output_buf;
|
||
|
if (In_string && !string_start && Ansi == 1 && last_char != '\n')
|
||
|
*next_slot++ = '"';
|
||
|
fwd_strcpy(next_slot, pointer + 1);
|
||
|
|
||
|
/* insert a line break */
|
||
|
|
||
|
if (last_char == '\n') {
|
||
|
if (In_string)
|
||
|
last_was_newline = 0;
|
||
|
else {
|
||
|
last_was_newline = 1;
|
||
|
extra_indent = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
extra_indent = TOO_LONG_INDENT;
|
||
|
if (In_string && !string_start) {
|
||
|
if (Ansi == 1) {
|
||
|
fprintf(fp, "\"\n");
|
||
|
use_indent = 1;
|
||
|
last_was_newline = 1;
|
||
|
}
|
||
|
else {
|
||
|
fprintf(fp, "\\\n");
|
||
|
last_was_newline = 0;
|
||
|
}
|
||
|
In_string = in_string0;
|
||
|
}
|
||
|
else {
|
||
|
putc ('\n', fp);
|
||
|
last_was_newline = 1;
|
||
|
}
|
||
|
} /* if *pointer != '\n' */
|
||
|
|
||
|
if (In_string && Ansi != 1 && !string_start)
|
||
|
cursor_pos = 0;
|
||
|
else
|
||
|
set_cursor = 1;
|
||
|
|
||
|
string_start = word_start = NULL;
|
||
|
|
||
|
} /* else */
|
||
|
|
||
|
} while (*next_slot);
|
||
|
|
||
|
return 0;
|
||
|
} /* ind_printf */
|