perl 3.0: (no announcement message available)
[p5sagit/p5-mst-13.2.git] / form.c
1 /* $Header: form.c,v 3.0 89/10/18 15:17:26 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  89/10/18  15:17:26  lwall
10  * 3.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 = line;
29     int oldsave = savestack->ary_fill;
30
31     str = fcmd->f_unparsed;
32     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     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                     }
110                     else
111                         linebeg = fcmd->f_next;
112                 }
113                 *d++ = *s++;
114             }
115         }
116         if (fcmd->f_unparsed)
117             form_parseargs(fcmd);
118         switch (fcmd->f_type) {
119         case F_NULL:
120             orec->o_lines++;
121             break;
122         case F_LEFT:
123             (void)eval(fcmd->f_expr,G_SCALAR,sp);
124             str = stack->ary_array[sp+1];
125             s = str_get(str);
126             size = fcmd->f_size;
127             CHKLEN(size);
128             chophere = Nullch;
129             while (size && *s && *s != '\n') {
130                 if (*s == '\t')
131                     *s = ' ';
132                 size--;
133                 if (*s && index(chopset,(*d++ = *s++)))
134                     chophere = s;
135                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
136                     *s = ' ';
137             }
138             if (size)
139                 chophere = s;
140             else if (chophere && chophere < s && *s && index(chopset,*s))
141                 chophere = s;
142             if (fcmd->f_flags & FC_CHOP) {
143                 if (!chophere)
144                     chophere = s;
145                 size += (s - chophere);
146                 d -= (s - chophere);
147                 if (fcmd->f_flags & FC_MORE &&
148                   *chophere && strNE(chophere,"\n")) {
149                     while (size < 3) {
150                         d--;
151                         size++;
152                     }
153                     while (d[-1] == ' ' && size < fcmd->f_size) {
154                         d--;
155                         size++;
156                     }
157                     *d++ = '.';
158                     *d++ = '.';
159                     *d++ = '.';
160                 }
161                 while (*chophere && index(chopset,*chophere))
162                     chophere++;
163                 str_chop(str,chophere);
164             }
165             if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
166                 size = 0;                       /* no spaces before newline */
167             while (size) {
168                 size--;
169                 *d++ = ' ';
170             }
171             break;
172         case F_RIGHT:
173             (void)eval(fcmd->f_expr,G_SCALAR,sp);
174             str = stack->ary_array[sp+1];
175             t = s = str_get(str);
176             size = fcmd->f_size;
177             CHKLEN(size);
178             chophere = Nullch;
179             while (size && *s && *s != '\n') {
180                 if (*s == '\t')
181                     *s = ' ';
182                 size--;
183                 if (*s && index(chopset,*s++))
184                     chophere = s;
185                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
186                     *s = ' ';
187             }
188             if (size)
189                 chophere = s;
190             else if (chophere && chophere < s && *s && index(chopset,*s))
191                 chophere = s;
192             if (fcmd->f_flags & FC_CHOP) {
193                 if (!chophere)
194                     chophere = s;
195                 size += (s - chophere);
196                 s = chophere;
197                 while (*chophere && index(chopset,*chophere))
198                     chophere++;
199             }
200             tmpchar = *s;
201             *s = '\0';
202             while (size) {
203                 size--;
204                 *d++ = ' ';
205             }
206             size = s - t;
207             (void)bcopy(t,d,size);
208             d += size;
209             *s = tmpchar;
210             if (fcmd->f_flags & FC_CHOP)
211                 str_chop(str,chophere);
212             break;
213         case F_CENTER: {
214             int halfsize;
215
216             (void)eval(fcmd->f_expr,G_SCALAR,sp);
217             str = stack->ary_array[sp+1];
218             t = s = str_get(str);
219             size = fcmd->f_size;
220             CHKLEN(size);
221             chophere = Nullch;
222             while (size && *s && *s != '\n') {
223                 if (*s == '\t')
224                     *s = ' ';
225                 size--;
226                 if (*s && index(chopset,*s++))
227                     chophere = s;
228                 if (*s == '\n' && (fcmd->f_flags & FC_CHOP))
229                     *s = ' ';
230             }
231             if (size)
232                 chophere = s;
233             else if (chophere && chophere < s && *s && index(chopset,*s))
234                 chophere = s;
235             if (fcmd->f_flags & FC_CHOP) {
236                 if (!chophere)
237                     chophere = s;
238                 size += (s - chophere);
239                 s = chophere;
240                 while (*chophere && index(chopset,*chophere))
241                     chophere++;
242             }
243             tmpchar = *s;
244             *s = '\0';
245             halfsize = size / 2;
246             while (size > halfsize) {
247                 size--;
248                 *d++ = ' ';
249             }
250             size = s - t;
251             (void)bcopy(t,d,size);
252             d += size;
253             *s = tmpchar;
254             if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
255                 size = 0;                       /* no spaces before newline */
256             else
257                 size = halfsize;
258             while (size) {
259                 size--;
260                 *d++ = ' ';
261             }
262             if (fcmd->f_flags & FC_CHOP)
263                 str_chop(str,chophere);
264             break;
265         }
266         case F_LINES:
267             (void)eval(fcmd->f_expr,G_SCALAR,sp);
268             str = stack->ary_array[sp+1];
269             s = str_get(str);
270             size = str_len(str);
271             CHKLEN(size);
272             orec->o_lines += countlines(s);
273             (void)bcopy(s,d,size);
274             d += size;
275             linebeg = fcmd->f_next;
276             break;
277         }
278     }
279     *d++ = '\0';
280 }
281
282 countlines(s)
283 register char *s;
284 {
285     register int count = 0;
286
287     while (*s) {
288         if (*s++ == '\n')
289             count++;
290     }
291     return count;
292 }
293
294 do_write(orec,stio,sp)
295 struct outrec *orec;
296 register STIO *stio;
297 int sp;
298 {
299     FILE *ofp = stio->ofp;
300
301 #ifdef DEBUGGING
302     if (debug & 256)
303         fprintf(stderr,"left=%ld, todo=%ld\n",
304           (long)stio->lines_left, (long)orec->o_lines);
305 #endif
306     if (stio->lines_left < orec->o_lines) {
307         if (!stio->top_stab) {
308             STAB *topstab;
309
310             if (!stio->top_name)
311                 stio->top_name = savestr("top");
312             topstab = stabent(stio->top_name,FALSE);
313             if (!topstab || !stab_form(topstab)) {
314                 stio->lines_left = 100000000;
315                 goto forget_top;
316             }
317             stio->top_stab = topstab;
318         }
319         if (stio->lines_left >= 0 && stio->page > 0)
320             (void)putc('\f',ofp);
321         stio->lines_left = stio->page_len;
322         stio->page++;
323         format(&toprec,stab_form(stio->top_stab),sp);
324         fputs(toprec.o_str,ofp);
325         stio->lines_left -= toprec.o_lines;
326     }
327   forget_top:
328     fputs(orec->o_str,ofp);
329     stio->lines_left -= orec->o_lines;
330 }