source: trunk/third/perl/form.c @ 9009

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