BSD 4_4_Lite2 development
[unix-history] / usr / src / contrib / perl-4.036 / form.c
CommitLineData
ca2dddd6
C
1/* $RCSfile: form.c,v $$Revision: 4.0.1.4 $$Date: 1993/02/05 19:34:32 $
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.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}