/* **************************************************************************** * * Mnemonic: FMinit * Abstract: This routine opens the initial input file and the output file * and does other necessary house keeping chores. * Parms: argc - Number of arguments passed to fm from command line * argv - Argument vector list passed from command line * Returns: Valid if all is well, ERROR if system could not be initialized. * Date: 17 November 1988 * Author: E. Scott Daniels * * Modified: 22 Apr 1991 - To remove need to have dedicated page num buffer * 3 May 1991 - To initialize flags2 variable * 3 May 1992 - To convert for post script output * 7 Nov 1992 - To alloc header font buffers * 12 Nov 1992 - To add justify PS proc * 13 Nov 1992 - To allocate current font buffer before use * 10 Dec 1992 - To use AFIwrite for ansi compat on sun * 6 Apr 1993 - To create a dummy variable block for psuedo * commands generated by .gm and .gd commands. * 26 May 1993 - To add stroke command to box routine. * 13 Jun 1993 - To set the psfm variable by placing a dv command * into the initial input buffer. * 12 Jul 1993 - To set the def item list font ptr to null * 21 Feb 1994 - To open output file just "w" * To put out the PS routine rightxy for header/footer * 22 Feb 1994 - To init figure font (ffont) * 7 Apr 1994 - To seup for TOC now that linelen is points related * 7 Oct 2000 - To use new AFI tokeniser * 10 Oct 2001 - To add new justification PS functions * 13 Jan 2001 - Added sym table support * 08 Nov 2006 - Some cleanup and now allow default input from stdin. * 10 Apr 2007 - Memory leak cleanup * 16 Sep 2007 - added page geometry argument support * 13 Nov 2007 - Changed the imbed/run() mechanism to better support the * oneject processing. * 22 Mar 2011 - Correctly set boty when geometry (-g) is given. * 07 Jul 2013 - Changed initialisation of text colour to use setcolour. * 17 Jul 2016 - Bring decls into the modern world. ***************************************************************************** */ extern int FMinit( int argc, char **argv ) { int i; /* loop index */ char buf[1024]; char *ptr; /* pointer to argument */ char *ifname = "stdin"; char *ofname = "stdout"; int geomh = 0; /* geometry from -g hxw */ int geomw = 0; argc--; argv++; while( argc > 0 && argv[0][0] == '-' ) { switch( argv[0][1] ) { case 'g': geomh = atoi( argv[1] ) * 72; if( (ptr = strchr( argv[1], 'x' )) != NULL ) geomw = atoi( ptr + 1 ) * 72; argv++; argc--; break; case 't': trace = atoi( argv[1] ); argv++; argc--; break; case 'v': flags2 |= F2_NOISY; break; case '?': FMmsg( ERROR, "Usage: tfm [input-file [output-file [inital command tokens]]]" ); exit( 1 ); default: fprintf( stderr, "unrecognised option: %s\n", argv[0] ); exit( 1 ); } argv++; argc--; } if( argc >= 1 ) { if( *argv[0] != '-' ) /* allow - to default to stdin */ ifname = argv[0]; } if( argc > 1 ) { if( *argv[1] != '-' ) /* allow - to default to stdout */ ofname = argv[1]; } if( strcmp( ifname, ofname ) == 0 ) { FMmsg( ERROR, "input name cannot be same as output; this is just wrong"); return ERROR; } if( FMopen( ifname ) < VALID ) /* open the initial input file */ return ERROR; symtab = sym_alloc( 4999 ); /* symtab for variables */ AFIsettoken( fptr->file, symtab, " \t", '&', '^', ":" ); AFIsetflag( fptr->file, AFI_F_EOBSIG, AFI_SET ); /* end of buffer notifications */ #ifdef KEEP this is dropped because imbed now puts a run/stop command into the stream to pop the call to fmrun() at end of file AFIsetflag( fptr->file, AFI_F_EOFSIG, AFI_SET ); /* end of file notifications -- must have so .im file .cmd works */ #endif ofile = AFIopen( ofname, "w" ); /* open output file */ if( ofile < VALID ) { FMmsg( E_CANTOPEN, ofname ); FMclose( ); return ERROR; } version = "pfm V2.8/17243"; /* returned by .gv v command */ snprintf( buf, sizeof( buf ), "+PFM text formatter (%s) started", version ); FMmsg( -1, buf ); /* write out our postscript routines that make life easier */ snprintf( buf, sizeof( buf ), "%%! %s generated this postscript file\n", version ); AFIwrite( ofile, buf ); /*AFIwrite( ofile, "%! PFM 1.1-02282 PostScript output\n" );*/ /*AFIwrite( ofile, "% Copyright (c) 1994-2002 by E. Scott Daniels. All Rights Reserved!\n" );*/ AFIwrite( ofile, "% A happy programme is one that generates other programmes;\n" ); AFIwrite( ofile, "% This was generated by a happy programme!\n" ); boty = (10 * 71); /* default to 11" page with a 1" bottom margin */ if( cury <= 0 ) cury = topy = 71; /* default to 1" top margin */ if( top_gutter <= 0 ) top_gutter = cury/2; // space above first line for running matter pagew = MAX_X; pageh = MAX_Y; AFIwrite( ofile, "%these functions are Copyright (c) 2001-2013 by E. Scott Daniels. All Rights Reserved!\n" ); /* new page macro to showpage and set the origion of the 0,0 */ if( geomh ) { pagew = geomw; /* override defaults with user setting */ pageh = geomh; AFIwrite( ofile, "%%BeginSetup\n" ); AFIwrite( ofile, "mark {\n" ); AFIwrite( ofile, "%BeginFeature: *PageRegion C\n" ); snprintf( buf, sizeof( buf ), "<</PageSize [%d %d]>> setpagedevice\n", pagew, pageh ); AFIwrite( ofile, buf ); AFIwrite( ofile, "%EndFeature\n" ); AFIwrite( ofile, "} stopped cleartomark\n" ); AFIwrite( ofile, "%%EndSetup\n" ); snprintf( buf, sizeof( buf ), "/xlate {0 %d translate} def\n/newp {showpage xlate} def\n", pageh ); AFIwrite( ofile, buf ); boty = pageh - 42; /* adjust botom y based on geometry */ } else AFIwrite( ofile, "/xlate {0 792 translate} def\n/newp {showpage xlate} def\n" ); /* the remainder of the native ps that we dump on initialisation is in init.ps which is parsed and compressed by a mk rule and put into init_ps.c */ #include "init_ps.c" /* easier to manage postscript functions we need */ /* now initialize from a C point of view */ difont = NULL; /* initially no def list item font string defined */ ffont = NULL; /* no figure font defined */ //textcolour = strdup( "000000" ); FMsetcolour( "#000000" ); /* default to black */ curfont = strdup( DEF_TEXTFONT ); runfont = strdup( DEF_RUNFONT ); FMfmt_add( ); textspace = 2; iptr = 0; optr = 0; /* start at beginning of the output buffer */ obuf = (char *) malloc( sizeof( char ) * 2048 ); inbuf = (char *) malloc( sizeof( char ) * 2048 ); if( ! obuf || ! inbuf ) { fprintf( stderr, "malloc of obuffer failed\n" ); return ERROR; } *obuf = (char) 0; sprintf( inbuf, ".dv pfm 1 : " ); /* simulate a user command - define compiler name */ AFIpushtoken( fptr->file, inbuf ); /* and push onto the input stack */ if( (path = getenv( "PFM_PATH" )) == NULL ) path = getenv( "XFM_PATH" ); cur_col = firstcol = (struct col_blk *) malloc( sizeof( struct col_blk ) ); if( cur_col == NULL ) return ERROR; cur_col->lmar = DEF_LMAR; cur_col->width = 550 - DEF_LMAR; /* set single column width */ cur_col->next = NULL; /* by default we are in single column mode */ flags = PARA_NUM; /* turn on paragraph numbering */ memset( tocname, 0, sizeof(tocname ) ); snprintf( tocname, sizeof( tocname )-5, "%s", ifname ); if( (ptr = strrchr( tocname, '.' )) != NULL ) *ptr = 0; strcat( tocname, ".toc" ); /* same filename with .toc extension */ memset( pnum, 0, sizeof( pnum ) ); for( i = argc - 1; i > 2; i-- ) AFIpushtoken( fptr->file, argv[i] ); /* whatever is after output file we use as input */ for( i = 0; i < MAX_HLEVELS; i++ ) /* allocate and init header blks */ { headers[i] = (struct header_blk *) malloc( sizeof( struct header_blk ) ); if( headers[i] == NULL ) return ERROR; headers[i]->font = (char *) malloc( (strlen( DEF_HEADFONT )) + 1 ); strcpy( headers[i]->font, DEF_HEADFONT ); /* move in default string */ headers[i]->flags = HTOC; /* initially only TOC flag set */ headers[i]->indent = DEF_HEADINDENT; /* set default indention */ headers[i]->level = i+1; /* set the level */ headers[i]->skip = 21; /* skip down 2 lines before/1after */ } headers[0]->size = DEF_H1SIZE; /* set default header text sizes */ headers[1]->size = DEF_H2SIZE; headers[2]->size = DEF_H3SIZE; headers[3]->size = DEF_H4SIZE; headers[0]->flags |= HEJECTC+HTOUPPER; /* header level 1 defaults */ return VALID; }
/* *************************************************************************** * * Mnemonic: FMcmd * Abstract: This routine is responsible for dispatching the proper * routine to handle the command that was input by the user. * Commands are those tokins that begin with a period and are 2 * characters long. * Parms: buf - Pointer to the command. (.aa) * Returns: Nothing. * Date: 17 November 1988 * Author: E. Scott Daniels * * Modified: 1-1-89 - To support normal and definition lists * 4-30-98- To support user defined list item characters * 5-05-89- To support boxes * 6-10-89- To add .** as a comment line in the input file * 3 May 1991 - To support .ts (two sided) command * 4 May 1991 - To support page shifting * 5 May 1992 - To support postscript * 1 Oct 1992 - To support punctuation space command * 2 Nov 1992 - To add center command * 13 Nov 1992 - To free/malloc current font buffer * 3 Dec 1992 - To flush before setting font size or font * 6 Jun 1993 - To set y position for list item bullets higher * 21 Feb 1994 - To handle shift value in dlstack rather than old * left margin; correct multi column problem * and to call setstr for running strings * 21 Oct 2007 - Added index interface * 26 Jun 2013 - Prevents 0 text size from being set on .st command (happening * when .st &var and var not defined. * 03 Jan 2016 - Removed errant flush before FMll() and indent * calls. ************************************************************************** */ int FMcmd( char *buf ) { int cmd; /* command converted to integer for switch */ int i; /* temp integer */ struct li_blk *liptr; /* pointer to head to delete on a .el cmd */ char *ptr; /* dummy pointer to skip parameters */ int len; /* length of parameter returned */ int rc = 1; /* return code indicating command or not */ char wbuf[512]; char *tok; cmd = toupper( buf[1] ); i = toupper( buf[2] ); /* pick off and translate indiv characters */ cmd = (cmd << 8) + i; /* combine the characters */ switch( cmd ) { case C_ABORT: exit( 1 ); break; /* get out w/o end housekeeping */ case C_ASIS: flags2 |= F2_ASIS; break; case C_BEGDEFLST: FMbd( ); break; /* definition list */ case C_BEGLIST: FMbeglst( ); break; case C_BLOCKCTR: /* .bc {start|end} */ if( FMgetparm( &buf ) != 0 ) { FMflush( ); /* need to put out last one */ cenx1 = cur_col->lmar; cenx2 = cur_col->lmar + cur_col->width; /* defalult center */ if( *buf == 's' || *buf == 'S' ) flags2 |= F2_CENTER; else flags2 &= ~F2_CENTER; } break; case C_BOTY: /* .by [-]x[ip] if - (neg) then thats how far UP from bottom */ len = FMgetparm( &ptr ); boty = FMgetpts( ptr, len ); if( boty <= 0 ) boty += (11 * 72)-10; break; case C_BREAK: FMflush( ); break; case C_BOX: FMbox( ); break; case C_CAPTURE: FMcapture( ); break; case C_CCOL: FMccol( 0 ); break; case C_COLNOTES: FMcolnotes( ); break; case C_TABLECELL: FMcell( 1 ); break; case C_CENTER: FMcenter( ); break; case C_COLOUR: if( FMgetparm( &ptr ) > 0 ) { if( strcmp( ptr, "text" ) != 0 || FMgetparm( &ptr ) > 0 ) /* hfm compatable format since it allows bg, link colours to be set */ { if( textcolour ) free( textcolour ); FMsetcolour( ptr ); } } break; case C_COMMA: FMcomma( ); break; case C_COMMENT: FMskip( ); break; /* skip to real end of buffer not : */ case C_DEFHEADER: FMdefheader( ); break; case C_CDEFINE: FMcd( ); break; case C_EP: FMep( ); break; case C_CEJECT: PFMceject( ); /* eject column, flush page if in last column */ break; case C_CPAGE: FMcpage( ); break; case C_CSS: /* html cascading style sheet -- meaningless here */ FMignore( ); break; case C_DEFDELIM: /* define the variable definition delimiter */ if( FMgetparm( &ptr ) != 0 ) vardelim = ptr[0]; /* set the new pointer */ break; case C_DEFITEM: FMditem( ); break; case C_DEFVAR: FMdv( ); break; case C_DOUBLESPACE: flags = flags | DOUBLESPACE; break; case C_ELSE: FMelse( ); break; case C_ENDDEFLST: /* end definition list */ if( dlstackp >= 0 ) /* valid stack pointer? */ { flags2 &= ~F2_DIRIGHT; /* turn off the right justify flag for di's */ FMflush( ); i = dlstack[dlstackp].indent / PTWIDTH; /* calc line len shift */ lmar -= dlstack[dlstackp].indent; /* shift margin back to left */ linelen += dlstack[dlstackp].indent; /* reset line len */ dlstackp--; /* "pop" from the stack */ } break; case C_ENDIF: break; /* .fi encountered - ignore it */ case C_ENDLIST: /* end a list */ if( lilist != NULL ) /* if inside of a list */ { FMflush( ); /* clear anything that is there */ FMendlist( TRUE ); /* terminate the list and delete the block */ } break; case C_ENDTABLE: FMendtable( ); break; case C_EVAL: /* evaluate expression and push result */ if( FMgetparm( &buf ) > 0 ) /* get parameter entered */ AFIpushtoken( fptr->file, buf ); break; case C_FIGURE: FMfigure( ); break; case C_FLOATMAR: FMfloat_mar( ); break; case C_FORMAT: FMformat( ); break; case C_GETVALUE: FMgetval( ); break; case C_GREY: /* set grey scale for fills */ if( FMgetparm( &buf ) > 0 ) /* get parameter entered */ fillgrey = atoi( buf ); /* convert it to integer */ break; case C_HDMARG: FMindent( &hlmar ); break; case C_HLINE: FMcline( ); break; case C_HN: FMhn( ); break; case C_H1: FMheader( headers[0] ); break; case C_H2: FMheader( headers[1] ); break; case C_H3: FMheader( headers[2] ); break; case C_H4: FMheader( headers[3] ); break; case C_HYPHEN: if( FMgetparm( &buf ) > 0 ) /* get parameter entered */ { if( *(buf+1) == 'n' ) /* assume on */ flags3 |= F3_HYPHEN; else flags3 &= ~F3_HYPHEN; } else flags3 |= F3_HYPHEN; break; case C_IF: FMif( ); break; case C_IMBED: FMimbed( ); break; case C_INDENT: /* user indention of next line */ FMindent( &lmar ); /* indent the left margin value */ break; case C_INDEX: fmindex( ); break; case C_JUMP: FMjump( ); break; case C_JUSTIFY: FMsetjust( ); break; case C_LINESIZE: /* set line size for line command */ if( FMgetparm( &buf ) > 0 ) /* get the parameter */ { linesize = atoi( buf ); /* convert to integer */ if( linesize > 10 ) linesize = 2; /* dont allow them to be crazy */ } break; case C_LISTITEM: /* list item entered */ if( lilist != NULL && lilist->yindex < 60 ) { FMflush( ); /* output what we have so far */ if( cury + textspace + textsize > boty ) /* flush before marking */ PFMceject( ); lilist->ypos[lilist->yindex] = (cury + textsize); lilist->yindex++; /* point at next index */ } break; case C_LL: /* reset line length */ FMll( ); break; case C_LINE: FMline( ); break; case C_ONPAGEEJECT: FMoneject( ); break; /* on all eject commands */ case C_OUTLINE: /* use true charpath and fill instead of stroke */ if( FMgetparm( &buf ) > 0 ) /* get the parameter on | off */ { if( toupper( buf[1] ) == 'N' ) flags2 |= F2_TRUECHAR; /* turn on the flag */ else flags2 &= ~F2_TRUECHAR; /* turn off the flag */ } break; case C_NOFORMAT: /* turn formatting off */ FMflush( ); /* send last formatted line on its way */ flags = flags | NOFORMAT; /* turn no format flag on */ break; case C_PAGE: /* eject the page now */ FMflush( ); /* terminate the line in progress */ FMpflush(); /* and do the flush */ break; case C_PAGENUM: FMpgnum( ); break; case C_PAGEMAR: FMindent( &pageshift ); break; case C_POP: FMpop_state( ); break; case C_PUNSPACE: flags2 ^= F2_PUNSPACE; break; case C_PUSH: FMpush_state( ); break; case C_QUIT: if( !FMcolnotes_show( 1 ) ) /* push command(s) to show end notes which MUST contain another .qu! */ AFIclose( fptr->file ); /* if there wasn't end commands, then safe to close and exit now */ break; case C_RFOOT: FMsetstr( &rfoot, HEADFOOT_SIZE ); break; case C_RHEAD: FMsetstr( &rhead, HEADFOOT_SIZE ); break; case C_RESTARTTAB: TRACE( 1, ">>>++++ calling restart\n" ) FMrestart_table(); break; case C_SECTION: FMsection( ); break; case C_SETX: FMsetx( ); break; case C_SETY: FMsety( ); break; case C_SHOWV: if( (len = FMgetparm( &buf )) > 0 ) { if( strcmp( buf, "all" ) == 0 ) FMshowvars( ); else { if( (ptr = sym_get( symtab, buf, 0 )) ) fprintf( stderr, "(%s @ %ld) %s = (%s)\n", fptr->name, AFIstat( fptr->file, AFI_OPS, NULL), buf, ptr ); else fprintf( stderr, "(%s @ %ld) %s = UNDEFINED\n", fptr->name, AFIstat( fptr->file, AFI_OPS, NULL), buf ); } } break; case C_SINGLESPACE: /* turn off double space */ if( flags & DOUBLESPACE ) flags = flags & (255-DOUBLESPACE); break; case C_SKIP: if( cury == topy ) break; /* if not at top fall into space */ case C_SPACE: /* user wants blank lines */ FMspace( ); break; case C_SETFONT: /* set font for text (font name only parm) */ if( (len = FMgetparm( &ptr )) != 0 ) /* if a parameter was entered */ { *wbuf = 0; for( tok = ptr; *tok && (isalpha( *tok ) || *tok == '-'); tok++ ); if( *tok != 0 ) /* found non-alpha, assume closing . or ) or somesuch */ { strcpy( wbuf, tok ); *tok = 0; } TRACE( 2, "setfont old=%s new=%s\n", curfont, ptr ); free( curfont ); curfont = strdup( ptr ); FMfmt_add( ); /* add a format block to the list */ //if( *wbuf ) // AFIpushtoken( fptr->file, wbuf ); } else TRACE( 2, "setfont MISSING parameter!\n" ); break; case C_SETTXTSIZE: /* set text font size */ if( FMgetparm( &ptr ) ) /* must have parameter */ { if( (i = atoi( ptr )) > 5 ) /* if number is ok */ { TRACE( 2, "textsize set to: %d\n", i ); textsize = i; FMfmt_add( ); } else TRACE( 2, "textsize NOT set to: %d", i ); } else TRACE( 2, "textsize NOT, no parm" ); break; case C_SMASH: flags2 |= F2_SMASH; break; case C_TABLE: FMtable( ); break; case C_TABLEHEADER: FMth( ); break; case C_TABLEROW: FMtr( 0 ); break; case C_TMPFONT: FMtmpfont( ); break; case C_TMPTOP: FMtmpy( cmd ); break; case C_TOC: FMtc( ); break; case C_TOPGUT: // set the top gutter if( (len = FMgetparm( &ptr )) ) { i = FMgetpts( ptr, len ); if( i > 0 && i < topy ) { TRACE( 2, "top gutter set to: %d\n", i ); top_gutter = i; } else { TRACE( 2, "top gutter not set, not in range: %d topy=%d\n", i, topy ) } } else {