This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
perl 3.0 patch #24 patch #19, continued
[perl5.git] / form.c
1 /* $Header: form.c,v 3.0.1.2 90/08/09 03:38:40 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.2  90/08/09  03:38:40  lwall
10  * patch19: did preliminary work toward debugging packages and evals
11  * 
12  * Revision 3.0.1.1  90/02/28  17:39:34  lwall
13  * patch9: ... in format threw off subsequent field
14  * 
15  * Revision 3.0  89/10/18  15:17:26  lwall
16  * 3.0 baseline
17  * 
18  */
19
20 #include "EXTERN.h"
21 #include "perl.h"
22
23 /* Forms stuff */
24
25 void
26 form_parseargs(fcmd)
27 register FCMD *fcmd;
28 {
29     register int i;
30     register ARG *arg;
31     register int items;
32     STR *str;
33     ARG *parselist();
34     line_t oldline = curcmd->c_line;
35     int oldsave = savestack->ary_fill;
36
37     str = fcmd->f_unparsed;
38     curcmd->c_line = fcmd->f_line;
39     fcmd->f_unparsed = Nullstr;
40     (void)savehptr(&curstash);
41     curstash = str->str_u.str_hash;
42     arg = parselist(str);
43     restorelist(oldsave);
44
45     items = arg->arg_len - 1;   /* ignore $$ on end */
46     for (i = 1; i <= items; i++) {
47         if (!fcmd || fcmd->f_type == F_NULL)
48             fatal("Too many field values");
49         dehoist(arg,i);
50         fcmd->f_expr = make_op(O_ITEM,1,
51           arg[i].arg_ptr.arg_arg,Nullarg,Nullarg);
52         if (fcmd->f_flags & FC_CHOP) {
53             if ((fcmd->f_expr[1].arg_type & A_MASK) == A_STAB)
54                 fcmd->f_expr[1].arg_type = A_LVAL;
55             else if ((fcmd->f_expr[1].arg_type & A_MASK) == A_EXPR)
56                 fcmd->f_expr[1].arg_type = A_LEXPR;
57             else
58                 fatal("^ field requires scalar lvalue");
59         }
60         fcmd = fcmd->f_next;
61     }
62     if (fcmd && fcmd->f_type)
63         fatal("Not enough field values");
64     curcmd->c_line = oldline;
65     Safefree(arg);
66     str_free(str);
67 }
68
69 int newsize;
70
71 #define CHKLEN(allow) \
72 newsize = (d - orec->o_str) + (allow); \
73 if (newsize >= curlen) { \
74     curlen = d - orec->o_str; \
75     GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \
76     d = orec->o_str + curlen;   /* in case it moves */ \
77     curlen = orec->o_len - 2; \
78 }
79
80 format(orec,fcmd,sp)
81 register struct outrec *orec;
82 register FCMD *fcmd;
83 int sp;
84 {
85     register char *d = orec->o_str;
86     register char *s;
87     register int curlen = orec->o_len - 2;
88     register int size;
89     FCMD *nextfcmd;
90     FCMD *linebeg = fcmd;
91     char tmpchar;
92     char *t;
93     CMD mycmd;
94     STR *str;
95     char *chophere;
96
97     mycmd.c_type = C_NULL;
98     orec->o_lines = 0;
99     for (; fcmd; fcmd = nextfcmd) {
100         nextfcmd = fcmd->f_next;
101         CHKLEN(fcmd->f_presize);
102         if (s = fcmd->f_pre) {
103             while (*s) {
104                 if (*s == '\n') {
105                     while (d > orec->o_str && (d[-1] == ' ' || d[-1] == '\t'))
106                         d--;
107                     if (fcmd->f_flags & FC_NOBLANK) {
108                         if (d == orec->o_str || d[-1] == '\n') {
109                             orec->o_lines--;    /* don't print blank line */
110                             linebeg = fcmd->f_next;
111                             break;
112                         }
113                         else if (fcmd->f_flags & FC_REPEAT)
114                             nextfcmd = linebeg;
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);
279             orec->o_lines += countlines(s);
280             (void)bcopy(s,d,size);
281             d += size;
282             linebeg = fcmd->f_next;
283             break;
284         }
285     }
286     CHKLEN(1);
287     *d++ = '\0';
288 }
289
290 countlines(s)
291 register char *s;
292 {
293     register int count = 0;
294
295     while (*s) {
296         if (*s++ == '\n')
297             count++;
298     }
299     return count;
300 }
301
302 do_write(orec,stio,sp)
303 struct outrec *orec;
304 register STIO *stio;
305 int sp;
306 {
307     FILE *ofp = stio->ofp;
308
309 #ifdef DEBUGGING
310     if (debug & 256)
311         fprintf(stderr,"left=%ld, todo=%ld\n",
312           (long)stio->lines_left, (long)orec->o_lines);
313 #endif
314     if (stio->lines_left < orec->o_lines) {
315         if (!stio->top_stab) {
316             STAB *topstab;
317
318             if (!stio->top_name)
319                 stio->top_name = savestr("top");
320             topstab = stabent(stio->top_name,FALSE);
321             if (!topstab || !stab_form(topstab)) {
322                 stio->lines_left = 100000000;
323                 goto forget_top;
324             }
325             stio->top_stab = topstab;
326         }
327         if (stio->lines_left >= 0 && stio->page > 0)
328             (void)putc('\f',ofp);
329         stio->lines_left = stio->page_len;
330         stio->page++;
331         format(&toprec,stab_form(stio->top_stab),sp);
332         fputs(toprec.o_str,ofp);
333         stio->lines_left -= toprec.o_lines;
334     }
335   forget_top:
336     fputs(orec->o_str,ofp);
337     stio->lines_left -= orec->o_lines;
338 }