perl 3.0 patch #43 patch #42, continued
[p5sagit/p5-mst-13.2.git] / form.c
CommitLineData
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 32void
33form_parseargs(fcmd)
34register 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
76int newsize;
77
8d063cd8 78#define CHKLEN(allow) \
a687059c 79newsize = (d - orec->o_str) + (allow); \
80if (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 87format(orec,fcmd,sp)
8d063cd8 88register struct outrec *orec;
89register FCMD *fcmd;
a687059c 90int 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 326countlines(s,size)
8d063cd8 327register char *s;
c623bd54 328register 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 339do_write(orec,stio,sp)
8d063cd8 340struct outrec *orec;
341register STIO *stio;
a687059c 342int 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}