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