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