perl 3.0 patch #43 patch #42, continued
[p5sagit/p5-mst-13.2.git] / form.c
1 /* $Header: form.c,v 3.0.1.4 91/01/11 18:04:07 lwall Locked $
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.
7  *
8  * $Log:        form.c,v $
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  * 
13  * Revision 3.0.1.3  90/10/15  17:26:24  lwall
14  * patch29: added @###.## fields to format
15  * 
16  * Revision 3.0.1.2  90/08/09  03:38:40  lwall
17  * patch19: did preliminary work toward debugging packages and evals
18  * 
19  * Revision 3.0.1.1  90/02/28  17:39:34  lwall
20  * patch9: ... in format threw off subsequent field
21  * 
22  * Revision 3.0  89/10/18  15:17:26  lwall
23  * 3.0 baseline
24  * 
25  */
26
27 #include "EXTERN.h"
28 #include "perl.h"
29
30 /* Forms stuff */
31
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();
41     line_t oldline = curcmd->c_line;
42     int oldsave = savestack->ary_fill;
43
44     str = fcmd->f_unparsed;
45     curcmd->c_line = fcmd->f_line;
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");
71     curcmd->c_line = oldline;
72     Safefree(arg);
73     str_free(str);
74 }
75
76 int newsize;
77
78 #define CHKLEN(allow) \
79 newsize = (d - orec->o_str) + (allow); \
80 if (newsize >= curlen) { \
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
87 format(orec,fcmd,sp)
88 register struct outrec *orec;
89 register FCMD *fcmd;
90 int sp;
91 {
92     register char *d = orec->o_str;
93     register char *s;
94     register int curlen = orec->o_len - 2;
95     register int size;
96     FCMD *nextfcmd;
97     FCMD *linebeg = fcmd;
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;
106     for (; fcmd; fcmd = nextfcmd) {
107         nextfcmd = fcmd->f_next;
108         CHKLEN(fcmd->f_presize);
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;
125                 }
126                 *d++ = *s++;
127             }
128         }
129         if (fcmd->f_unparsed)
130             form_parseargs(fcmd);
131         switch (fcmd->f_type) {
132         case F_NULL:
133             orec->o_lines++;
134             break;
135         case F_LEFT:
136             (void)eval(fcmd->f_expr,G_SCALAR,sp);
137             str = stack->ary_array[sp+1];
138             s = str_get(str);
139             size = fcmd->f_size;
140             CHKLEN(size);
141             chophere = Nullch;
142             while (size && *s && *s != '\n') {
143                 if (*s == '\t')
144                     *s = ' ';
145                 size--;
146                 if (*s && index(chopset,(*d++ = *s++)))
147                     chophere = s;
148                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
149                     *s = ' ';
150             }
151             if (size)
152                 chophere = s;
153             else if (chophere && chophere < s && *s && index(chopset,*s))
154                 chophere = s;
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++ = '.';
173                     size -= 3;
174                 }
175                 while (*chophere && index(chopset,*chophere))
176                     chophere++;
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:
187             (void)eval(fcmd->f_expr,G_SCALAR,sp);
188             str = stack->ary_array[sp+1];
189             t = s = str_get(str);
190             size = fcmd->f_size;
191             CHKLEN(size);
192             chophere = Nullch;
193             while (size && *s && *s != '\n') {
194                 if (*s == '\t')
195                     *s = ' ';
196                 size--;
197                 if (*s && index(chopset,*s++))
198                     chophere = s;
199                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
200                     *s = ' ';
201             }
202             if (size)
203                 chophere = s;
204             else if (chophere && chophere < s && *s && index(chopset,*s))
205                 chophere = s;
206             if (fcmd->f_flags & FC_CHOP) {
207                 if (!chophere)
208                     chophere = s;
209                 size += (s - chophere);
210                 s = chophere;
211                 while (*chophere && index(chopset,*chophere))
212                     chophere++;
213             }
214             tmpchar = *s;
215             *s = '\0';
216             while (size) {
217                 size--;
218                 *d++ = ' ';
219             }
220             size = s - t;
221             (void)bcopy(t,d,size);
222             d += size;
223             *s = tmpchar;
224             if (fcmd->f_flags & FC_CHOP)
225                 str_chop(str,chophere);
226             break;
227         case F_CENTER: {
228             int halfsize;
229
230             (void)eval(fcmd->f_expr,G_SCALAR,sp);
231             str = stack->ary_array[sp+1];
232             t = s = str_get(str);
233             size = fcmd->f_size;
234             CHKLEN(size);
235             chophere = Nullch;
236             while (size && *s && *s != '\n') {
237                 if (*s == '\t')
238                     *s = ' ';
239                 size--;
240                 if (*s && index(chopset,*s++))
241                     chophere = s;
242                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
243                     *s = ' ';
244             }
245             if (size)
246                 chophere = s;
247             else if (chophere && chophere < s && *s && index(chopset,*s))
248                 chophere = s;
249             if (fcmd->f_flags & FC_CHOP) {
250                 if (!chophere)
251                     chophere = s;
252                 size += (s - chophere);
253                 s = chophere;
254                 while (*chophere && index(chopset,*chophere))
255                     chophere++;
256             }
257             tmpchar = *s;
258             *s = '\0';
259             halfsize = size / 2;
260             while (size > halfsize) {
261                 size--;
262                 *d++ = ' ';
263             }
264             size = s - t;
265             (void)bcopy(t,d,size);
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             }
276             if (fcmd->f_flags & FC_CHOP)
277                 str_chop(str,chophere);
278             break;
279         }
280         case F_LINES:
281             (void)eval(fcmd->f_expr,G_SCALAR,sp);
282             str = stack->ary_array[sp+1];
283             s = str_get(str);
284             size = str_len(str);
285             CHKLEN(size+1);
286             orec->o_lines += countlines(s,size) - 1;
287             (void)bcopy(s,d,size);
288             d += size;
289             if (size && s[size-1] != '\n') {
290                 *d++ = '\n';
291                 orec->o_lines++;
292             }
293             linebeg = fcmd->f_next;
294             break;
295         case F_DECIMAL: {
296             double value;
297
298             (void)eval(fcmd->f_expr,G_SCALAR,sp);
299             str = stack->ary_array[sp+1];
300             size = fcmd->f_size;
301             CHKLEN(size);
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);
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         }
320         }
321     }
322     CHKLEN(1);
323     *d++ = '\0';
324 }
325
326 countlines(s,size)
327 register char *s;
328 register int size;
329 {
330     register int count = 0;
331
332     while (size--) {
333         if (*s++ == '\n')
334             count++;
335     }
336     return count;
337 }
338
339 do_write(orec,stio,sp)
340 struct outrec *orec;
341 register STIO *stio;
342 int sp;
343 {
344     FILE *ofp = stio->ofp;
345
346 #ifdef DEBUGGING
347     if (debug & 256)
348         fprintf(stderr,"left=%ld, todo=%ld\n",
349           (long)stio->lines_left, (long)orec->o_lines);
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);
358             if (!topstab || !stab_form(topstab)) {
359                 stio->lines_left = 100000000;
360                 goto forget_top;
361             }
362             stio->top_stab = topstab;
363         }
364         if (stio->lines_left >= 0 && stio->page > 0)
365             (void)putc('\f',ofp);
366         stio->lines_left = stio->page_len;
367         stio->page++;
368         format(&toprec,stab_form(stio->top_stab),sp);
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 }