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