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