/* $Header: form.c,v 1.0 87/12/18 13:05:07 root Exp $
 *
 * $Log:	form.c,v $
 * Revision 1.0  87/12/18  13:05:07  root
 * Initial revision
 * 
 */

#include "handy.h"
#include "EXTERN.h"
#include "search.h"
#include "util.h"
#include "perl.h"

/* Forms stuff */

#define CHKLEN(allow) \
if (d - orec->o_str + (allow) >= curlen) { \
    curlen = d - orec->o_str; \
    GROWSTR(&orec->o_str,&orec->o_len,orec->o_len + (allow)); \
    d = orec->o_str + curlen;	/* in case it moves */ \
    curlen = orec->o_len - 2; \
}

format(orec,fcmd)
register struct outrec *orec;
register FCMD *fcmd;
{
    register char *d = orec->o_str;
    register char *s;
    register int curlen = orec->o_len - 2;
    register int size;
    char tmpchar;
    char *t;
    CMD mycmd;
    STR *str;
    char *chophere;

    mycmd.c_type = C_NULL;
    orec->o_lines = 0;
    for (; fcmd; fcmd = fcmd->f_next) {
	CHKLEN(fcmd->f_presize);
	for (s=fcmd->f_pre; *s;) {
	    if (*s == '\n') {
		while (d > orec->o_str && (d[-1] == ' ' || d[-1] == '\t'))
		    d--;
		if (fcmd->f_flags & FC_NOBLANK &&
		  (d == orec->o_str || d[-1] == '\n') ) {
		    orec->o_lines--;		/* don't print blank line */
		    break;
		}
	    }
	    *d++ = *s++;
	}
	switch (fcmd->f_type) {
	case F_NULL:
	    orec->o_lines++;
	    break;
	case F_LEFT:
	    str = eval(fcmd->f_expr,Null(char***),(double*)0);
	    s = str_get(str);
	    size = fcmd->f_size;
	    CHKLEN(size);
	    chophere = Nullch;
	    while (size && *s && *s != '\n') {
		size--;
		if ((*d++ = *s++) == ' ')
		    chophere = s;
	    }
	    if (size)
		chophere = s;
	    if (fcmd->f_flags & FC_CHOP) {
		if (!chophere)
		    chophere = s;
		size += (s - chophere);
		d -= (s - chophere);
		if (fcmd->f_flags & FC_MORE &&
		  *chophere && strNE(chophere,"\n")) {
		    while (size < 3) {
			d--;
			size++;
		    }
		    while (d[-1] == ' ' && size < fcmd->f_size) {
			d--;
			size++;
		    }
		    *d++ = '.';
		    *d++ = '.';
		    *d++ = '.';
		}
		s = chophere;
		while (*chophere == ' ' || *chophere == '\n')
			chophere++;
		str_chop(str,chophere);
	    }
	    if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
		size = 0;			/* no spaces before newline */
	    while (size) {
		size--;
		*d++ = ' ';
	    }
	    break;
	case F_RIGHT:
	    t = s = str_get(eval(fcmd->f_expr,Null(char***),(double*)0));
	    size = fcmd->f_size;
	    CHKLEN(size);
	    chophere = Nullch;
	    while (size && *s && *s != '\n') {
		size--;
		if (*s++ == ' ')
			chophere = s;
	    }
	    if (size)
		chophere = s;
	    if (fcmd->f_flags & FC_CHOP) {
		if (!chophere)
		    chophere = s;
		size += (s - chophere);
		d -= (s - chophere);
		if (fcmd->f_flags & FC_MORE &&
		  *chophere && strNE(chophere,"\n")) {
		    while (size < 3) {
			d--;
			size++;
		    }
		    while (d[-1] == ' ' && size < fcmd->f_size) {
			d--;
			size++;
		    }
		    *d++ = '.';
		    *d++ = '.';
		    *d++ = '.';
		}
		s = chophere;
		while (*chophere == ' ' || *chophere == '\n')
			chophere++;
		str_chop(str,chophere);
	    }
	    tmpchar = *s;
	    *s = '\0';
	    while (size) {
		size--;
		*d++ = ' ';
	    }
	    size = s - t;
	    bcopy(t,d,size);
	    d += size;
	    *s = tmpchar;
	    break;
	case F_CENTER: {
	    int halfsize;

	    t = s = str_get(eval(fcmd->f_expr,Null(char***),(double*)0));
	    size = fcmd->f_size;
	    CHKLEN(size);
	    chophere = Nullch;
	    while (size && *s && *s != '\n') {
		size--;
		if (*s++ == ' ')
			chophere = s;
	    }
	    if (size)
		chophere = s;
	    if (fcmd->f_flags & FC_CHOP) {
		if (!chophere)
		    chophere = s;
		size += (s - chophere);
		d -= (s - chophere);
		if (fcmd->f_flags & FC_MORE &&
		  *chophere && strNE(chophere,"\n")) {
		    while (size < 3) {
			d--;
			size++;
		    }
		    while (d[-1] == ' ' && size < fcmd->f_size) {
			d--;
			size++;
		    }
		    *d++ = '.';
		    *d++ = '.';
		    *d++ = '.';
		}
		s = chophere;
		while (*chophere == ' ' || *chophere == '\n')
			chophere++;
		str_chop(str,chophere);
	    }
	    tmpchar = *s;
	    *s = '\0';
	    halfsize = size / 2;
	    while (size > halfsize) {
		size--;
		*d++ = ' ';
	    }
	    size = s - t;
	    bcopy(t,d,size);
	    d += size;
	    *s = tmpchar;
	    if (fcmd->f_next && fcmd->f_next->f_pre[0] == '\n')
		size = 0;			/* no spaces before newline */
	    else
		size = halfsize;
	    while (size) {
		size--;
		*d++ = ' ';
	    }
	    break;
	}
	case F_LINES:
	    str = eval(fcmd->f_expr,Null(char***),(double*)0);
	    s = str_get(str);
	    size = str_len(str);
	    CHKLEN(size);
	    orec->o_lines += countlines(s);
	    bcopy(s,d,size);
	    d += size;
	    break;
	}
    }
    *d++ = '\0';
}

countlines(s)
register char *s;
{
    register int count = 0;

    while (*s) {
	if (*s++ == '\n')
	    count++;
    }
    return count;
}

do_write(orec,stio)
struct outrec *orec;
register STIO *stio;
{
    FILE *ofp = stio->fp;

#ifdef DEBUGGING
    if (debug & 256)
	fprintf(stderr,"left=%d, todo=%d\n",stio->lines_left, orec->o_lines);
#endif
    if (stio->lines_left < orec->o_lines) {
	if (!stio->top_stab) {
	    STAB *topstab;

	    if (!stio->top_name)
		stio->top_name = savestr("top");
	    topstab = stabent(stio->top_name,FALSE);
	    if (!topstab || !topstab->stab_form) {
		stio->lines_left = 100000000;
		goto forget_top;
	    }
	    stio->top_stab = topstab;
	}
	if (stio->lines_left >= 0)
	    putc('\f',ofp);
	stio->lines_left = stio->page_len;
	stio->page++;
	format(&toprec,stio->top_stab->stab_form);
	fputs(toprec.o_str,ofp);
	stio->lines_left -= toprec.o_lines;
    }
  forget_top:
    fputs(orec->o_str,ofp);
    stio->lines_left -= orec->o_lines;
}
