-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathformat.c
225 lines (201 loc) · 4.78 KB
/
format.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#include "c2ada.h"
extern FILE* cur_unit_fd;
#undef NULL
#define NULL 0
static int indentation = START_INDENT;
static int spec_indentation = START_INDENT;
static int body_indentation = START_INDENT;
/*
* This flag is true if we're currently putting a string or char literal.
* It's used to decide how to handle line breaks.
*/
static bool in_text_literal = false;
/* This is a stronger form of literal quotation: unlike strings,
* we'll NEVER want to split in one of these literals (floating
* point literals are the motivating case.)
*/
static bool in_literal = false;
/*
* This flag is set if we're outputting a comment.
*/
static bool in_comment = false;
/*
* The maximum allowable width of an output line. GNAT, for one, has
* a hard limit on this, aside from legibility concerns.
*/
static const int max_line_width = 100;
static int line_num = 0;
static int spec_line_num = 0;
static int body_line_num = 0;
void format_to_spec()
{
body_indentation = indentation;
body_line_num = line_num;
indentation = spec_indentation;
line_num = spec_line_num;
}
void format_to_body()
{
spec_indentation = indentation;
spec_line_num = line_num;
indentation = body_indentation;
line_num = body_line_num;
}
int output_line()
{
return line_num;
}
void reset_output_line()
{
spec_line_num = body_line_num = line_num = 1;
}
static bool allow_break_after(char c)
{
if(isalnum(c))
return false;
switch(c)
{
case '_': /* constituent of identifiers */
case ':': /* := */
case '=': /* => */
case '.': /* .. */
case '/': /* /= */
case '>': /* >=, >> */
case '<': /* <=, <<, <> */
case '*': /* ** */
return false;
default:
return true;
}
}
static void put(char c)
{
fputc(c, cur_unit_fd);
if(c == '\n')
{
line_num++;
indentation = START_INDENT;
in_comment = false;
}
else
{
indentation++;
if(indentation > max_line_width)
{
/* For now, we're not strictly enforcing line length.
* We may have to break long text literals if this
* simpler scheme doesn't work
*/
if(!(in_text_literal || in_literal) && allow_break_after(c))
{
if(in_comment)
{
put('\n');
putf("%--");
}
else
{
put('\n');
}
}
}
}
}
void reset_indent()
{
spec_indentation = body_indentation = indentation = START_INDENT;
}
void put_char(int c)
{
put(c);
}
void new_line()
{
put('\n');
}
int cur_indent()
{
return indentation;
}
void indent_to(int n)
{
if(n < indentation)
{
put('\n');
}
while(indentation < n)
{
put(' ');
}
}
void put_string(const char* s)
{
if(s == NULL)
s = " <NULL> ";
while(*s)
{
put(*s++);
}
}
void putf(const char* s, ...)
{
va_list ap;
char c;
char* sarg;
int iarg;
va_start(ap, s);
while((c = *s++))
{
if(c == '%')
{
c = *s++;
switch(c)
{
case 's':
sarg = va_arg(ap, char*);
if(sarg && *sarg)
{
put_string(sarg);
}
break;
case '>':
iarg = va_arg(ap, int);
indent_to(iarg);
break;
case '%':
put('%');
break;
case '{': /* start of string or char literal */
in_text_literal = true;
break;
case '}': /* end of string or char literal */
in_text_literal = false;
break;
case '-': /* start of comment; the format string */
/* will look like ...%--... */
if(indentation > max_line_width)
put('\n');
in_comment = true;
put('-');
break;
case '[': /* start of unbreakable literal */
in_literal = true;
break;
case ']': /* end of unbreakable literal */
in_literal = false;
break;
case 0:
default:
fatal(__FILE__, __LINE__, "bad format in putf()");
}
}
else
{
put(c);
}
}
va_end(ap);
}