Commit | Line | Data |
c623bd54 |
1 | /* $Header: form.c,v 3.0.1.4 91/01/11 18:04:07 lwall Locked $ |
a687059c |
2 | * |
3 | * Copyright (c) 1989, Larry Wall |
4 | * |
5 | * You may distribute under the terms of the GNU General Public License |
6 | * as specified in the README file that comes with the perl 3.0 kit. |
8d063cd8 |
7 | * |
8 | * $Log: form.c,v $ |
c623bd54 |
9 | * Revision 3.0.1.4 91/01/11 18:04:07 lwall |
10 | * patch42: the @* format counted lines wrong |
11 | * patch42: the @* format didn't handle lines with nulls or without newline |
12 | * |
d9d8d8de |
13 | * Revision 3.0.1.3 90/10/15 17:26:24 lwall |
14 | * patch29: added @###.## fields to format |
15 | * |
154e51a4 |
16 | * Revision 3.0.1.2 90/08/09 03:38:40 lwall |
17 | * patch19: did preliminary work toward debugging packages and evals |
18 | * |
ac58e20f |
19 | * Revision 3.0.1.1 90/02/28 17:39:34 lwall |
20 | * patch9: ... in format threw off subsequent field |
21 | * |
a687059c |
22 | * Revision 3.0 89/10/18 15:17:26 lwall |
23 | * 3.0 baseline |
8d063cd8 |
24 | * |
25 | */ |
26 | |
8d063cd8 |
27 | #include "EXTERN.h" |
8d063cd8 |
28 | #include "perl.h" |
29 | |
30 | /* Forms stuff */ |
31 | |
a687059c |
32 | void |
33 | form_parseargs(fcmd) |
34 | register FCMD *fcmd; |
35 | { |
36 | register int i; |
37 | register ARG *arg; |
38 | register int items; |
39 | STR *str; |
40 | ARG *parselist(); |
154e51a4 |
41 | line_t oldline = curcmd->c_line; |
a687059c |
42 | int oldsave = savestack->ary_fill; |
43 | |
44 | str = fcmd->f_unparsed; |
154e51a4 |
45 | curcmd->c_line = fcmd->f_line; |
a687059c |
46 | fcmd->f_unparsed = Nullstr; |
47 | (void)savehptr(&curstash); |
48 | curstash = str->str_u.str_hash; |
49 | arg = parselist(str); |
50 | restorelist(oldsave); |
51 | |
52 | items = arg->arg_len - 1; /* ignore $$ on end */ |
53 | for (i = 1; i <= items; i++) { |
54 | if (!fcmd || fcmd->f_type == F_NULL) |
55 | fatal("Too many field values"); |
56 | dehoist(arg,i); |
57 | fcmd->f_expr = make_op(O_ITEM,1, |
58 | arg[i].arg_ptr.arg_arg,Nullarg,Nullarg); |
59 | if (fcmd->f_flags & FC_CHOP) { |
60 | if ((fcmd->f_expr[1].arg_type & A_MASK) == A_STAB) |
61 | fcmd->f_expr[1].arg_type = A_LVAL; |
62 | else if ((fcmd->f_expr[1].arg_type & A_MASK) == A_EXPR) |
63 | fcmd->f_expr[1].arg_type = A_LEXPR; |
64 | else |
65 | fatal("^ field requires scalar lvalue"); |
66 | } |
67 | fcmd = fcmd->f_next; |
68 | } |
69 | if (fcmd && fcmd->f_type) |
70 | fatal("Not enough field values"); |
154e51a4 |
71 | curcmd->c_line = oldline; |
a687059c |
72 | Safefree(arg); |
73 | str_free(str); |
74 | } |
75 | |
76 | int newsize; |
77 | |
8d063cd8 |
78 | #define CHKLEN(allow) \ |
a687059c |
79 | newsize = (d - orec->o_str) + (allow); \ |
80 | if (newsize >= curlen) { \ |
8d063cd8 |
81 | curlen = d - orec->o_str; \ |
82 | GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \ |
83 | d = orec->o_str + curlen; /* in case it moves */ \ |
84 | curlen = orec->o_len - 2; \ |
85 | } |
86 | |
a687059c |
87 | format(orec,fcmd,sp) |
8d063cd8 |
88 | register struct outrec *orec; |
89 | register FCMD *fcmd; |
a687059c |
90 | int sp; |
8d063cd8 |
91 | { |
92 | register char *d = orec->o_str; |
93 | register char *s; |
94 | register int curlen = orec->o_len - 2; |
95 | register int size; |
a687059c |
96 | FCMD *nextfcmd; |
97 | FCMD *linebeg = fcmd; |
8d063cd8 |
98 | char tmpchar; |
99 | char *t; |
100 | CMD mycmd; |
101 | STR *str; |
102 | char *chophere; |
103 | |
104 | mycmd.c_type = C_NULL; |
105 | orec->o_lines = 0; |
a687059c |
106 | for (; fcmd; fcmd = nextfcmd) { |
107 | nextfcmd = fcmd->f_next; |
8d063cd8 |
108 | CHKLEN(fcmd->f_presize); |
a687059c |
109 | if (s = fcmd->f_pre) { |
110 | while (*s) { |
111 | if (*s == '\n') { |
112 | while (d > orec->o_str && (d[-1] == ' ' || d[-1] == '\t')) |
113 | d--; |
114 | if (fcmd->f_flags & FC_NOBLANK) { |
115 | if (d == orec->o_str || d[-1] == '\n') { |
116 | orec->o_lines--; /* don't print blank line */ |
117 | linebeg = fcmd->f_next; |
118 | break; |
119 | } |
120 | else if (fcmd->f_flags & FC_REPEAT) |
121 | nextfcmd = linebeg; |
122 | } |
123 | else |
124 | linebeg = fcmd->f_next; |
8d063cd8 |
125 | } |
a687059c |
126 | *d++ = *s++; |
8d063cd8 |
127 | } |
8d063cd8 |
128 | } |
a687059c |
129 | if (fcmd->f_unparsed) |
130 | form_parseargs(fcmd); |
8d063cd8 |
131 | switch (fcmd->f_type) { |
132 | case F_NULL: |
133 | orec->o_lines++; |
134 | break; |
135 | case F_LEFT: |
a687059c |
136 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
137 | str = stack->ary_array[sp+1]; |
8d063cd8 |
138 | s = str_get(str); |
139 | size = fcmd->f_size; |
140 | CHKLEN(size); |
141 | chophere = Nullch; |
142 | while (size && *s && *s != '\n') { |
a687059c |
143 | if (*s == '\t') |
144 | *s = ' '; |
8d063cd8 |
145 | size--; |
a687059c |
146 | if (*s && index(chopset,(*d++ = *s++))) |
8d063cd8 |
147 | chophere = s; |
a687059c |
148 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
149 | *s = ' '; |
8d063cd8 |
150 | } |
151 | if (size) |
152 | chophere = s; |
a687059c |
153 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
154 | chophere = s; |
8d063cd8 |
155 | if (fcmd->f_flags & FC_CHOP) { |
156 | if (!chophere) |
157 | chophere = s; |
158 | size += (s - chophere); |
159 | d -= (s - chophere); |
160 | if (fcmd->f_flags & FC_MORE && |
161 | *chophere && strNE(chophere,"\n")) { |
162 | while (size < 3) { |
163 | d--; |
164 | size++; |
165 | } |
166 | while (d[-1] == ' ' && size < fcmd->f_size) { |
167 | d--; |
168 | size++; |
169 | } |
170 | *d++ = '.'; |
171 | *d++ = '.'; |
172 | *d++ = '.'; |
ac58e20f |
173 | size -= 3; |
8d063cd8 |
174 | } |
a687059c |
175 | while (*chophere && index(chopset,*chophere)) |
176 | chophere++; |
8d063cd8 |
177 | str_chop(str,chophere); |
178 | } |
179 | if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n') |
180 | size = 0; /* no spaces before newline */ |
181 | while (size) { |
182 | size--; |
183 | *d++ = ' '; |
184 | } |
185 | break; |
186 | case F_RIGHT: |
a687059c |
187 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
188 | str = stack->ary_array[sp+1]; |
189 | t = s = str_get(str); |
8d063cd8 |
190 | size = fcmd->f_size; |
191 | CHKLEN(size); |
192 | chophere = Nullch; |
193 | while (size && *s && *s != '\n') { |
a687059c |
194 | if (*s == '\t') |
195 | *s = ' '; |
8d063cd8 |
196 | size--; |
a687059c |
197 | if (*s && index(chopset,*s++)) |
198 | chophere = s; |
199 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
200 | *s = ' '; |
8d063cd8 |
201 | } |
202 | if (size) |
203 | chophere = s; |
a687059c |
204 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
205 | chophere = s; |
8d063cd8 |
206 | if (fcmd->f_flags & FC_CHOP) { |
207 | if (!chophere) |
208 | chophere = s; |
209 | size += (s - chophere); |
8d063cd8 |
210 | s = chophere; |
a687059c |
211 | while (*chophere && index(chopset,*chophere)) |
212 | chophere++; |
8d063cd8 |
213 | } |
214 | tmpchar = *s; |
215 | *s = '\0'; |
216 | while (size) { |
217 | size--; |
218 | *d++ = ' '; |
219 | } |
220 | size = s - t; |
a687059c |
221 | (void)bcopy(t,d,size); |
8d063cd8 |
222 | d += size; |
223 | *s = tmpchar; |
a687059c |
224 | if (fcmd->f_flags & FC_CHOP) |
225 | str_chop(str,chophere); |
8d063cd8 |
226 | break; |
227 | case F_CENTER: { |
228 | int halfsize; |
229 | |
a687059c |
230 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
231 | str = stack->ary_array[sp+1]; |
232 | t = s = str_get(str); |
8d063cd8 |
233 | size = fcmd->f_size; |
234 | CHKLEN(size); |
235 | chophere = Nullch; |
236 | while (size && *s && *s != '\n') { |
a687059c |
237 | if (*s == '\t') |
238 | *s = ' '; |
8d063cd8 |
239 | size--; |
a687059c |
240 | if (*s && index(chopset,*s++)) |
241 | chophere = s; |
242 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
243 | *s = ' '; |
8d063cd8 |
244 | } |
245 | if (size) |
246 | chophere = s; |
a687059c |
247 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
248 | chophere = s; |
8d063cd8 |
249 | if (fcmd->f_flags & FC_CHOP) { |
250 | if (!chophere) |
251 | chophere = s; |
252 | size += (s - chophere); |
8d063cd8 |
253 | s = chophere; |
a687059c |
254 | while (*chophere && index(chopset,*chophere)) |
255 | chophere++; |
8d063cd8 |
256 | } |
257 | tmpchar = *s; |
258 | *s = '\0'; |
259 | halfsize = size / 2; |
260 | while (size > halfsize) { |
261 | size--; |
262 | *d++ = ' '; |
263 | } |
264 | size = s - t; |
a687059c |
265 | (void)bcopy(t,d,size); |
8d063cd8 |
266 | d += size; |
267 | *s = tmpchar; |
268 | if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n') |
269 | size = 0; /* no spaces before newline */ |
270 | else |
271 | size = halfsize; |
272 | while (size) { |
273 | size--; |
274 | *d++ = ' '; |
275 | } |
a687059c |
276 | if (fcmd->f_flags & FC_CHOP) |
277 | str_chop(str,chophere); |
8d063cd8 |
278 | break; |
279 | } |
280 | case F_LINES: |
a687059c |
281 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
282 | str = stack->ary_array[sp+1]; |
8d063cd8 |
283 | s = str_get(str); |
284 | size = str_len(str); |
c623bd54 |
285 | CHKLEN(size+1); |
286 | orec->o_lines += countlines(s,size) - 1; |
a687059c |
287 | (void)bcopy(s,d,size); |
8d063cd8 |
288 | d += size; |
c623bd54 |
289 | if (size && s[size-1] != '\n') { |
290 | *d++ = '\n'; |
291 | orec->o_lines++; |
292 | } |
a687059c |
293 | linebeg = fcmd->f_next; |
8d063cd8 |
294 | break; |
d9d8d8de |
295 | case F_DECIMAL: { |
296 | double value; |
297 | |
298 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
299 | str = stack->ary_array[sp+1]; |
c623bd54 |
300 | size = fcmd->f_size; |
301 | CHKLEN(size); |
d9d8d8de |
302 | /* If the field is marked with ^ and the value is undefined, |
303 | blank it out. */ |
304 | if ((fcmd->f_flags & FC_CHOP) && !str->str_pok && !str->str_nok) { |
305 | while (size) { |
306 | size--; |
307 | *d++ = ' '; |
308 | } |
309 | break; |
310 | } |
311 | value = str_gnum(str); |
d9d8d8de |
312 | if (fcmd->f_flags & FC_DP) { |
313 | sprintf(d, "%#*.*f", size, fcmd->f_decimals, value); |
314 | } else { |
315 | sprintf(d, "%*.0f", size, value); |
316 | } |
317 | d += size; |
318 | break; |
319 | } |
8d063cd8 |
320 | } |
321 | } |
154e51a4 |
322 | CHKLEN(1); |
8d063cd8 |
323 | *d++ = '\0'; |
324 | } |
325 | |
c623bd54 |
326 | countlines(s,size) |
8d063cd8 |
327 | register char *s; |
c623bd54 |
328 | register int size; |
8d063cd8 |
329 | { |
330 | register int count = 0; |
331 | |
c623bd54 |
332 | while (size--) { |
8d063cd8 |
333 | if (*s++ == '\n') |
334 | count++; |
335 | } |
336 | return count; |
337 | } |
338 | |
a687059c |
339 | do_write(orec,stio,sp) |
8d063cd8 |
340 | struct outrec *orec; |
341 | register STIO *stio; |
a687059c |
342 | int sp; |
8d063cd8 |
343 | { |
a687059c |
344 | FILE *ofp = stio->ofp; |
8d063cd8 |
345 | |
346 | #ifdef DEBUGGING |
347 | if (debug & 256) |
378cc40b |
348 | fprintf(stderr,"left=%ld, todo=%ld\n", |
349 | (long)stio->lines_left, (long)orec->o_lines); |
8d063cd8 |
350 | #endif |
351 | if (stio->lines_left < orec->o_lines) { |
352 | if (!stio->top_stab) { |
353 | STAB *topstab; |
354 | |
355 | if (!stio->top_name) |
356 | stio->top_name = savestr("top"); |
357 | topstab = stabent(stio->top_name,FALSE); |
a687059c |
358 | if (!topstab || !stab_form(topstab)) { |
8d063cd8 |
359 | stio->lines_left = 100000000; |
360 | goto forget_top; |
361 | } |
362 | stio->top_stab = topstab; |
363 | } |
a687059c |
364 | if (stio->lines_left >= 0 && stio->page > 0) |
365 | (void)putc('\f',ofp); |
8d063cd8 |
366 | stio->lines_left = stio->page_len; |
367 | stio->page++; |
a687059c |
368 | format(&toprec,stab_form(stio->top_stab),sp); |
8d063cd8 |
369 | fputs(toprec.o_str,ofp); |
370 | stio->lines_left -= toprec.o_lines; |
371 | } |
372 | forget_top: |
373 | fputs(orec->o_str,ofp); |
374 | stio->lines_left -= orec->o_lines; |
375 | } |