--- loncom/cgi/mimeTeX/mimetex.c 2007/10/09 21:41:41 1.3 +++ loncom/cgi/mimeTeX/mimetex.c 2008/12/04 12:17:13 1.4 @@ -1,10 +1,11 @@ /**************************************************************************** * - * Copyright(c) 2002-2006, John Forkosh Associates, Inc. All rights reserved. + * Copyright(c) 2002-2008, John Forkosh Associates, Inc. All rights reserved. + * http://www.forkosh.com mailto: john@forkosh.com * -------------------------------------------------------------------------- * This file is part of mimeTeX, which is free software. You may redistribute * and/or modify it under the terms of the GNU General Public License, - * version 2 or later, as published by the Free Software Foundation. + * version 3 or later, as published by the Free Software Foundation. * MimeTeX is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY. * See the GNU General Public License for specific details. @@ -12,10 +13,11 @@ * agreed to these terms and conditions, and that you possess the legal * right and ability to enter into this agreement and to use mimeTeX * in accordance with it. - * Your mimeTeX distribution should contain a copy of the GNU General - * Public License. If not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA, - * or point your browser to http://www.gnu.org/licenses/gpl.html + * Your mimetex.zip distribution file should contain the file COPYING, + * an ascii text copy of the GNU General Public License, version 3. + * If not, point your browser to http://www.gnu.org/licenses/ + * or write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * -------------------------------------------------------------------------- * * Purpose: o MimeTeX, licensed under the gpl, lets you easily embed @@ -25,23 +27,29 @@ * entirely separate little program that doesn't use TeX or * its fonts in any way. It's just one cgi that you put in * your site's cgi-bin/ directory, with no other dependencies. - * So mimeTeX is very easy to install. And it's equally easy - * to use. Just place an html tag in your document + * So mimeTeX is very easy to install. And it's equally + * easy to use. Just place an html tag in your document * wherever you want to see the corresponding LaTeX expression. * For example, * * immediately generates the corresponding gif image on-the-fly, * displaying the rendered expression wherever you put that - * tag. MimeTeX doesn't need intermediate dvi-to-gif - * conversion, and it doesn't clutter up your filesystem with - * separate little gif files for each converted expression. + * tag. + * MimeTeX doesn't need intermediate dvi-to-gif conversion, + * and it doesn't clutter up your filesystem with separate + * little gif files for each converted expression. * But image caching is available by using mimeTeX's * -DCACHEPATH=\"path/\" compile option (see below). * There's also no inherent need to repeatedly write the * cumbersome tag illustrated above. You can write * your own custom tags, or write a wrapper script around * mimeTeX to simplify the notation. + * Further discussion about mimeTeX's features and + * usage is available on its homepage, + * http://www.forkosh.com/mimetex.html + * and similarly in mimetex.html included with your mimetex.zip + * distribution file. * * Functions: ===================== Raster Functions ====================== * PART2 --- raster constructor functions --- @@ -188,13 +196,13 @@ * ismonth(month) is month current month ("jan"-"dec")? * unescape_url(url,isescape), x2c(what) xlate %xx url-encoded * logger(fp,msglevel,logvars) logs environment variables - * emitcache(cachefile,maxage,isbuffer) emit cachefile to stdout + * emitcache(cachefile,maxage,valign,isbuffer) emit cachefile * readcachefile(cachefile,buffer) read cachefile into buffer * md5str(instr) md5 hash library functions * GetPixel(x,y) callback function for gifsave library * * Source: mimetex.c (needs mimetex.h and texfonts.h to compile, - * and also needs gifsave.c if compiled with -DAA or -DGIF) + * and also needs gifsave.c when compiled with -DAA or -DGIF) * * -------------------------------------------------------------------------- * Notes o See bottom of file for main() driver (and "friends"), @@ -211,9 +219,10 @@ * and with -DAA or -DGIF you'll also need gifsave.c * o For gif images, the gifsave.c library by Sverre H. Huseby * slightly modified by me to allow - * (a)sending output to stdout and (b)specifying a transparent - * background color index, is included with mimeTeX, - * and it's documented in mimetex.html#gifsave . + * (a)sending output to stdout or returning it in memory, + * and (b)specifying a transparent background color index, + * is included with mimeTeX, and it's documented in + * mimetex.html#gifsave . * o Optional compile-line -D defined symbols are documented * in mimetex.html#options . They include (additional -D * switches are discussed in mimetex.html#options)... @@ -332,7 +341,8 @@ * 10/02/04 J.Forkosh Version 1.50 released. * 11/30/04 J.Forkosh Version 1.60 released. * 10/11/05 J.Forkosh Version 1.64 released. - * 11/30/06 J.Forkosh most recent changes + * 11/30/06 J.Forkosh Version 1.65 released. + * 09/06/08 J.Forkosh Version 1.70 released. * ****************************************************************************/ @@ -669,7 +679,6 @@ GLOBAL(char,*subexprptr,(char *)NULL); / /*SHARED(int,imageformat,1);*/ /* image is 1=bitmap, 2=.gf-like */ GLOBAL(int,isdisplaystyle,1); /* displaystyle mode (forced if 2) */ GLOBAL(int,ispreambledollars,0); /* displaystyle mode set by $$...$$ */ -GLOBAL(int,isemitcontenttype,1); /* true to emit mime content-type */ GLOBAL(int,fontnum,0); /* cal=1,scr=2,rm=3,it=4,bb=5,bf=6 */ GLOBAL(int,fontsize,NORMALSIZE); /* current size */ GLOBAL(int,displaysize,DISPLAYSIZE); /* use \displaystyle when fontsize>=*/ @@ -716,6 +725,9 @@ GLOBAL(int,fraccenterline,NOVALUE); /* b /*GLOBAL(int,currentcharclass,NOVALUE);*/ /*primarily to check for PUNCTION*/ GLOBAL(int,iscaching,ISCACHING); /* true if caching images */ GLOBAL(char,cachepath[256],CACHEPATH); /* relative path to cached files */ +GLOBAL(int,isemitcontenttype,1); /* true to emit mime content-type */ +int iscachecontenttype = 0; /* true to cache mime content-type */ +char contenttype[2048] = "\000"; /* content-type:, etc buffer */ GLOBAL(char,pathprefix[256],PATHPREFIX); /*prefix for \input,\counter paths*/ /*GLOBAL(int,iswindows,ISWINDOWS);*/ /* true if compiled for ms windows */ @@ -13474,7 +13486,7 @@ messages -------------------------------------------------------------------------- */ static char *copyright = /* copyright, gnu/gpl notice */ "+-----------------------------------------------------------------------+\n" - "|mimeTeX vers 1.64, Copyright(c) 2002-2006, John Forkosh Associates, Inc|\n" + "|mimeTeX vers 1.70, Copyright(c) 2002-2008, John Forkosh Associates, Inc|\n" "+-----------------------------------------------------------------------+\n" "| mimeTeX is free software, licensed to you under terms of the GNU/GPL, |\n" "| and comes with absolutely no warranty whatsoever. |\n" @@ -13551,6 +13563,7 @@ char *gif_outfile = (char *)NULL, /* gif cachefile[256] = "\000", /* full path and name to cache file*/ *md5str(); /* md5 has of expression */ int maxage = 7200; /* max-age is two hours */ +int valign = (-9999); /*Vertical-Align:baseline-(height-1)*/ /* --- pbm/pgm (-g switch) --- */ int ispbmpgm = 0; /* true to write pbm/pgm file */ int type_pbmpgm(), ptype=0; /* entry point, graphic format */ @@ -13583,7 +13596,18 @@ initialization /* --- set global variables --- */ msgfp = stdout; /* for comamnd-line mode output */ isss = issupersampling; /* set supersampling flag */ +isemitcontenttype = 1; /* true to emit mime content-type */ +iscachecontenttype = 0; /* true to cache mime content-type */ +*contenttype = '\000'; /* reset content-type:, etc. cache */ +iscaching = ISCACHING; /* true if caching images */ +if ( iscaching ) { /* images are being cached */ + strcpy(cachepath,CACHEPATH); /* relative path to cached files */ + if ( *cachepath == '%' ) { /* leading % signals cache headers */ + iscachecontenttype = 1; /* signal caching mime content-type*/ + strcpy(cachepath,cachepath+1); } } /* and squeeze out leading % char */ gifSize = 0; /* signal that image not in memory */ +fgred=FGRED; fggreen=FGGREEN; fgblue=FGBLUE; /* default foreground colors */ +bgred=BGRED; bggreen=BGGREEN; bgblue=BGBLUE; /* default background colors */ shrinkfactor = shrinkfactors[NORMALSIZE]; /* set shrinkfactor */ for ( ipattern=1; ipattern<=51; ipattern++ ) patternnumcount0[ipattern] = patternnumcount1[ipattern] = 0; @@ -13594,6 +13618,9 @@ if ( query != NULL ) /* check query st if ( strlen(query) >= 1 ) /* caller gave us a query string */ { strncpy(expression,query,MAXEXPRSZ); /* so use it as expression */ expression[MAXEXPRSZ] = '\000'; /* make sure it's null terminated */ + if ( 0 ) /*true to remove leading whitespace*/ + while ( isspace(*expression) && *expression!='\000' ) + strcpy(expression,expression+1); /* squeeze out white space */ isquery = 1; } /* and set isquery flag */ if ( !isquery ) /* empty query string */ { char *host = getenv("HTTP_HOST"), /* additional getenv("") results */ @@ -13913,9 +13940,11 @@ if ( isquery ) /* don't cache command /* --- emit mime content-type line --- */ if ( 0 && isemitcontenttype ) /* now done in emitcache() */ { fprintf( stdout, "Cache-Control: max-age=%d\n",maxage ); + if ( abs(valign) < 999 ) /* have vertical align */ + fprintf( stdout, "Vertical-Align: %d\n",valign ); fprintf( stdout, "Content-type: image/gif\n\n" ); } /* --- emit cached image if it already exists --- */ - if ( emitcache(cachefile,maxage,0) > 0 ) /* cached image emitted */ + if ( emitcache(cachefile,maxage,valign,0) > 0 ) /* cached image emitted */ goto end_of_job; /* so nothing else to do */ /* --- log caching request --- */ if ( msglevel >= 1 /* check if logging */ @@ -13958,7 +13987,8 @@ if ( !isdumpimage ) /* don't mix ascii rasterize expression and put a border around it -------------------------------------------------------------------------- */ /* --- preprocess expression, converting LaTeX constructs for mimeTeX --- */ -expression = mimeprep(expression); /* preprocess expression */ +if ( expression != NULL ) { /* have expression to rasterize */ + expression = mimeprep(expression); } /* preprocess expression */ /* --- double-check that we actually have an expression to rasterize --- */ if ( expression == NULL ) /* nothing to rasterize */ { if ( (!isquery||isqlogging) && msgfp!=NULL ) /*emit error if not a query*/ @@ -13977,6 +14007,9 @@ if ( issupersampling ) /* no border ne else /* for mime xbitmaps must have... */ bp = border_raster(sp->image,0,0,0,1); /* image width multiple of 8 bits */ sp->image = bitmap_raster = bp; /* global copy for gif,png output */ +if ( sp!=NULL && bp!=NULL ) { /* have raster */ + valign = sp->baseline - (bp->height - 1); /* #pixels for Vertical-Align: */ + if ( abs(valign) > 255 ) valign = (-9999); } /* sanity check */ if ( ispbmpgm && ptype<2 ) /* -g switch or -g1 switch */ type_pbmpgm(bp,ptype,pbm_outfile); /* emit b/w pbm file */ /* ------------------------------------------------------------------------- @@ -14119,15 +14152,24 @@ if ( isquery /* called from browser ------------------------------------------------------------------------- */ /* --- don't use memory buffer if outout file given --- */ if ( gif_outfile != NULL ) isinmemory = 0; /* reset memory buffer flag */ + /* --- construct contenttype[] buffer containing mime headers --- */ + if ( 1 ) { /* always construct buffer */ + sprintf( contenttype, "Cache-Control: max-age=%d\n", maxage ); + /*sprintf(contenttype+strlen(contenttype), + "Expires: Fri, 31 Oct 2003 23:59:59 GMT\n" );*/ + /*sprintf(contenttype+strlen(contenttype), + "Last-Modified: Wed, 15 Oct 2003 01:01:01 GMT\n");*/ + if ( abs(valign) < 999 ) /* have Vertical-Align: header info*/ + sprintf( contenttype+strlen(contenttype), + "Vertical-Align: %d\n", valign ); + sprintf( contenttype+strlen(contenttype), + "Content-type: image/gif\n\n" ); } /* --- emit mime content-type line --- */ if ( isemitcontenttype /* content-type lines wanted */ && !isdumpimage /* don't mix ascii with image dump */ && !isinmemory /* done below if in memory */ && !iscaching ) /* done by emitcache() if caching */ - { fprintf( stdout, "Cache-Control: max-age=%d\n",maxage ); - /*fprintf( stdout, "Expires: Fri, 31 Oct 2003 23:59:59 GMT\n" );*/ - /*fprintf( stdout, "Last-Modified: Wed, 15 Oct 2003 01:01:01 GMT\n" );*/ - fprintf( stdout, "Content-type: image/gif\n\n" ); } + { fputs(contenttype,stdout); } /* emit content-type: header buffer*/ /* --- write output to memory buffer, possibly for testing --- */ if ( isinmemory /* want gif written to memory */ || isdumpbuffer ) /*or dump memory buffer for testing*/ @@ -14190,9 +14232,9 @@ if ( isquery /* called from browser || msglevel >= 99 ) { /* or debugging */ int maxage2 = (isdumpimage?(-1):maxage); /* no headers if dumping image */ if ( iscaching ) /* caching enabled */ - emitcache(cachefile,maxage2,0); /* cached image (hopefully) emitted*/ + emitcache(cachefile,maxage2,valign,0); /*emit cached image (hopefully)*/ else if ( isinmemory ) /* or emit image from memory buffer*/ - emitcache(gif_buffer,maxage2,1); } /* emitted from memory buffer */ + emitcache(gif_buffer,maxage2,valign,1); } /*emitted from memory buffer*/ /* --- for testing, may need to write image buffer to file --- */ if ( isdumpbuffer > 99 ) /* gif image in memory buffer */ if ( gifSize > 0 ) /* and it's not an empty buffer */ @@ -14572,14 +14614,16 @@ return ( nlogged ); /* back to caller } /* --- end-of-function logger() --- */ /* ========================================================================== - * Function: emitcache ( cachefile, maxage, isbuffer ) + * Function: emitcache ( cachefile, maxage, valign, isbuffer ) * Purpose: dumps bytes from cachefile to stdout * -------------------------------------------------------------------------- * Arguments: cachefile (I) pointer to null-terminated char string * containing full path to file to be dumped, * or contains buffer of bytes to be dumped - * maxage (I) int containing maxage. in seconds, for + * maxage (I) int containing maxage, in seconds, for * http header, or -1 to not emit headers + * valign (I) int containing Vertical-Align:, in pixels, + * for http header, or <= -999 to not emit * isbuffer (I) 1 if cachefile is buffer of bytes to be * dumped * -------------------------------------------------------------------------- @@ -14588,7 +14632,7 @@ return ( nlogged ); /* back to caller * Notes: o * ======================================================================= */ /* --- entry point --- */ -int emitcache ( char *cachefile, int maxage, int isbuffer ) +int emitcache ( char *cachefile, int maxage, int valign, int isbuffer ) { /* ------------------------------------------------------------------------- Allocations and Declarations @@ -14597,6 +14641,8 @@ int nbytes=gifSize, readcachefile(); /* FILE *emitptr = stdout; /* emit cachefile to stdout */ unsigned char buffer[MAXGIFSZ+1]; /* bytes from cachefile */ unsigned char *buffptr = buffer; /* ptr to buffer */ +int isvalign = (abs(valign)<999?1:0); /* true to emit Vertical-Align: */ +int iscontenttypecached = iscachecontenttype; /*true if headers cached*/ /* ------------------------------------------------------------------------- initialization -------------------------------------------------------------------------- */ @@ -14604,17 +14650,21 @@ initialization if ( emitptr == (FILE *)NULL ) /* failed to open emit file */ goto end_of_job; /* so return 0 bytes to caller */ /* --- read the file if necessary --- */ -if ( isbuffer ) /* cachefile is buffer */ - buffptr = (unsigned char *)cachefile; /* so reset buffer pointer */ -else /* cachefile is file name */ - if ( (nbytes = readcachefile(cachefile,buffer)) /* read the file */ - < 1 ) goto end_of_job; /* quit if file not read */ +if ( isbuffer ) { /* cachefile is buffer */ + buffptr = (unsigned char *)cachefile; /* so reset buffer pointer */ + iscontenttypecached = 0; } /* and iscontenttypecached flag */ +else { /* cachefile is file name */ + if ( (nbytes = readcachefile(cachefile,buffer)) /* read the file */ + < 1 ) goto end_of_job; } /* quit if file not read */ /* --- first emit http headers if requested --- */ if ( isemitcontenttype /* content-type lines enabled */ +&& !iscontenttypecached /* and not in cached image */ && maxage >= 0 ) /* caller wants http headers */ { /* --- emit mime content-type line --- */ fprintf( emitptr, "Cache-Control: max-age=%d\n",maxage ); fprintf( emitptr, "Content-Length: %d\n",nbytes ); + if ( isvalign ) /* Vertical-Align: header wanted */ + fprintf( emitptr, "Vertical-Align: %d\n",valign ); fprintf( emitptr, "Content-type: image/gif\n\n" ); } /* ------------------------------------------------------------------------- set stdout to binary mode (for Windows)