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