2b0553fbdb6557d5e09e9d9ffa46c51b928a1963
[p5sagit/p5-mst-13.2.git] / form.c
1 /* $Header: form.c,v 3.0.1.3 90/10/15 17:26:24 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.3  90/10/15  17:26:24  lwall
10  * patch29: added @###.## fields to format
11  * 
12  * Revision 3.0.1.2  90/08/09  03:38:40  lwall
13  * patch19: did preliminary work toward debugging packages and evals
14  * 
15  * Revision 3.0.1.1  90/02/28  17:39:34  lwall
16  * patch9: ... in format threw off subsequent field
17  * 
18  * Revision 3.0  89/10/18  15:17:26  lwall
19  * 3.0 baseline
20  * 
21  */
22
23 #include "EXTERN.h"
24 #include "perl.h"
25
26 /* Forms stuff */
27
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();
37     line_t oldline = curcmd->c_line;
38     int oldsave = savestack->ary_fill;
39
40     str = fcmd->f_unparsed;
41     curcmd->c_line = fcmd->f_line;
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");
67     curcmd->c_line = oldline;
68     Safefree(arg);
69     str_free(str);
70 }
71
72 int newsize;
73
74 #define CHKLEN(allow) \
75 newsize = (d - orec->o_str) + (allow); \
76 if (newsize >= curlen) { \
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
83 format(orec,fcmd,sp)
84 register struct outrec *orec;
85 register FCMD *fcmd;
86 int sp;
87 {
88     register char *d = orec->o_str;
89     register char *s;
90     register int curlen = orec->o_len - 2;
91     register int size;
92     FCMD *nextfcmd;
93     FCMD *linebeg = fcmd;
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;
102     for (; fcmd; fcmd = nextfcmd) {
103         nextfcmd = fcmd->f_next;
104         CHKLEN(fcmd->f_presize);
105         if (s = fcmd->f_pre) {
106             while (*s) {
107                 if (*s == '\n') {
108                     while (d > orec->o_str && (d[-1] == ' ' || d[-1] == '\t'))
109                         d--;
110                     if (fcmd->f_flags & FC_NOBLANK) {
111                         if (d == orec->o_str || d[-1] == '\n') {
112                             orec->o_lines--;    /* don't print blank line */
113                             linebeg = fcmd->f_next;
114                             break;
115                         }
116                         else if (fcmd->f_flags & FC_REPEAT)
117                             nextfcmd = linebeg;
118                     }
119                     else
120                         linebeg = fcmd->f_next;
121                 }
122                 *d++ = *s++;
123             }
124         }
125         if (fcmd->f_unparsed)
126             form_parseargs(fcmd);
127         switch (fcmd->f_type) {
128         case F_NULL:
129             orec->o_lines++;
130             break;
131         case F_LEFT:
132             (void)eval(fcmd->f_expr,G_SCALAR,sp);
133             str = stack->ary_array[sp+1];
134             s = str_get(str);
135             size = fcmd->f_size;
136             CHKLEN(size);
137             chophere = Nullch;
138             while (size && *s && *s != '\n') {
139                 if (*s == '\t')
140                     *s = ' ';
141                 size--;
142                 if (*s && index(chopset,(*d++ = *s++)))
143                     chophere = s;
144                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
145                     *s = ' ';
146             }
147             if (size)
148                 chophere = s;
149             else if (chophere && chophere < s && *s && index(chopset,*s))
150                 chophere = s;
151             if (fcmd->f_flags & FC_CHOP) {
152                 if (!chophere)
153                     chophere = s;
154                 size += (s - chophere);
155                 d -= (s - chophere);
156                 if (fcmd->f_flags & FC_MORE &&
157                   *chophere && strNE(chophere,"\n")) {
158                     while (size < 3) {
159                         d--;
160                         size++;
161                     }
162                     while (d[-1] == ' ' && size < fcmd->f_size) {
163                         d--;
164                         size++;
165                     }
166                     *d++ = '.';
167                     *d++ = '.';
168                     *d++ = '.';
169                     size -= 3;
170                 }
171                 while (*chophere && index(chopset,*chophere))
172                     chophere++;
173                 str_chop(str,chophere);
174             }
175             if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
176                 size = 0;                       /* no spaces before newline */
177             while (size) {
178                 size--;
179                 *d++ = ' ';
180             }
181             break;
182         case F_RIGHT:
183             (void)eval(fcmd->f_expr,G_SCALAR,sp);
184             str = stack->ary_array[sp+1];
185             t = s = str_get(str);
186             size = fcmd->f_size;
187             CHKLEN(size);
188             chophere = Nullch;
189             while (size && *s && *s != '\n') {
190                 if (*s == '\t')
191                     *s = ' ';
192                 size--;
193                 if (*s && index(chopset,*s++))
194                     chophere = s;
195                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
196                     *s = ' ';
197             }
198             if (size)
199                 chophere = s;
200             else if (chophere && chophere < s && *s && index(chopset,*s))
201                 chophere = s;
202             if (fcmd->f_flags & FC_CHOP) {
203                 if (!chophere)
204                     chophere = s;
205                 size += (s - chophere);
206                 s = chophere;
207                 while (*chophere && index(chopset,*chophere))
208                     chophere++;
209             }
210             tmpchar = *s;
211             *s = '\0';
212             while (size) {
213                 size--;
214                 *d++ = ' ';
215             }
216             size = s - t;
217             (void)bcopy(t,d,size);
218             d += size;
219             *s = tmpchar;
220             if (fcmd->f_flags & FC_CHOP)
221                 str_chop(str,chophere);
222             break;
223         case F_CENTER: {
224             int halfsize;
225
226             (void)eval(fcmd->f_expr,G_SCALAR,sp);
227             str = stack->ary_array[sp+1];
228             t = s = str_get(str);
229             size = fcmd->f_size;
230             CHKLEN(size);
231             chophere = Nullch;
232             while (size && *s && *s != '\n') {
233                 if (*s == '\t')
234                     *s = ' ';
235                 size--;
236                 if (*s && index(chopset,*s++))
237                     chophere = s;
238                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
239                     *s = ' ';
240             }
241             if (size)
242                 chophere = s;
243             else if (chophere && chophere < s && *s && index(chopset,*s))
244                 chophere = s;
245             if (fcmd->f_flags & FC_CHOP) {
246                 if (!chophere)
247                     chophere = s;
248                 size += (s - chophere);
249                 s = chophere;
250                 while (*chophere && index(chopset,*chophere))
251                     chophere++;
252             }
253             tmpchar = *s;
254             *s = '\0';
255             halfsize = size / 2;
256             while (size > halfsize) {
257                 size--;
258                 *d++ = ' ';
259             }
260             size = s - t;
261             (void)bcopy(t,d,size);
262             d += size;
263             *s = tmpchar;
264             if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
265                 size = 0;                       /* no spaces before newline */
266             else
267                 size = halfsize;
268             while (size) {
269                 size--;
270                 *d++ = ' ';
271             }
272             if (fcmd->f_flags & FC_CHOP)
273                 str_chop(str,chophere);
274             break;
275         }
276         case F_LINES:
277             (void)eval(fcmd->f_expr,G_SCALAR,sp);
278             str = stack->ary_array[sp+1];
279             s = str_get(str);
280             size = str_len(str);
281             CHKLEN(size);
282             orec->o_lines += countlines(s);
283             (void)bcopy(s,d,size);
284             d += size;
285             linebeg = fcmd->f_next;
286             break;
287         case F_DECIMAL: {
288             double value;
289
290             (void)eval(fcmd->f_expr,G_SCALAR,sp);
291             str = stack->ary_array[sp+1];
292             /* If the field is marked with ^ and the value is undefined,
293                blank it out. */
294             if ((fcmd->f_flags & FC_CHOP) && !str->str_pok && !str->str_nok) {
295                 while (size) {
296                     size--;
297                     *d++ = ' ';
298                 }
299                 break;
300             }
301             value = str_gnum(str);
302             size = fcmd->f_size;
303             CHKLEN(size);
304             if (fcmd->f_flags & FC_DP) {
305                 sprintf(d, "%#*.*f", size, fcmd->f_decimals, value);
306             } else {
307                 sprintf(d, "%*.0f", size, value);
308             }
309             d += size;
310             break;
311         }
312         }
313     }
314     CHKLEN(1);
315     *d++ = '\0';
316 }
317
318 countlines(s)
319 register char *s;
320 {
321     register int count = 0;
322
323     while (*s) {
324         if (*s++ == '\n')
325             count++;
326     }
327     return count;
328 }
329
330 do_write(orec,stio,sp)
331 struct outrec *orec;
332 register STIO *stio;
333 int sp;
334 {
335     FILE *ofp = stio->ofp;
336
337 #ifdef DEBUGGING
338     if (debug & 256)
339         fprintf(stderr,"left=%ld, todo=%ld\n",
340           (long)stio->lines_left, (long)orec->o_lines);
341 #endif
342     if (stio->lines_left < orec->o_lines) {
343         if (!stio->top_stab) {
344             STAB *topstab;
345
346             if (!stio->top_name)
347                 stio->top_name = savestr("top");
348             topstab = stabent(stio->top_name,FALSE);
349             if (!topstab || !stab_form(topstab)) {
350                 stio->lines_left = 100000000;
351                 goto forget_top;
352             }
353             stio->top_stab = topstab;
354         }
355         if (stio->lines_left >= 0 && stio->page > 0)
356             (void)putc('\f',ofp);
357         stio->lines_left = stio->page_len;
358         stio->page++;
359         format(&toprec,stab_form(stio->top_stab),sp);
360         fputs(toprec.o_str,ofp);
361         stio->lines_left -= toprec.o_lines;
362     }
363   forget_top:
364     fputs(orec->o_str,ofp);
365     stio->lines_left -= orec->o_lines;
366 }