home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / PERL4036.ZIP / form.c < prev    next >
C/C++ Source or Header  |  1993-02-08  |  10KB  |  417 lines

  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.  
  36. static int countlines();
  37.  
  38. void
  39. form_parseargs(fcmd)
  40. register 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.  
  82. int newsize;
  83.  
  84. #define CHKLEN(allow) \
  85. newsize = (d - orec->o_str) + (allow); \
  86. if (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.  
  93. void
  94. format(orec,fcmd,sp)
  95. register struct outrec *orec;
  96. register FCMD *fcmd;
  97. int 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.  
  355. static int
  356. countlines(s,size)
  357. register char *s;
  358. register int size;
  359. {
  360.     register int count = 0;
  361.  
  362.     while (size--) {
  363.     if (*s++ == '\n')
  364.         count++;
  365.     }
  366.     return count;
  367. }
  368.  
  369. void
  370. do_write(orec,stab,sp)
  371. struct outrec *orec;
  372. STAB *stab;
  373. int 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. }
  417.