/* **************************************************************************** * * Mnemonic: FMimbed * Abstract: This routine is responsible for parsing the imbed string and * calling FMopen to open a file to process. * Parms: None. * Returns: Nothing. * Date: 15 November 1988 * Author: E. Scott Daniels * Modified: 25 Aug 2000 - to add NF option * 13 Nov 207 - Added run/stop command to stream to mark pop of * the fmrun() command and return to this function. Allows * this rouitine to drive the imbed which is needed * for things like oneject that imbed files and push/pop the * environment before/after the file. Basically negates the * AFIchain() feature where the imbed file was pushed onto * the stack of open files. c'est la vie! * 17 Jul 2016 - Bring decls into the modern world. * * .im [nf] filename *************************************************************************** */ extern void FMimbed( void ) { char *fp = 0; char *buf; /* pointer into the imput buffer of the fname token */ int len; /* length of the token */ len = FMgetparm( &buf ); if( strcmp( buf, "nf" ) == 0 ) { len = FMgetparm( &buf ); /* point to the next token in the buffer */ FMflush( ); /* send last formatted line on its way */ flags = flags | NOFORMAT; /* turn no format flag on */ } if( len <= 0 ) { FMmsg( E_MISSINGNAME, ".IM" ); return; } FMmsg( I_IMBED, buf ); fp = strdup( buf ); AFIpushtoken( fptr->file, ".sr" ); /* push the special runstop command to mark end of imbed file */ TRACE( 2, "imbed: starting with file %s (pushed .sr token) \n", fp ); FMopen( buf ); /* open the imbed file */ FMrun( ); /* run until we hit the end of the file */ TRACE( 2, "imbed: finished with file %s lmar=%d\n", fp, lmar ); free( fp ); } /* FMimbed */
/* * -------------------------------------------------------------------------- * Mnemonic: fmth * Abstract: save a table header placed into the table now, and if we page eject * Date: 02 Nov 2006 - converted from hfm * Author: E. Scott Daniels * * .th string * -------------------------------------------------------------------------- */ extern void FMth( void ) { struct table_mgt_blk *t; char *buf; int len; int totlen = 0; char data[4096]; if( ts_index <= 0 || (t = table_stack[ts_index-1]) == NULL ) { while( (len = FMgetparm( &buf )) != 0 ); /* just dump the record */ return; } *data = 0; while( (len = FMgetparm( &buf )) != 0 ) { if( len + totlen + 1 < sizeof( data ) ) { strcat( data, buf ); strcat( data, " " ); } totlen += len + 1; } if( t->header ) free( t->header ); t->header = strdup( data ); TRACE( 2, "tab_header: header in place: %s\n", t->header ); AFIpushtoken( fptr->file, t->header ); /* fmtr calls get parm; prevent eating things */ }
extern void FMendtable( void ) { struct table_mgt_blk *t; struct col_blk *next; int i; int x; char obuf[1024]; if( ts_index <= 0 || ! (t = table_stack[ts_index-1]) ) return; TRACE( 1, "end_table: cury=%d rows=%d total_depth=%d ave_depth=%d\n", cury, t->nrows, t->tot_row_depth, t->ave_row_depth ); AFIpushtoken( fptr->file, ":" ); /* fmtr calls get parm; prevent eating things */ FMtr( ts_index > 1 ? 0 : 1 ); /* flush out last row (adds bottom and side borders if needed */ if( firstcol != t->col_list ) { for( cur_col = firstcol; cur_col; cur_col = next ) { next = cur_col->next; cur_col->next = NULL; // fail if reuse is tried free( cur_col ); } } TRACE( 2, "tab_end: reset first col from %p to %p\n", firstcol, t->col_list ); TRACE( 2, "tab_end: reset cur_col from %p to %p\n", cur_col, t->cur_col ); cur_col = t->cur_col; lmar = t->lmar; hlmar = t->hlmar; linelen = t->old_linelen; firstcol = t->col_list; #ifdef KEEP /* setting the temp top is up to the user as the table might be in a left column and the next column needs to go to the top of the physical page. If this is a page wide table, then the user must setup multiple columns after .et and set the temp top. we cannot assume this to be the case */ if( rtopy == 0 ) /* allow for multiple columns under the table */ rtopy = t->old_topy; topy = cury; #endif topy = t->old_topy; if( t->header ) free( t->header ); free( t ); table_stack[ts_index-1] = NULL; if( ts_index > 0 ) ts_index--; /* keep it from going neg */ if( ts_index ) topy = table_stack[ts_index-1]->topy; }
/* ***************************************************************************** * * Mnemonic: FMpflush * Abstract: This routine causes the running header and footer to be placed * into the file and then issues the newp command which will issue * a showpage and then a translate. * Parms: None. * Returns: Nothing * Date: 1 December 1988 * Author: E. Scott Daniels * * Modified: 22 Apr 1991 - To put header and footer and page under 2nd * column if in two column mode. * 3 May 1991 - To support two sided page format of headers. * 4 May 1991 - To shift pages by pageshift size * Broke header/footer code to FMrunout * 13 May 1992 - Conversion to PostScript output * 25 Oct 1992 - To call fmrunout with page and shift only. * 27 Nov 1992 - To also set hlmar on new column * 10 Dec 1992 - To use AFI routines for ansi compatability * 7 Apr 1994 - To reset topy to realy if realy not 0. * 17 Aug 2001 - To add support for on eject command buffer * 26 Jun 2013 - Calls colnotes_show() to show the notes before * doing the eject. * 07 Jul 2013 - Colour support changes. * 18 Dec 2015 - Cleaned up commented out code. * 17 Jul 2016 - Bring decls into the modern world. ***************************************************************************** */ extern void FMpflush( void ) { int diff; /* difference between default lmar and cur lmar*/ int diffh; /* difference between default lmar and header */ int i; /* index into page number buffer */ char tbuf[HEADFOOT_SIZE+1]; /* buf to gen page and head/foots in */ int len; /* number of characters in the string */ int even = FALSE; /* even/odd page number flag */ int skip; /* # columns to skip before writing string */ int shift = FALSE; /* local flag so if stmts are executed only once */ char *tok; if( cn_space ) /* if and end note was defined, need to add it too */ { TRACE( 3, "pflush: dumping column notes first, pushing .pa command back\n" ); AFIpushtoken( fptr->file, ".pa" ); /* page command to execute after the column notes are written */ cn_space = 0; FMcolnotes_show( 0 ); /* cause the column notes to be put in before eject */ return; // go run all of the commands which will 'end' with the page eject we just pushed } page++; /* increase the page number */ if( rtopy != 0 ) /* see if top margin reset temporarily */ { topy = rtopy; /* reset as it is good only to the end of pg*/ rtopy = 0; /* indicate nothing set at this point */ } /* determine if we need to shift the page */ if( flags2 & F2_2SIDE ) /* if in two sided mode */ { if( (page % 2) != 0 ) /* and its an odd page (only shift odd pages) */ shift = TRUE; } else /* page shift not 0 and one sided mode */ shift = TRUE; /* then EACH page is shifted */ FMpushcolour( "#000000" ); /* push current colour and set head/foot/pagen colour (black) */ FMrunout( page, shift ); /* put header/footer and page strings */ FMpopcolour( ); /* restore the colour */ AFIwrite( ofile, "newp\n" ); /* newpage ps definition "showpage" */ diff = lmar - cur_col->lmar; /* calculate diff in col default mar& cur mar */ diffh = hlmar - cur_col->lmar; /* calc diff in header left margin */ cur_col = firstcol; /* start point at the first column block */ lmar = cur_col->lmar + diff; /* set up lmar for first column */ hlmar = cur_col->lmar +diffh; /* set up header left margin for first col */ cury = topy + (textsize/2); /* reset current y to top y position */ FMateject( 1 ); /* do page eject stuff first */ }
/* Restart a paused table */ extern void FMrestart_table( void ) { struct table_mgt_blk *t; if( ts_index <= 0 || ! (t = table_stack[ts_index-1]) ) { return; } if( t->paused_list == NULL ) { fprintf( stderr, "abort: internal mishap restarting table; no paused list\n" ); exit( 1 ); } firstcol = t->paused_list; cur_col = firstcol; lmar = cur_col->lmar - textspace - t->padding; firstcol->anchor = t->paused_list->anchor; // cary the anchor over for running head/feet t->maxy = cury; if( t->header ) // new header on resume { AFIpushtoken( fptr->file, ".tr :" ); /* must drop a table row after the header command(s) */ AFIpushtoken( fptr->file, t->header ); /* fmtr calls get parm; prevent eating things */ } // cell start emulation cury = topy; t->topy = topy; lmar = cur_col->lmar + t->padding; /* set lmar based on difference calculated */ hlmar = cur_col->lmar + t->padding; /* earlier and next columns left edge */ if( lilist != NULL ) /* if list then reset xpos for next col */ lilist->xpos = cur_col->lmar + t->padding; linelen = cur_col->width; t->paused_list = NULL; if( t->border ) // add top border to start the table in next col/page { //sprintf( obuf, "%d %d moveto %d %d rlineto stroke\n", t->lmar+t->padding, -(cury - t->padding), t->border_width-t->padding, 0 ); sprintf( obuf, "%d %d moveto %d %d rlineto stroke\n", t->lmar+t->padding, -(cury ), t->border_width-t->padding, 0 ); AFIwrite( ofile, obuf ); } }
/* ***************************************************************************** * * Mnemonic: FMnofmt * Abstract: This routine is called when the noformat flag is set. It * reads in lines from the input file and if there is not a * command in the first column then it places the line of * text as is out to the page buffer. If a command is on the * input line control is returned to the caller to process the * command. * Parms: None. * Returns: Nothing. * Date: 8 December 1988 * Author: E. Scott Daniels * * Modified: 7 Jul 1994 - To convert to rfm * 4 Oct 1994 - To reduce amount skipped in y direction. * 6 Dec 1996 - To convert for hfm * 4 Apr 1997 - To use the new tokenizer in AFIleio! * 15 Apr 1997 - To return if vardelim is in first col too ******************************************************************************* */ void FMnofmt( ) { char *buf; /* work buffer */ int status; /* status of the read */ int i; /* loop index */ status = FMread( inbuf ); /* get the next buffer */ while( status >= 0 && inbuf[0] != CMDSYM && *inbuf != vardelim ) { for( i = 0; i < MAX_READ-1 && inbuf[i] != EOS; i++, optr++ ) { switch( inbuf[i] ) /* properly escape html special chars */ { case '>': obuf[optr] = EOS; /* terminate for strcat */ strcat( obuf, ">" ); /* copy in the character */ optr += 3; /* incr past the html esc string */ osize += 3; /* incr number of chars in output */ break; case '<': obuf[optr] = EOS; /* terminate for strcat */ strcat( obuf, "<" ); /* copy in the character */ optr += 3; /* incr past the html esc string */ osize += 3; /* incr number of chars in output */ break; case '&': obuf[optr] = EOS; /* terminate for strcat */ strcat( obuf, "&" ); /* copy in the character */ optr += 4; /* incr past the html esce string */ osize += 4; /* incr number of chars in output */ break; default: /* not a special character - just copy in */ obuf[optr] = inbuf[i]; obuf[optr+1] = EOS; /* terminate incase of strcat on next loop */ break; } } /* end while stuff in input buffer to copy */ if( optr == 0 ) /* if this was a blank line */ obuf[optr++] = ' '; /* give flush a blank to write */ obuf[optr] = EOS; /* terminate buffer for flush */ FMflush( ); /* send the line on its way */ status = FMread( inbuf ); /* get the next line and loop back */ } /* end while */ AFIpushtoken( fptr->file, inbuf ); /* put command back into input stack */ iptr = optr = 0; /* return pointing at beginning */ } /* FMnofmt */
/* show the col notes by closing the file and pushing an imbed command onto the stack. the last command in the file is a .cn command to unlink the file (we'll leave droppings in the file system if the user causes us to crash, but thats low risk). returns true if something was pushed -- needed for the end; */ extern int FMcolnotes_show( int end ) { char buf[1024]; FILE *target = NULL; char *fname = NULL; int status = 0; char *end_cmd = ""; if( bfile != NULL ) // target is always the b file if it's there { target = bfile; bfile = NULL; fname = bfname; } if( end ) /* end of doc (atclose) */ { FMflush( ); if( target == NULL ) { // end and no bfile; try end file now target = efile; efile = NULL; fname = efname; } end_cmd = ".qu"; // needed to force end processing after our embed (might bring us back to do efile if bfile exists } if( target == NULL ) return 0; TRACE( 2, "colnotes: showing at: %s cury=%d boty=%d page=%d\n", end ? "end of doc" : "bottom of col", cury, boty, page ); if( cn_space > 0 ) if( boty - cn_space > cury ) cury = boty - cn_space; TRACE( 2, "colnotes: cury set to=%d\n", cury ); fprintf( target, ".br\n.po\n" ); // add the ending commands to the file (force flush and pop) if( ! end ) fprintf( target, ".cb\n" ) ; // new col only if not at end; causes extra page eject if at end if( flags & JUSTIFY ) fprintf( target, ".ju on\n" ); // justify back on if needed fprintf( target, ".cn unlink %s\n%s\n", fname, end_cmd ); fclose( target ); snprintf( buf, sizeof( buf ), "\n.im %s", fname ); /* must have a guarding newline as lead (prevent accidents with .sp without optional parm etc.) */ status = AFIpushtoken( fptr->file, buf ); /* push to imbed the file */ TRACE( 2, "colnotes: pushing: stat=%d (%s)\n", status, buf ); *fname = 0; return 1; }
/* **************************************************************************** * * 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 {
/* --------------------------------------------------------------------------- Mnemonic: fmtr Abstract: start a new row in the current table Date: 26 Oct 2001 - converted from hfml stuff syntax: .tr [n] [c=bgcolour] [a=alignval] [r=reserve] [v=valignvalue] [w=weight] [l=linecount] w= allows the line weight (drawn between the current row and the new) to be differnt than the default. m= allows multiple lines to separate the row being terminated from the next. Lines are spaced fairly close together. The n option prevents table cell from being called automatically (user needs to supply a first .cl command). r= (reserve) will force a column break if the desired amount of space isn't remaining. Mods: 10 Apr 2007 -- fixed write of border to be in conditional. --------------------------------------------------------------------------- */ extern void FMtr( int last ) { struct table_mgt_blk *t = NULL; char *ptr = NULL; /* pointer at parms */ int len = 0; int do_cell = 1; /* turned off by n option */ char colour[50]; char align[50]; char valign[50]; char obuf[2048]; int row_top = 0; /* used to calc the depth of each row */ int old_cn_space = 0; int required = 0; // points required for the next row; col eject if not enough int tmp_lw = -1; // temp line weight (l=) int lcount = 1; // number of horizontal separating lines colour[0] = 0; align[0] = 0; valign[0] = 0; if( ts_index <= 0 || (t = table_stack[ts_index-1]) == NULL ) { char *b; while( (len = FMgetparm( &b )) != 0 ); // no table, ditch parms and scoot return; } if( cur_col == firstcol ) /* we've not seen a .cl command (one col table) */ t->maxy = cury; /* force it to be set */ row_top = cury; TRACE(2, "table/tr: cury=%d textsize=%d textspace=%d font=%s boty=%d topy=%d maxy=%d\n", cury, textsize, textspace, curfont, boty, topy, table_stack[ts_index-1]->maxy ); while( cur_col != firstcol ) FMcell( 0 ); /* flush and calc maxy for the row */ t->tot_row_depth += t->maxy - row_top; /* add in depth of this column */ t->nrows++; t->ave_row_depth = t->tot_row_depth / t->nrows; /* average depth of a row to predict end of page */ while( (len = FMgetparm( &ptr )) != 0 ) { switch( *ptr ) { case 'a': sprintf( align, "align=%s", ptr + 2 ); break; case 'c': if( strncmp( ptr, "class=", 6 ) == 0 ) /* ignore hfm class */ break; sprintf( colour, "bgcolor=%s", ptr + 2 ); break; case 'l': if( *(ptr+1) == '=' ) { lcount = atoi( ptr+2 ); } break; case 'n': do_cell = 0; break; case 'r': required = FMgetpts( ptr + 2, len-2 ); break; case 'v': sprintf( valign, "valign=%s", ptr + 2 ); break; case 'w': if( *(ptr+1) == '=' ) { tmp_lw = atoi( ptr+2 ); } break; default: // ignore anything unrecognised break; } } cury = t->maxy + t->padding; if( t->border ) // add vert lines for the row if borders are on { sprintf( obuf, "%d setlinewidth ", t->weight ); AFIwrite( ofile, obuf ); tab_vlines( t, 0 ); /* add vlines just for this row */ } if( t->border || tmp_lw >= 0 ) { // add a top line if borders, or a temp line width was given int line_y = cury; TRACE( 2, "table/tr-border: cury=%d lcount=%d tlw=%d\n", cury, lcount, tmp_lw ); if( lcount && tmp_lw >= 0 ) { // dont need if no line generated sprintf( obuf, "%d setlinewidth ", tmp_lw ); // need a second adjustment AFIwrite( ofile, obuf ); } while( lcount > 0 ) { //sprintf( obuf, "%d %d moveto %d %d rlineto stroke\n", t->lmar+t->padding, -cury, t->border_width-t->padding, 0 ); // top border sprintf( obuf, "%d %d moveto %d %d rlineto stroke\n", t->lmar+t->padding, -line_y, t->border_width-t->padding, 0 ); // top border AFIwrite( ofile, obuf ); // bottom line for the previous row if( --lcount ) { // small increase to cury if we have more to do line_y += 2; } } } TRACE( 1, "table/tr: required=%d cn_space=%d ard=%d cury=%d boty=%d remain=%d\n", required, cn_space, t->ave_row_depth, cury, boty, boty-cury ); // ??? Do we need to prevent eject if this is the last one? if( (required + cury) > (boty-8) || cn_space + cury + t->ave_row_depth + textsize + textspace >= (boty-8) ) // extra 8pts to have room for bottom line { FMpause_table(); // pause so we can eject to the next real column which might be a page eject AFIpushtoken( fptr->file, ".rt" ); // must restart table; push first so that col notes go before if needed old_cn_space = cn_space; // eject will reset if set PFMceject( ); // move to the top of the new col/eject page if( old_cn_space > 0 ) { // if col note, must set it up and return so it is processes before new col is started t->maxy = topy; return; // allow the col notes commands to play out first } topy = t->old_topy; cury = topy; t->maxy = t->topy; // reset the mexy for the next col/page } t->topy = cury; if( ! last ) cury += t->padding; topy = cury; /* columns need to bounce back to here */ }