1 | /* $RCSfile: form.c,v $$Revision: 1.1.1.1 $$Date: 1996-10-02 06:39:56 $ |
---|
2 | * |
---|
3 | * Copyright (c) 1991, Larry Wall |
---|
4 | * |
---|
5 | * You may distribute under the terms of either the GNU General Public |
---|
6 | * License or the Artistic License, as specified in the README file. |
---|
7 | * |
---|
8 | * $Log: not supported by cvs2svn $ |
---|
9 | * Revision 4.0.1.4 1993/02/05 19:34:32 lwall |
---|
10 | * patch36: formats now ignore literal text for ~~ loop determination |
---|
11 | * |
---|
12 | * Revision 4.0.1.3 92/06/08 13:21:42 lwall |
---|
13 | * patch20: removed implicit int declarations on funcions |
---|
14 | * patch20: form feed for formats is now specifiable via $^L |
---|
15 | * patch20: Perl now distinguishes overlapped copies from non-overlapped |
---|
16 | * |
---|
17 | * Revision 4.0.1.2 91/11/05 17:18:43 lwall |
---|
18 | * patch11: formats didn't fill their fields as well as they could |
---|
19 | * patch11: ^ fields chopped hyphens on line break |
---|
20 | * patch11: # fields could write outside allocated memory |
---|
21 | * |
---|
22 | * Revision 4.0.1.1 91/06/07 11:07:59 lwall |
---|
23 | * patch4: new copyright notice |
---|
24 | * patch4: default top-of-form format is now FILEHANDLE_TOP |
---|
25 | * |
---|
26 | * Revision 4.0 91/03/20 01:19:23 lwall |
---|
27 | * 4.0 baseline. |
---|
28 | * |
---|
29 | */ |
---|
30 | |
---|
31 | #include "EXTERN.h" |
---|
32 | #include "perl.h" |
---|
33 | |
---|
34 | /* Forms stuff */ |
---|
35 | |
---|
36 | static int countlines(); |
---|
37 | |
---|
38 | void |
---|
39 | form_parseargs(fcmd) |
---|
40 | register FCMD *fcmd; |
---|
41 | { |
---|
42 | register int i; |
---|
43 | register ARG *arg; |
---|
44 | register int items; |
---|
45 | STR *str; |
---|
46 | ARG *parselist(); |
---|
47 | line_t oldline = curcmd->c_line; |
---|
48 | int oldsave = savestack->ary_fill; |
---|
49 | |
---|
50 | str = fcmd->f_unparsed; |
---|
51 | curcmd->c_line = fcmd->f_line; |
---|
52 | fcmd->f_unparsed = Nullstr; |
---|
53 | (void)savehptr(&curstash); |
---|
54 | curstash = str->str_u.str_hash; |
---|
55 | arg = parselist(str); |
---|
56 | restorelist(oldsave); |
---|
57 | |
---|
58 | items = arg->arg_len - 1; /* ignore $$ on end */ |
---|
59 | for (i = 1; i <= items; i++) { |
---|
60 | if (!fcmd || fcmd->f_type == F_NULL) |
---|
61 | fatal("Too many field values"); |
---|
62 | dehoist(arg,i); |
---|
63 | fcmd->f_expr = make_op(O_ITEM,1, |
---|
64 | arg[i].arg_ptr.arg_arg,Nullarg,Nullarg); |
---|
65 | if (fcmd->f_flags & FC_CHOP) { |
---|
66 | if ((fcmd->f_expr[1].arg_type & A_MASK) == A_STAB) |
---|
67 | fcmd->f_expr[1].arg_type = A_LVAL; |
---|
68 | else if ((fcmd->f_expr[1].arg_type & A_MASK) == A_EXPR) |
---|
69 | fcmd->f_expr[1].arg_type = A_LEXPR; |
---|
70 | else |
---|
71 | fatal("^ field requires scalar lvalue"); |
---|
72 | } |
---|
73 | fcmd = fcmd->f_next; |
---|
74 | } |
---|
75 | if (fcmd && fcmd->f_type) |
---|
76 | fatal("Not enough field values"); |
---|
77 | curcmd->c_line = oldline; |
---|
78 | Safefree(arg); |
---|
79 | str_free(str); |
---|
80 | } |
---|
81 | |
---|
82 | int newsize; |
---|
83 | |
---|
84 | #define CHKLEN(allow) \ |
---|
85 | newsize = (d - orec->o_str) + (allow); \ |
---|
86 | if (newsize >= curlen) { \ |
---|
87 | curlen = d - orec->o_str; \ |
---|
88 | GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \ |
---|
89 | d = orec->o_str + curlen; /* in case it moves */ \ |
---|
90 | curlen = orec->o_len - 2; \ |
---|
91 | } |
---|
92 | |
---|
93 | void |
---|
94 | format(orec,fcmd,sp) |
---|
95 | register struct outrec *orec; |
---|
96 | register FCMD *fcmd; |
---|
97 | int sp; |
---|
98 | { |
---|
99 | register char *d = orec->o_str; |
---|
100 | register char *s; |
---|
101 | register int curlen = orec->o_len - 2; |
---|
102 | register int size; |
---|
103 | FCMD *nextfcmd; |
---|
104 | FCMD *linebeg = fcmd; |
---|
105 | char tmpchar; |
---|
106 | char *t; |
---|
107 | CMD mycmd; |
---|
108 | STR *str; |
---|
109 | char *chophere; |
---|
110 | int blank = TRUE; |
---|
111 | |
---|
112 | mycmd.c_type = C_NULL; |
---|
113 | orec->o_lines = 0; |
---|
114 | for (; fcmd; fcmd = nextfcmd) { |
---|
115 | nextfcmd = fcmd->f_next; |
---|
116 | CHKLEN(fcmd->f_presize); |
---|
117 | /*SUPPRESS 560*/ |
---|
118 | if (s = fcmd->f_pre) { |
---|
119 | while (*s) { |
---|
120 | if (*s == '\n') { |
---|
121 | t = orec->o_str; |
---|
122 | if (blank && (fcmd->f_flags & FC_REPEAT)) { |
---|
123 | while (d > t && (d[-1] != '\n')) |
---|
124 | d--; |
---|
125 | } |
---|
126 | else { |
---|
127 | while (d > t && (d[-1] == ' ' || d[-1] == '\t')) |
---|
128 | d--; |
---|
129 | } |
---|
130 | if (fcmd->f_flags & FC_NOBLANK) { |
---|
131 | if (blank || d == orec->o_str || d[-1] == '\n') { |
---|
132 | orec->o_lines--; /* don't print blank line */ |
---|
133 | linebeg = fcmd->f_next; |
---|
134 | break; |
---|
135 | } |
---|
136 | else if (fcmd->f_flags & FC_REPEAT) |
---|
137 | nextfcmd = linebeg; |
---|
138 | else |
---|
139 | linebeg = fcmd->f_next; |
---|
140 | } |
---|
141 | else |
---|
142 | linebeg = fcmd->f_next; |
---|
143 | blank = TRUE; |
---|
144 | } |
---|
145 | *d++ = *s++; |
---|
146 | } |
---|
147 | } |
---|
148 | if (fcmd->f_unparsed) |
---|
149 | form_parseargs(fcmd); |
---|
150 | switch (fcmd->f_type) { |
---|
151 | case F_NULL: |
---|
152 | orec->o_lines++; |
---|
153 | break; |
---|
154 | case F_LEFT: |
---|
155 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
---|
156 | str = stack->ary_array[sp+1]; |
---|
157 | s = str_get(str); |
---|
158 | size = fcmd->f_size; |
---|
159 | CHKLEN(size); |
---|
160 | chophere = Nullch; |
---|
161 | while (size && *s && *s != '\n') { |
---|
162 | if (*s == '\t') |
---|
163 | *s = ' '; |
---|
164 | else if (*s != ' ') |
---|
165 | blank = FALSE; |
---|
166 | size--; |
---|
167 | if (*s && index(chopset,(*d++ = *s++))) |
---|
168 | chophere = s; |
---|
169 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
---|
170 | *s = ' '; |
---|
171 | } |
---|
172 | if (size || !*s) |
---|
173 | chophere = s; |
---|
174 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
---|
175 | chophere = s; |
---|
176 | if (fcmd->f_flags & FC_CHOP) { |
---|
177 | if (!chophere) |
---|
178 | chophere = s; |
---|
179 | size += (s - chophere); |
---|
180 | d -= (s - chophere); |
---|
181 | if (fcmd->f_flags & FC_MORE && |
---|
182 | *chophere && strNE(chophere,"\n")) { |
---|
183 | while (size < 3) { |
---|
184 | d--; |
---|
185 | size++; |
---|
186 | } |
---|
187 | while (d[-1] == ' ' && size < fcmd->f_size) { |
---|
188 | d--; |
---|
189 | size++; |
---|
190 | } |
---|
191 | *d++ = '.'; |
---|
192 | *d++ = '.'; |
---|
193 | *d++ = '.'; |
---|
194 | size -= 3; |
---|
195 | } |
---|
196 | while (*chophere && index(chopset,*chophere) |
---|
197 | && isSPACE(*chophere)) |
---|
198 | chophere++; |
---|
199 | str_chop(str,chophere); |
---|
200 | } |
---|
201 | if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n') |
---|
202 | size = 0; /* no spaces before newline */ |
---|
203 | while (size) { |
---|
204 | size--; |
---|
205 | *d++ = ' '; |
---|
206 | } |
---|
207 | break; |
---|
208 | case F_RIGHT: |
---|
209 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
---|
210 | str = stack->ary_array[sp+1]; |
---|
211 | t = s = str_get(str); |
---|
212 | size = fcmd->f_size; |
---|
213 | CHKLEN(size); |
---|
214 | chophere = Nullch; |
---|
215 | while (size && *s && *s != '\n') { |
---|
216 | if (*s == '\t') |
---|
217 | *s = ' '; |
---|
218 | else if (*s != ' ') |
---|
219 | blank = FALSE; |
---|
220 | size--; |
---|
221 | if (*s && index(chopset,*s++)) |
---|
222 | chophere = s; |
---|
223 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
---|
224 | *s = ' '; |
---|
225 | } |
---|
226 | if (size || !*s) |
---|
227 | chophere = s; |
---|
228 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
---|
229 | chophere = s; |
---|
230 | if (fcmd->f_flags & FC_CHOP) { |
---|
231 | if (!chophere) |
---|
232 | chophere = s; |
---|
233 | size += (s - chophere); |
---|
234 | s = chophere; |
---|
235 | while (*chophere && index(chopset,*chophere) |
---|
236 | && isSPACE(*chophere)) |
---|
237 | chophere++; |
---|
238 | } |
---|
239 | tmpchar = *s; |
---|
240 | *s = '\0'; |
---|
241 | while (size) { |
---|
242 | size--; |
---|
243 | *d++ = ' '; |
---|
244 | } |
---|
245 | size = s - t; |
---|
246 | Copy(t,d,size,char); |
---|
247 | d += size; |
---|
248 | *s = tmpchar; |
---|
249 | if (fcmd->f_flags & FC_CHOP) |
---|
250 | str_chop(str,chophere); |
---|
251 | break; |
---|
252 | case F_CENTER: { |
---|
253 | int halfsize; |
---|
254 | |
---|
255 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
---|
256 | str = stack->ary_array[sp+1]; |
---|
257 | t = s = str_get(str); |
---|
258 | size = fcmd->f_size; |
---|
259 | CHKLEN(size); |
---|
260 | chophere = Nullch; |
---|
261 | while (size && *s && *s != '\n') { |
---|
262 | if (*s == '\t') |
---|
263 | *s = ' '; |
---|
264 | else if (*s != ' ') |
---|
265 | blank = FALSE; |
---|
266 | size--; |
---|
267 | if (*s && index(chopset,*s++)) |
---|
268 | chophere = s; |
---|
269 | if (*s == '\n' && (fcmd->f_flags & FC_CHOP)) |
---|
270 | *s = ' '; |
---|
271 | } |
---|
272 | if (size || !*s) |
---|
273 | chophere = s; |
---|
274 | else if (chophere && chophere < s && *s && index(chopset,*s)) |
---|
275 | chophere = s; |
---|
276 | if (fcmd->f_flags & FC_CHOP) { |
---|
277 | if (!chophere) |
---|
278 | chophere = s; |
---|
279 | size += (s - chophere); |
---|
280 | s = chophere; |
---|
281 | while (*chophere && index(chopset,*chophere) |
---|
282 | && isSPACE(*chophere)) |
---|
283 | chophere++; |
---|
284 | } |
---|
285 | tmpchar = *s; |
---|
286 | *s = '\0'; |
---|
287 | halfsize = size / 2; |
---|
288 | while (size > halfsize) { |
---|
289 | size--; |
---|
290 | *d++ = ' '; |
---|
291 | } |
---|
292 | size = s - t; |
---|
293 | Copy(t,d,size,char); |
---|
294 | d += size; |
---|
295 | *s = tmpchar; |
---|
296 | if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n') |
---|
297 | size = 0; /* no spaces before newline */ |
---|
298 | else |
---|
299 | size = halfsize; |
---|
300 | while (size) { |
---|
301 | size--; |
---|
302 | *d++ = ' '; |
---|
303 | } |
---|
304 | if (fcmd->f_flags & FC_CHOP) |
---|
305 | str_chop(str,chophere); |
---|
306 | break; |
---|
307 | } |
---|
308 | case F_LINES: |
---|
309 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
---|
310 | str = stack->ary_array[sp+1]; |
---|
311 | s = str_get(str); |
---|
312 | size = str_len(str); |
---|
313 | CHKLEN(size+1); |
---|
314 | orec->o_lines += countlines(s,size) - 1; |
---|
315 | Copy(s,d,size,char); |
---|
316 | d += size; |
---|
317 | if (size && s[size-1] != '\n') { |
---|
318 | *d++ = '\n'; |
---|
319 | orec->o_lines++; |
---|
320 | } |
---|
321 | linebeg = fcmd->f_next; |
---|
322 | break; |
---|
323 | case F_DECIMAL: { |
---|
324 | double value; |
---|
325 | |
---|
326 | (void)eval(fcmd->f_expr,G_SCALAR,sp); |
---|
327 | str = stack->ary_array[sp+1]; |
---|
328 | size = fcmd->f_size; |
---|
329 | CHKLEN(size+1); |
---|
330 | /* If the field is marked with ^ and the value is undefined, |
---|
331 | blank it out. */ |
---|
332 | if ((fcmd->f_flags & FC_CHOP) && !str->str_pok && !str->str_nok) { |
---|
333 | while (size) { |
---|
334 | size--; |
---|
335 | *d++ = ' '; |
---|
336 | } |
---|
337 | break; |
---|
338 | } |
---|
339 | blank = FALSE; |
---|
340 | value = str_gnum(str); |
---|
341 | if (fcmd->f_flags & FC_DP) { |
---|
342 | sprintf(d, "%#*.*f", size, fcmd->f_decimals, value); |
---|
343 | } else { |
---|
344 | sprintf(d, "%*.0f", size, value); |
---|
345 | } |
---|
346 | d += size; |
---|
347 | break; |
---|
348 | } |
---|
349 | } |
---|
350 | } |
---|
351 | CHKLEN(1); |
---|
352 | *d++ = '\0'; |
---|
353 | } |
---|
354 | |
---|
355 | static int |
---|
356 | countlines(s,size) |
---|
357 | register char *s; |
---|
358 | register int size; |
---|
359 | { |
---|
360 | register int count = 0; |
---|
361 | |
---|
362 | while (size--) { |
---|
363 | if (*s++ == '\n') |
---|
364 | count++; |
---|
365 | } |
---|
366 | return count; |
---|
367 | } |
---|
368 | |
---|
369 | void |
---|
370 | do_write(orec,stab,sp) |
---|
371 | struct outrec *orec; |
---|
372 | STAB *stab; |
---|
373 | int sp; |
---|
374 | { |
---|
375 | register STIO *stio = stab_io(stab); |
---|
376 | FILE *ofp = stio->ofp; |
---|
377 | |
---|
378 | #ifdef DEBUGGING |
---|
379 | if (debug & 256) |
---|
380 | fprintf(stderr,"left=%ld, todo=%ld\n", |
---|
381 | (long)stio->lines_left, (long)orec->o_lines); |
---|
382 | #endif |
---|
383 | if (stio->lines_left < orec->o_lines) { |
---|
384 | if (!stio->top_stab) { |
---|
385 | STAB *topstab; |
---|
386 | char tmpbuf[256]; |
---|
387 | |
---|
388 | if (!stio->top_name) { |
---|
389 | if (!stio->fmt_name) |
---|
390 | stio->fmt_name = savestr(stab_name(stab)); |
---|
391 | sprintf(tmpbuf, "%s_TOP", stio->fmt_name); |
---|
392 | topstab = stabent(tmpbuf,FALSE); |
---|
393 | if (topstab && stab_form(topstab)) |
---|
394 | stio->top_name = savestr(tmpbuf); |
---|
395 | else |
---|
396 | stio->top_name = savestr("top"); |
---|
397 | } |
---|
398 | topstab = stabent(stio->top_name,FALSE); |
---|
399 | if (!topstab || !stab_form(topstab)) { |
---|
400 | stio->lines_left = 100000000; |
---|
401 | goto forget_top; |
---|
402 | } |
---|
403 | stio->top_stab = topstab; |
---|
404 | } |
---|
405 | if (stio->lines_left >= 0 && stio->page > 0) |
---|
406 | fwrite(formfeed->str_ptr, formfeed->str_cur, 1, ofp); |
---|
407 | stio->lines_left = stio->page_len; |
---|
408 | stio->page++; |
---|
409 | format(&toprec,stab_form(stio->top_stab),sp); |
---|
410 | fputs(toprec.o_str,ofp); |
---|
411 | stio->lines_left -= toprec.o_lines; |
---|
412 | } |
---|
413 | forget_top: |
---|
414 | fputs(orec->o_str,ofp); |
---|
415 | stio->lines_left -= orec->o_lines; |
---|
416 | } |
---|