Annotation of loncom/cgi/mimeTeX/mimetex.c, revision 1.1
1.1 ! albertel 1: /****************************************************************************
! 2: *
! 3: * Copyright(c) 2002-2005, John Forkosh Associates, Inc. All rights reserved.
! 4: * --------------------------------------------------------------------------
! 5: * This file is part of mimeTeX, which is free software. You may redistribute
! 6: * and/or modify it under the terms of the GNU General Public License,
! 7: * version 2 or later, as published by the Free Software Foundation.
! 8: * MimeTeX is distributed in the hope that it will be useful, but
! 9: * WITHOUT ANY WARRANTY, not even the implied warranty of MERCHANTABILITY.
! 10: * See the GNU General Public License for specific details.
! 11: * By using mimeTeX, you warrant that you have read, understood and
! 12: * agreed to these terms and conditions, and that you possess the legal
! 13: * right and ability to enter into this agreement and to use mimeTeX
! 14: * in accordance with it.
! 15: * Your mimeTeX distribution should contain a copy of the GNU General
! 16: * Public License. If not, write to the Free Software Foundation, Inc.,
! 17: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA,
! 18: * or point your browser to http://www.gnu.org/licenses/gpl.html
! 19: * --------------------------------------------------------------------------
! 20: *
! 21: * Purpose: o MimeTeX, licensed under the gpl, lets you easily embed
! 22: * LaTeX math in your html pages. It parses a LaTeX math
! 23: * expression and immediately emits the corresponding gif
! 24: * image, rather than the usual TeX dvi. And mimeTeX is an
! 25: * entirely separate little program that doesn't use TeX or
! 26: * its fonts in any way. It's just one cgi that you put in
! 27: * your site's cgi-bin/ directory, with no other dependencies.
! 28: * So mimeTeX is very easy to install. And it's equally easy
! 29: * to use. Just place an html <img> tag in your document
! 30: * wherever you want to see the corresponding LaTeX expression.
! 31: * For example,
! 32: * <img src="../cgi-bin/mimetex.cgi?\int_{-\infty}^xe^{-t^2}dt"
! 33: * alt="" border=0 align=middle>
! 34: * immediately generates the corresponding gif image on-the-fly,
! 35: * displaying the rendered expression wherever you put that
! 36: * <img> tag. MimeTeX doesn't need intermediate dvi-to-gif
! 37: * conversion, and it doesn't clutter up your filesystem with
! 38: * separate little gif files for each converted expression.
! 39: * There's also no inherent need to repeatedly write the
! 40: * cumbersome <img> tag illustrated above. You can write
! 41: * your own custom tags, or write a wrapper script around
! 42: * mimeTeX to simplify the necessary notation.
! 43: *
! 44: * Functions: ===================== Raster Functions ======================
! 45: * PART2 --- raster constructor functions ---
! 46: * new_raster(width,height,pixsz) allocation (and constructor)
! 47: * new_subraster(width,height,pixsz)allocation (and constructor)
! 48: * new_chardef() allocate chardef struct
! 49: * delete_raster(rp) deallocate raster (rp = raster ptr)
! 50: * delete_subraster(sp) deallocate subraster (sp=subraster ptr)
! 51: * delete_chardef(cp) deallocate chardef (cp = chardef ptr)
! 52: * --- primitive (sub)raster functions ---
! 53: * rastcpy(rp) allocate new copy of rp
! 54: * subrastcpy(sp) allocate new copy of sp
! 55: * rastrot(rp) new raster rotated right 90 degrees to rp
! 56: * rastput(target,source,top,left,isopaque) overlay src on trgt
! 57: * rastcompose(sp1,sp2,offset2,isalign,isfree) sp2 on top of sp1
! 58: * rastcat(sp1,sp2,isfree) concatanate sp1||sp2
! 59: * rastack(sp1,sp2,base,space,iscenter,isfree)stack sp2 atop sp1
! 60: * rastile(tiles,ntiles) create composite raster from tiles
! 61: * rastsquash(sp1,sp2,xmin,ymin) calc #squash pixels sp1||sp2
! 62: * --- raster "drawing" functions ---
! 63: * accent_subraster(accent,width,height) draw \hat\vec\etc
! 64: * arrow_subraster(width,height,drctn,isBig) left/right arrow
! 65: * uparrow_subraster(width,height,drctn,isBig) up/down arrow
! 66: * rule_raster(rp,top,left,width,height,type) draw rule in rp
! 67: * line_raster(rp,row0,col0,row1,col1,thickness) draw line in rp
! 68: * line_recurse(rp,row0,col0,row1,col1,thickness) recurse line
! 69: * circle_raster(rp,row0,col0,row1,col1,thickness,quads) ellipse
! 70: * circle_recurse(rp,row0,col0,row1,col1,thickness,theta0,theta1)
! 71: * bezier_raster(rp,r0,c0,r1,c1,rt,ct) draw bezier recursively
! 72: * border_raster(rp,ntop,nbot,isline,isfree)put border around rp
! 73: * --- raster (and chardef) output functions ---
! 74: * type_raster(rp,fp) emit ascii dump of rp on file ptr fp
! 75: * type_bytemap(bp,grayscale,width,height,fp) dump bytemap on fp
! 76: * xbitmap_raster(rp,fp) emit mime xbitmap of rp on fp
! 77: * cstruct_chardef(cp,fp,col1) emit C struct of cp on fp
! 78: * cstruct_raster(rp,fp,col1) emit C struct of rp on fp
! 79: * hex_bitmap(rp,fp,col1,isstr)emit hex dump of rp->pixmap on fp
! 80: * --- ancillary output functions ---
! 81: * emit_string(fp,col1,string,comment) emit string and C comment
! 82: * ====================== Font Functions =======================
! 83: * --- font lookup functions ---
! 84: * get_symdef(symbol) returns mathchardef for symbol
! 85: * get_chardef(symdef,size) returns chardef for symdef,size
! 86: * get_charsubraster(symdef,size) wrap subraster around chardef
! 87: * --- ancillary font functions ---
! 88: * get_baseline(gfdata) determine baseline (in our coords)
! 89: * get_delim(symbol,height,family) delim just larger than height
! 90: * make_delim(symbol,height) construct delim exactly height size
! 91: * ================= Tokenize/Parse Functions ==================
! 92: * texchar(expression,chartoken) retruns next char or \sequence
! 93: * texsubexpr(expr,subexpr,maxsubsz,left,right,isescape,isdelim)
! 94: * texscripts(expression,subscript,superscript,which)get scripts
! 95: * --- ancillary parse functions ---
! 96: * isbrace(expression,braces,isescape) check for leading brace
! 97: * preamble(expression,size,subexpr) parse preamble
! 98: * mimeprep(expression) preprocessor converts \left( to \(, etc.
! 99: * strchange(nfirst,from,to) change nfirst chars of from to to
! 100: * strreplace(string,from,to,nreplace) change from to to in str
! 101: * strtexchr(string,texchr) find texchr in string
! 102: * findbraces(expression,command) find opening { or closing }
! 103: * PART3 =========== Rasterize an Expression (recursively) ===========
! 104: * --- here's the primary entry point for all of mimeTeX ---
! 105: * rasterize(expression,size) parse and rasterize expression
! 106: * --- explicitly called handlers that rasterize... ---
! 107: * rastparen(subexpr,size,basesp) parenthesized subexpr
! 108: * rastlimits(expression,size,basesp) dispatch super/sub call
! 109: * rastscripts(expression,size,basesp) super/subscripted exprssn
! 110: * rastdispmath(expression,size,sp) scripts for displaymath
! 111: * --- table-driven handlers that rasterize... ---
! 112: * rastleft(expression,size,basesp,ildelim,arg2,arg3)\left\right
! 113: * rastflags(expression,size,basesp,flag,value,arg3) set flag
! 114: * rastspace(expression,size,basesp,width,isfill,isheight)\,\:\;
! 115: * rastnewline(expression,size,basesp,arg1,arg2,arg3) \\
! 116: * rastarrow(expression,size,basesp,width,height,drctn) \longarr
! 117: * rastuparrow(expression,size,basesp,width,height,drctn)up/down
! 118: * rastoverlay(expression,size,basesp,overlay,arg2,arg3) \not
! 119: * rastfrac(expression,size,basesp,isfrac,arg2,arg3) \frac \atop
! 120: * rastackrel(expression,size,basesp,base,arg2,arg3) \stackrel
! 121: * rastmathfunc(expression,size,basesp,base,arg2,arg3) \lim,\etc
! 122: * rastsqrt(expression,size,basesp,arg1,arg2,arg3) \sqrt
! 123: * rastaccent(expression,size,basesp,accent,isabove,isscript)
! 124: * rastfont(expression,size,basesp,font,arg2,arg3) \cal{},\scr{}
! 125: * rastbegin(expression,size,basesp,arg1,arg2,arg3) \begin{}
! 126: * rastarray(expression,size,basesp,arg1,arg2,arg3) \array
! 127: * rastpicture(expression,size,basesp,arg1,arg2,arg3) \picture
! 128: * rastline(expression,size,basesp,arg1,arg2,arg3) \line
! 129: * rastcircle(expression,size,basesp,arg1,arg2,arg3) \circle
! 130: * rastbezier(expression,size,basesp,arg1,arg2,arg3) \bezier
! 131: * rastraise(expression,size,basesp,arg1,arg2,arg3) \raisebox
! 132: * rastrotate(expression,size,basesp,arg1,arg2,arg3) \rotatebox
! 133: * rastfbox(expression,size,basesp,arg1,arg2,arg3) \fbox
! 134: * rastinput(expression,size,basesp,arg1,arg2,arg3) \input
! 135: * rastcounter(expression,size,basesp,arg1,arg2,arg3) \counter
! 136: * rastnoop(expression,size,basesp,arg1,arg2,arg3) flush \escape
! 137: * --- helper functions for handlers ---
! 138: * rastopenfile(filename,mode) opens filename[.tex] in mode
! 139: * rastreadfile(filename,tag,value) read between <tag>...</tag>
! 140: * rastwritefile(filename,tag,value,isstrict)write<tag>...</tag>
! 141: * timestamp( ) formats timestamp string (used by rastcounter)
! 142: * dtoa(d,npts) double to comma-separated ascii
! 143: * === Anti-alias completed raster (lowpass) or symbols (ss) ===
! 144: * aalowpass(rp,bytemap,grayscale) lowpass grayscale bytemap
! 145: * aapnm(rp,bytemap,grayscale) lowpass based on pnmalias.c
! 146: * aasupsamp(rp,aa,sf,grayscale) or by supersampling
! 147: * aacolormap(bytemap,nbytes,colors,colormap)make colors,colormap
! 148: * aaweights(width,height) builds "canonical" weight matrix
! 149: * aawtpixel(image,ipixel,weights,rotate) weight image at ipixel
! 150: * PART1 ========================== Driver ===========================
! 151: * main(argc,argv) parses math expression and emits mime xbitmap
! 152: * isstrstr(string,snippets,iscase) are any snippets in string?
! 153: * ismonth(month) is month current month ("jan"-"dec")?
! 154: * unescape_url(url,isescape), x2c(what) xlate %xx url-encoded
! 155: * logger(fp,msglevel,logvars) logs environment variables
! 156: * emitcache(cachefile) read cachefile and emit bytes to stdout
! 157: * md5str(instr) md5 hash library functions
! 158: * GetPixel(x,y) callback function for gifsave library
! 159: *
! 160: * Source: mimetex.c (needs mimetex.h and texfonts.h to compile,
! 161: * and also needs gifsave.c if compiled with -DAA or -DGIF)
! 162: *
! 163: * --------------------------------------------------------------------------
! 164: * Notes o See bottom of file for main() driver (and "friends"),
! 165: * and compile as
! 166: * cc -DAA mimetex.c gifsave.c -lm -o mimetex.cgi
! 167: * to produce an executable that emits gif images with
! 168: * anti-aliasing (see Notes below). You may also compile
! 169: * cc -DGIF mimetex.c gifsave.c -lm -o mimetex.cgi
! 170: * to produce an executable that emits gif images without
! 171: * anti-aliasing. Alternatively, compile mimeTeX as
! 172: * cc -DXBITMAP mimetex.c -lm -o mimetex.cgi
! 173: * to produce an executable that just emits mime xbitmaps.
! 174: * In either case you'll need mimetex.h and texfonts.h,
! 175: * and with -DAA or -DGIF you'll also need gifsave.c
! 176: * o For gif images, the gifsave.c library by Sverre H. Huseby
! 177: * <http://shh.thathost.com> slightly modified by me to allow
! 178: * (a)sending output to stdout and (b)specifying a transparent
! 179: * background color index, is included with mimeTeX,
! 180: * and it's documented in mimetex.html#gifsave .
! 181: * o Optional compile-line -D defined symbols are documented
! 182: * in mimetex.html#options . They include...
! 183: * -DAA
! 184: * Turns on gif anti-aliasing with default values
! 185: * (CENTERWT=32, ADJACENTWT=3, CORNERWT=1)
! 186: * for the following anti-aliasing parameters...
! 187: * -DCENTERWT=n
! 188: * -DADJACENTWT=j
! 189: * -DCORNERWT=k
! 190: * MimeTeX currently provides a lowpass filtering
! 191: * algorithm for anti-aliasing, which is applied to the
! 192: * existing set of bitmap fonts. This lowpass filter
! 193: * applies default weights
! 194: * 1 3 1
! 195: * 3 32 3
! 196: * 1 3 1
! 197: * to neighboring pixels. The defaults weights are
! 198: * CENTERWT=32, ADJACENTWT=3 and CORNERWT=1,
! 199: * which you can adjust to control anti-aliasing.
! 200: * Lower CENTERWT values will blur/spread out lines
! 201: * while higher values will tend to sharpen lines.
! 202: * Experimentation is recommended to determine
! 203: * what value works best for you.
! 204: * -DCACHEPATH=\"path/\"
! 205: * This option saves each rendered image to a file
! 206: * in directory path/ which mimeTeX reads rather than
! 207: * re-rendering the same image every time it's given
! 208: * the same LaTeX expression. Sometimes mimeTeX disables
! 209: * caching, e.g., expressions containing \input{ } are
! 210: * re-rendered since the contents of the inputted file
! 211: * may have changed. If compiled without -DCACHEPATH
! 212: * mimeTeX always re-renders expressions. This usually
! 213: * isn't too cpu intensive, but if you have unusually
! 214: * high hit rates then image caching may be helpful.
! 215: * The path/ is relative to mimetex.cgi, and must
! 216: * be writable by it. Files created under path/ are
! 217: * named filename.gif, where filename is the 32-character
! 218: * MD5 hash of the LaTeX expression.
! 219: * -DDISPLAYSIZE=n
! 220: * By default, operator limits like \int_a^b are rendered
! 221: * \textstyle at font sizes \normalsize and smaller,
! 222: * and rendered \displaystyle at font sizes \large and
! 223: * larger. This default corresponds to -DDISPLAYSIZE=3,
! 224: * which you can adjust; e.g., -DDISPLAYSIZE=0 always
! 225: * defaults to \displaystyle, and 99 (or any large number)
! 226: * always defaults to \textstyle. Note that explicit
! 227: * \textstyle, \displaystyle, \limits or \nolimits
! 228: * directives in an expression always override
! 229: * the DISPLAYSIZE default.
! 230: * -NORMALSIZE=n
! 231: * MimeTeX currently has six font sizes numbered 0-5,
! 232: * and always starts in NORMALSIZE whose default value
! 233: * is 2. Specify -DNORMALSIZE=3 on the compile line if
! 234: * you prefer mimeTeX to start in default size 3, etc.
! 235: * -DREFERER=\"domain\" -or-
! 236: * -DREFERER=\"domain1,domain2,etc\"
! 237: * Blocks mimeTeX requests from unauthorized domains that
! 238: * may be using your server's mimetex.cgi without permission.
! 239: * If REFERER is defined, mimeTeX checks for the environment
! 240: * variable HTTP_REFERER and, if it exists, performs a
! 241: * case-insensitive test to make sure it contains 'domain'
! 242: * as a substring. If given several 'domain's (second form)
! 243: * then HTTP_REFERER must contain either 'domain1' or
! 244: * 'domain2', etc, as a (case-insensitive) substring.
! 245: * If HTTP_REFERER fails to contain a substring matching
! 246: * any of these domain(s), mimeTeX emits an error message
! 247: * image corresponding to the expression specified by
! 248: * the invalid_referer_msg string defined in main().
! 249: * Note: if HTTP_REFERER is not an environment variable,
! 250: * mimeTeX correctly generates the requested expression
! 251: * (i.e., no referer error).
! 252: * -DWARNINGS=n -or-
! 253: * -DNOWARNINGS
! 254: * If an expression submitted to mimeTeX contains an
! 255: * unrecognzied escape sequence, e.g., "y=x+\abc+1", then
! 256: * mimeTeX generates a gif image containing an embedded
! 257: * warning in the form "y=x+[\abc?]+1". If you want these
! 258: * warnings suppressed, -DWARNINGS=0 or -DNOWARNINGS tells
! 259: * mimeTeX to ignore unrecognized symbols, and the rendered
! 260: * image is "y=x++1" instead.
! 261: * -DWHITE
! 262: * MimeTeX usually renders black symbols on a white
! 263: * background. This option renders white symbols on
! 264: * a black background instead.
! 265: * o See individual function entry points for further comments.
! 266: * o The font information in texfonts.h was produced by multiple
! 267: * runs of gfuntype, one run per struct (i.e., one run per font
! 268: * family at a particular size). See gfuntype.c, and also
! 269: * mimetex.html#fonts, for details.
! 270: * o mimetex.c contains library functions implementing a raster
! 271: * datatype, functions to manipulate rasterized .mf fonts
! 272: * (see gfuntype.c which rasterizes .mf fonts), functions
! 273: * to parse LaTeX expressions, etc. A complete list of
! 274: * mimetex.c functions is above. See their individual entry
! 275: * points below for further comments.
! 276: * All these functions eventually belong in several
! 277: * different modules, possibly along the lines suggested
! 278: * by the divisions above. But until the best decomposition
! 279: * becomes clear, it seems better to keep mimetex.c
! 280: * neatly together, avoiding a bad decomposition that
! 281: * becomes permanent by default.
! 282: * o The "main" reusable function is rasterize(),
! 283: * which takes a string like "f(x)=\int_{-\infty}^xe^{-t^2}dt"
! 284: * and returns a (sub)raster representing it as a bit or bytemap.
! 285: * Your application can do anything it likes with this pixel map.
! 286: * MimeTeX just outputs it, either as a mime xbitmap or as a gif.
! 287: * --------------------------------------------------------------------------
! 288: * Revision History:
! 289: * 09/18/02 J.Forkosh Installation.
! 290: * 12/11/02 J.Forkosh Version 1.00 released.
! 291: * 07/04/03 J.Forkosh Version 1.01 released.
! 292: * 10/17/03 J.Forkosh Version 1.20 released.
! 293: * 12/21/03 J.Forkosh Version 1.30 released.
! 294: * 02/01/04 J.Forkosh Version 1.40 released.
! 295: * 10/02/04 J.Forkosh Version 1.50 released.
! 296: * 11/30/04 J.Forkosh Version 1.60 released.
! 297: *
! 298: ****************************************************************************/
! 299:
! 300: /* -------------------------------------------------------------------------
! 301: header files and macros
! 302: -------------------------------------------------------------------------- */
! 303: /* --- standard headers --- */
! 304: #include <stdio.h>
! 305: #include <stdlib.h>
! 306: /*#include <unistd.h>*/
! 307: #include <string.h>
! 308: #include <ctype.h>
! 309: #include <math.h>
! 310: #include <time.h>
! 311:
! 312: /* --- windows-specific header info --- */
! 313: #ifndef WINDOWS /* -DWINDOWS not supplied by user */
! 314: #if defined(_WIN32) || defined(WIN32) \
! 315: || defined(DJGPP) /* try to recognize windows */
! 316: #define WINDOWS /* signal windows */
! 317: #endif
! 318: #endif
! 319: #ifdef WINDOWS /* Windows opens stdout in char mode, and */
! 320: #include <fcntl.h> /* precedes every 0x0A with spurious 0x0D.*/
! 321: #include <io.h> /* So emitcache() issues a Win _setmode() */
! 322: /* call to put stdout in binary mode. */
! 323: #if defined(_O_BINARY) && !defined(O_BINARY) /* only have _O_BINARY */
! 324: #define O_BINARY _O_BINARY /* make O_BINARY available, etc... */
! 325: #define setmode _setmode
! 326: #define fileno _fileno
! 327: #endif
! 328: #if defined(_O_BINARY) || defined(O_BINARY) /* setmode() now available */
! 329: #define HAVE_SETMODE /* so we'll use setmode() */
! 330: #endif
! 331: #define ISWINDOWS 1
! 332: #else
! 333: #define ISWINDOWS 0
! 334: #endif
! 335:
! 336: /* --- check for supersampling or low-pass anti-aliasing --- */
! 337: #ifdef SS
! 338: #define ISSUPERSAMPLING 1
! 339: #ifndef AAALGORITHM
! 340: #define AAALGORITHM 1 /* default supersampling algorithm */
! 341: #endif
! 342: #ifndef AA /* anti-aliasing not explicitly set */
! 343: #define AA /* so define it ourselves */
! 344: #endif
! 345: #ifndef SSFONTS /* need supersampling fonts */
! 346: #define SSFONTS
! 347: #endif
! 348: #else
! 349: #define ISSUPERSAMPLING 0
! 350: #ifndef AAALGORITHM
! 351: #define AAALGORITHM 2 /* default lowpass algorithm */
! 352: #endif
! 353: #endif
! 354:
! 355: /* --- set aa (and default gif) if any anti-aliasing options specified --- */
! 356: #if defined(AA) || defined(GIF) || defined(PNG) \
! 357: || defined(CENTERWT) || defined(ADJACENTWT) || defined(CORNERWT) \
! 358: || defined(MINADJACENT) || defined(MAXADJACENT)
! 359: #if !defined(GIF) && !defined(AA) /* aa not explicitly specified */
! 360: #define AA /* so define it ourselves */
! 361: #endif
! 362: #if !defined(GIF) && !defined(PNG) /* neither gif nor png specified */
! 363: #define GIF /* so default to gif */
! 364: #endif
! 365: #endif
! 366: /* --- resolve output option inconsistencies --- */
! 367: #if defined(XBITMAP) /* xbitmap supercedes gif and png */
! 368: #ifdef AA
! 369: #undef AA
! 370: #endif
! 371: #ifdef GIF
! 372: #undef GIF
! 373: #endif
! 374: #ifdef PNG
! 375: #undef PNG
! 376: #endif
! 377: #endif
! 378:
! 379: /* --- decide whether to compile main() --- */
! 380: #if defined(XBITMAP) || defined(GIF) || defined(PNG)
! 381: #define DRIVER /* driver will be compiled */
! 382: /* --- check whether or not to perform http_referer check --- */
! 383: #ifndef REFERER /* all http_referer's allowed */
! 384: #define REFERER NULL
! 385: #endif
! 386: /* --- max query_string length if no http_referer supplied --- */
! 387: #ifndef NOREFMAXLEN
! 388: #define NOREFMAXLEN 9999 /* default to any length query */
! 389: #endif
! 390: #else
! 391: #define NOTEXFONTS /* texfonts not required */
! 392: #endif
! 393:
! 394: /* --- application headers --- */
! 395: #if !defined(NOTEXFONTS) && !defined(TEXFONTS)
! 396: #define TEXFONTS /* to include texfonts.h */
! 397: #endif
! 398: #include "mimetex.h"
! 399:
! 400: /* -------------------------------------------------------------------------
! 401: adjustable default values
! 402: -------------------------------------------------------------------------- */
! 403: /* --- anti-aliasing parameters --- */
! 404: #ifndef CENTERWT
! 405: /*#define CENTERWT 10*/ /* anti-aliasing centerwt default */
! 406: /*#define CENTERWT 6*/ /* anti-aliasing centerwt default */
! 407: #define CENTERWT 32 /* anti-aliasing centerwt default */
! 408: #endif
! 409: #ifndef ADJACENTWT
! 410: /*#define ADJACENTWT 3*/ /* anti-aliasing adjacentwt default*/
! 411: /*#define ADJACENTWT 2*/ /* anti-aliasing adjacentwt default*/
! 412: #define ADJACENTWT 3 /* anti-aliasing adjacentwt default*/
! 413: #endif
! 414: #ifndef CORNERWT
! 415: #define CORNERWT 1 /* anti-aliasing cornerwt default*/
! 416: #endif
! 417: #ifndef MINADJACENT
! 418: #define MINADJACENT 6 /*anti-aliasing minadjacent default*/
! 419: #endif
! 420: #ifndef MAXADJACENT
! 421: #define MAXADJACENT 8 /*anti-aliasing maxadjacent default*/
! 422: #endif
! 423: /* --- variables for anti-aliasing parameters --- */
! 424: GLOBAL(int,centerwt,CENTERWT); /*lowpass matrix center pixel wt */
! 425: GLOBAL(int,adjacentwt,ADJACENTWT); /*lowpass matrix adjacent pixel wt*/
! 426: GLOBAL(int,cornerwt,CORNERWT); /*lowpass matrix corner pixel wt */
! 427: GLOBAL(int,minadjacent,MINADJACENT); /* darken if>=adjacent pts black*/
! 428: GLOBAL(int,maxadjacent,MAXADJACENT); /* darken if<=adjacent pts black */
! 429: GLOBAL(int,weightnum,1); /* font wt, */
! 430: GLOBAL(int,maxaaparams,4); /* #entries in table */
! 431: /* --- parameter values by font weight --- */
! 432: #define aaparameters struct aaparameters_struct /* typedef */
! 433: aaparameters
! 434: { int centerwt; /* lowpass matrix center pixel wt*/
! 435: int adjacentwt; /* lowpass matrix adjacent pixel wt*/
! 436: int cornerwt; /* lowpass matrix corner pixel wt*/
! 437: int minadjacent; /* darken if >= adjacent pts black */
! 438: int maxadjacent; /* darken if <= adjacent pts black */
! 439: int fgalias,fgonly,bgalias,bgonly; } ; /* aapnm() params */
! 440: STATIC aaparameters aaparams[] /* set params by weight */
! 441: #ifdef INITVALS
! 442: =
! 443: { /* ----------------------------------------------------
! 444: centerwt adj corner minadj max fgalias,only,bgalias,only
! 445: ------------------------------------------------------- */
! 446: { 64, 1, 1, 6, 8, 1,0,0,0 }, /* 0 = light */
! 447: { CENTERWT,ADJACENTWT,CORNERWT,MINADJACENT,MAXADJACENT,1,0,0,0 },
! 448: { 8, 1, 1, 5, 8, 1,0,0,0 }, /* 2 = semibold */
! 449: { 8, 2, 1, 4, 9, 1,0,0,0 } /* 3 = bold */
! 450: } /* --- end-of-aaparams[] --- */
! 451: #endif
! 452: ;
! 453:
! 454: /* -------------------------------------------------------------------------
! 455: other variables
! 456: -------------------------------------------------------------------------- */
! 457: /* --- black on white background (default), or white on black --- */
! 458: #ifdef WHITE
! 459: #define ISBLACKONWHITE 0 /* white on black background */
! 460: #else
! 461: #define ISBLACKONWHITE 1 /* black on white background */
! 462: #endif
! 463: /* --- colors --- */
! 464: #define BGRED (ISBLACKONWHITE?255:0)
! 465: #define BGGREEN (ISBLACKONWHITE?255:0)
! 466: #define BGBLUE (ISBLACKONWHITE?255:0)
! 467: #ifndef FGRED
! 468: #define FGRED (ISBLACKONWHITE?0:255)
! 469: #endif
! 470: #ifndef FGGREEN
! 471: #define FGGREEN (ISBLACKONWHITE?0:255)
! 472: #endif
! 473: #ifndef FGBLUE
! 474: #define FGBLUE (ISBLACKONWHITE?0:255)
! 475: #endif
! 476: /* --- "squash" margin (0 means no squashing) --- */
! 477: #ifndef SQUASHMARGIN
! 478: #ifdef NOSQUASH
! 479: #define SQUASHMARGIN 0
! 480: #else
! 481: #define SQUASHMARGIN 3
! 482: #endif
! 483: #endif
! 484: /* --- textwidth --- */
! 485: #ifndef TEXTWIDTH
! 486: #define TEXTWIDTH (400)
! 487: #endif
! 488: /* --- font "combinations" --- */
! 489: #define CMSYEX (107) /* select CMSY10 _or_ CMEX10 */
! 490: /* --- prefix prepended to all expressions --- */
! 491: #ifndef PREFIX
! 492: #define PREFIX "\000" /* default no prepended prefix */
! 493: #endif
! 494: /* --- skip argv[]'s preceding ARGSIGNAL when parsing command-line args --- */
! 495: #ifdef NOARGSIGNAL
! 496: #define ARGSIGNAL NULL
! 497: #endif
! 498: #ifndef ARGSIGNAL
! 499: #define ARGSIGNAL "++"
! 500: #endif
! 501: /* --- security and logging (inhibit message logging, etc) --- */
! 502: #ifndef SECURITY
! 503: #define SECURITY 999 /* default highest security level */
! 504: #endif
! 505: #ifndef LOGFILE
! 506: #define LOGFILE "mimetex.log" /* default log file */
! 507: #endif
! 508: #ifndef CACHELOG
! 509: #define CACHELOG "mimetex.log" /* default caching log file */
! 510: #endif
! 511: #if !defined(NODUMPENVP) && !defined(DUMPENVP)
! 512: #define DUMPENVP /* assume char *envp[] available */
! 513: #endif
! 514: /* --- image caching (cache images if given -DCACHEPATH=\"path\") --- */
! 515: #ifndef CACHEPATH
! 516: #define ISCACHING 0 /* no caching */
! 517: #define CACHEPATH "\000" /* same directory as mimetex.cgi */
! 518: #else
! 519: #define ISCACHING 1 /* caching if -DCACHEPATH="path" */
! 520: #endif
! 521: /* --- \input paths (prepend prefix if given -DPATHPREFIX=\"prefix\") --- */
! 522: #ifndef PATHPREFIX
! 523: #define PATHPREFIX "\000" /* paths relative mimetex.cgi */
! 524: #endif
! 525:
! 526: /* -------------------------------------------------------------------------
! 527: debugging and logging / error reporting
! 528: -------------------------------------------------------------------------- */
! 529: /* --- debugging and error reporting --- */
! 530: #ifndef MSGLEVEL
! 531: #define MSGLEVEL 1
! 532: #endif
! 533: #define DBGLEVEL 9 /* debugging if msglevel>=DBGLEVEL */
! 534: #define LOGLEVEL 3 /* logging if msglevel>=LOGLEVEL */
! 535: #ifndef FORMLEVEL
! 536: #define FORMLEVEL LOGLEVEL /*msglevel if called from html form*/
! 537: #endif
! 538: GLOBAL(int,seclevel,SECURITY); /* security level */
! 539: GLOBAL(int,msglevel,MSGLEVEL); /* message level for verbose/debug */
! 540: STATIC FILE *msgfp; /* output in command-line mode */
! 541: /* --- embed warnings in rendered expressions, [\xxx?] if \xxx unknown --- */
! 542: #ifdef WARNINGS
! 543: #define WARNINGLEVEL WARNINGS
! 544: #else
! 545: #ifdef NOWARNINGS
! 546: #define WARNINGLEVEL 0
! 547: #else
! 548: #define WARNINGLEVEL 1
! 549: #endif
! 550: #endif
! 551: GLOBAL(int,warninglevel,WARNINGLEVEL); /* warning level */
! 552:
! 553: /* -------------------------------------------------------------------------
! 554: control flags and values
! 555: -------------------------------------------------------------------------- */
! 556: GLOBAL(int,recurlevel,0); /* inc/decremented in rasterize() */
! 557: GLOBAL(int,scriptlevel,0); /* inc/decremented in rastlimits() */
! 558: GLOBAL(int,istext,0); /* textmode if true,italics=2,bb=3 */
! 559: GLOBAL(int,isstring ,0); /*pixmap is ascii string, not raster*/
! 560: GLOBAL(int,isdisplaystyle,1); /* displaystyle mode (forced if 2) */
! 561: GLOBAL(int,ispreambledollars,0); /* displaystyle mode set by $$...$$ */
! 562: GLOBAL(int,fontsize,NORMALSIZE); /* current size */
! 563: GLOBAL(int,displaysize,DISPLAYSIZE); /* use \displaystyle when fontsize>=*/
! 564: GLOBAL(int,shrinkfactor,3); /* shrinkfactors[fontsize] */
! 565: GLOBAL(double,unitlength,1.0); /* #pixels per unit (may be <1.0) */
! 566: /*GLOBAL(int,textwidth,TEXTWIDTH);*/ /* #pixels across line */
! 567: GLOBAL(int,squashmargin,SQUASHMARGIN); /* minimum "squash" margin */
! 568: GLOBAL(int,issquashdelta,1); /* true if squashmargin is a delta */
! 569: GLOBAL(int,istransparent,1); /*true to set background transparent*/
! 570: GLOBAL(int,fgred,FGRED);
! 571: GLOBAL(int,fggreen,FGGREEN);
! 572: GLOBAL(int,fgblue,FGBLUE); /* fg r,g,b */
! 573: GLOBAL(int,bgred,BGRED);
! 574: GLOBAL(int,bggreen,BGGREEN);
! 575: GLOBAL(int,bgblue,BGBLUE); /* bg r,g,b */
! 576: GLOBAL(int,isblackonwhite,ISBLACKONWHITE); /*1=black on white,0=reverse*/
! 577: GLOBAL(char,exprprefix[256],PREFIX); /* prefix prepended to expressions */
! 578: GLOBAL(int,aaalgorithm,AAALGORITHM); /* for lp, 1=aalowpass, 2 =aapnm */
! 579: GLOBAL(int,fgalias,1);
! 580: GLOBAL(int,fgonly,0);
! 581: GLOBAL(int,bgalias,0);
! 582: GLOBAL(int,bgonly,0); /* aapnm() params */
! 583: GLOBAL(int,issupersampling,ISSUPERSAMPLING); /*1=supersampling 0=lowpass*/
! 584: GLOBAL(int,isss,ISSUPERSAMPLING); /* supersampling flag for main() */
! 585: GLOBAL(int,*workingparam,(int *)NULL); /* working parameter */
! 586: GLOBAL(subraster,*workingbox,(subraster *)NULL); /*working subraster box*/
! 587: GLOBAL(int,isreplaceleft,0); /* true to replace leftexpression */
! 588: GLOBAL(subraster,*leftexpression,(subraster *)NULL); /*rasterized so far*/
! 589: GLOBAL(mathchardef,*leftsymdef,NULL); /* mathchardef for preceding symbol*/
! 590: GLOBAL(int,iscaching,ISCACHING); /* true if caching images */
! 591: GLOBAL(char,cachepath[256],CACHEPATH); /* relative path to cached files */
! 592: GLOBAL(char,pathprefix[256],PATHPREFIX); /*prefix for \input,\counter paths*/
! 593: /*GLOBAL(int,iswindows,ISWINDOWS);*/ /* true if compiled for ms windows */
! 594:
! 595: /* -------------------------------------------------------------------------
! 596: miscellaneous macros
! 597: -------------------------------------------------------------------------- */
! 598: #define max2(x,y) ((x)>(y)? (x):(y)) /* larger of 2 arguments */
! 599: #define min2(x,y) ((x)<(y)? (x):(y)) /* smaller of 2 arguments */
! 600: #define max3(x,y,z) max2(max2(x,y),(z)) /* largest of 3 arguments */
! 601: #define min3(x,y,z) min2(min2(x,y),(z)) /* smallest of 3 arguments */
! 602: #define absval(x) ((x)>=0?(x):(-(x))) /* absolute value */
! 603: #define iround(x) ((int)((x)>=0?(x)+0.5:(x)-0.5)) /* round double to int */
! 604: #define dmod(x,y) ((x)-((y)*((double)((int)((x)/(y)))))) /*x%y for doubles*/
! 605: #define compress(s,c) if((s)!=NULL) /* remove embedded c's from s */ \
! 606: { char *p; while((p=strchr((s),(c)))!=NULL) strcpy(p,p+1); } else
! 607: #define slower(s) if ((s)!=NULL) /* lowercase all chars in s */ \
! 608: { char *p=(s); while(*p!='\000'){*p=tolower(*p); p++;} } else
! 609:
! 610: /* ---
! 611: * PART2
! 612: * ------ */
! 613: #if !defined(PARTS) || defined(PART2)
! 614: /* ==========================================================================
! 615: * Function: new_raster ( width, height, pixsz )
! 616: * Purpose: Allocation and constructor for raster.
! 617: * mallocs and initializes memory for width*height pixels,
! 618: * and returns raster struct ptr to caller.
! 619: * --------------------------------------------------------------------------
! 620: * Arguments: width (I) int containing width, in bits,
! 621: * of raster pixmap to be allocated
! 622: * height (I) int containing height, in bits/scans,
! 623: * of raster pixmap to be allocated
! 624: * pixsz (I) int containing #bits per pixel, 1 or 8
! 625: * --------------------------------------------------------------------------
! 626: * Returns: ( raster * ) ptr to allocated and initialized
! 627: * raster struct, or NULL for any error.
! 628: * --------------------------------------------------------------------------
! 629: * Notes:
! 630: * ======================================================================= */
! 631: /* --- entry point --- */
! 632: raster *new_raster ( int width, int height, int pixsz )
! 633: {
! 634: /* -------------------------------------------------------------------------
! 635: Allocations and Declarations
! 636: -------------------------------------------------------------------------- */
! 637: raster *rp = (raster *)NULL; /* raster ptr returned to caller */
! 638: pixbyte *pixmap = NULL; /* raster pixel map to be malloced */
! 639: int nbytes = pixsz*bitmapsz(width,height); /* #bytes needed for pixmap */
! 640: int filler = (isstring?' ':0); /* pixmap filler */
! 641: int delete_raster(); /* in case pixmap malloc() fails */
! 642: int npadding = (0&&issupersampling?8+256:0); /* padding bytes */
! 643: /* -------------------------------------------------------------------------
! 644: allocate and initialize raster struct and embedded bitmap
! 645: -------------------------------------------------------------------------- */
! 646: if ( msgfp!=NULL && msglevel>=9999 )
! 647: { fprintf(msgfp,"new_raster(%d,%d,%d)> entry point\n",
! 648: width,height,pixsz); fflush(msgfp); }
! 649: /* --- allocate and initialize raster struct --- */
! 650: rp = (raster *)malloc(sizeof(raster)); /* malloc raster struct */
! 651: if ( msgfp!=NULL && msglevel>=9999 )
! 652: { fprintf(msgfp,"new_raster> rp=malloc(%d) returned (%s)\n",
! 653: sizeof(raster),(rp==NULL?"null ptr":"success")); fflush(msgfp); }
! 654: if ( rp == (raster *)NULL ) /* malloc failed */
! 655: goto end_of_job; /* return error to caller */
! 656: rp->width = width; /* store width in raster struct */
! 657: rp->height = height; /* and store height */
! 658: rp->pixsz = pixsz; /* store #bits per pixel */
! 659: rp->pixmap = (pixbyte *)NULL; /* init bitmap as null ptr */
! 660: /* --- allocate and initialize bitmap array --- */
! 661: if ( msgfp!=NULL && msglevel>=9999 )
! 662: { fprintf(msgfp,"new_raster> calling pixmap=malloc(%d)\n",
! 663: nbytes); fflush(msgfp); }
! 664: if ( nbytes>0 && nbytes<=pixsz*maxraster ) /* fail if width*height too big*/
! 665: pixmap = (pixbyte *)malloc(nbytes+npadding); /*bytes for width*height bits*/
! 666: if ( msgfp!=NULL && msglevel>=9999 )
! 667: { fprintf(msgfp,"new_raster> pixmap=malloc(%d) returned (%s)\n",
! 668: nbytes,(pixmap==NULL?"null ptr":"success")); fflush(msgfp); }
! 669: if ( pixmap == (pixbyte *)NULL ) /* malloc failed */
! 670: { delete_raster(rp); /* so free everything */
! 671: rp = (raster *)NULL; /* reset pointer */
! 672: goto end_of_job; } /* and return error to caller */
! 673: memset((void *)pixmap,filler,nbytes); /* init bytes to binary 0's or ' 's*/
! 674: *pixmap = (pixbyte)0; /* and first byte alwasy 0 */
! 675: rp->pixmap = pixmap; /* store ptr to malloced memory */
! 676: /* -------------------------------------------------------------------------
! 677: Back to caller with address of raster struct, or NULL ptr for any error.
! 678: -------------------------------------------------------------------------- */
! 679: end_of_job:
! 680: if ( msgfp!=NULL && msglevel>=9999 )
! 681: { fprintf(msgfp,"new_raster(%d,%d,%d)> returning (%s)\n",
! 682: width,height,pixsz,(rp==NULL?"null ptr":"success")); fflush(msgfp); }
! 683: return ( rp ); /* back to caller with raster */
! 684: } /* --- end-of-function new_raster() --- */
! 685:
! 686:
! 687: /* ==========================================================================
! 688: * Function: new_subraster ( width, height, pixsz )
! 689: * Purpose: Allocate a new subraster along with
! 690: * an embedded raster of width x height.
! 691: * --------------------------------------------------------------------------
! 692: * Arguments: width (I) int containing width of embedded raster
! 693: * height (I) int containing height of embedded raster
! 694: * pixsz (I) int containing #bits per pixel, 1 or 8
! 695: * --------------------------------------------------------------------------
! 696: * Returns: ( subraster * ) ptr to newly-allocated subraster,
! 697: * or NULL for any error.
! 698: * --------------------------------------------------------------------------
! 699: * Notes: o if width or height <=0, embedded raster not allocated
! 700: * ======================================================================= */
! 701: /* --- entry point --- */
! 702: subraster *new_subraster ( int width, int height, int pixsz )
! 703: {
! 704: /* -------------------------------------------------------------------------
! 705: Allocations and Declarations
! 706: -------------------------------------------------------------------------- */
! 707: subraster *sp=NULL; /* subraster returned to caller */
! 708: raster *new_raster(), *rp=NULL; /* image raster embedded in sp */
! 709: int delete_subraster(); /* in case new_raster() fails */
! 710: int size = NORMALSIZE, /* default size */
! 711: baseline = height-1; /* and baseline */
! 712: /* -------------------------------------------------------------------------
! 713: allocate and initialize subraster struct
! 714: -------------------------------------------------------------------------- */
! 715: if ( msgfp!=NULL && msglevel>=9999 )
! 716: { fprintf(msgfp,"new_subraster(%d,%d,%d)> entry point\n",
! 717: width,height,pixsz); fflush(msgfp); }
! 718: /* --- allocate subraster struct --- */
! 719: sp = (subraster *)malloc(sizeof(subraster)); /* malloc subraster struct */
! 720: if ( sp == (subraster *)NULL ) /* malloc failed */
! 721: goto end_of_job; /* return error to caller */
! 722: /* --- initialize subraster struct --- */
! 723: sp->type = NOVALUE; /* character or image raster */
! 724: sp->symdef = (mathchardef *)NULL; /* mathchardef identifying image */
! 725: sp->baseline = baseline; /*0 if image is entirely descending*/
! 726: sp->size = size; /* font size 0-4 */
! 727: sp->toprow = sp->leftcol = (-1); /* upper-left corner of subraster */
! 728: sp->image = (raster *)NULL; /*ptr to bitmap image of subraster*/
! 729: /* -------------------------------------------------------------------------
! 730: allocate raster and embed it in subraster, and return to caller
! 731: -------------------------------------------------------------------------- */
! 732: /* --- allocate raster struct if desired --- */
! 733: if ( width>0 && height>0 && pixsz>0 ) /* caller wants raster */
! 734: { if ( (rp=new_raster(width,height,pixsz)) /* allocate embedded raster */
! 735: != NULL ) /* if allocate succeeded */
! 736: sp->image = rp; /* embed raster in subraster */
! 737: else /* or if allocate failed */
! 738: { delete_subraster(sp); /* free non-unneeded subraster */
! 739: sp = NULL; } } /* signal error */
! 740: /* --- back to caller with new subraster or NULL --- */
! 741: end_of_job:
! 742: if ( msgfp!=NULL && msglevel>=9999 )
! 743: { fprintf(msgfp,"new_subraster(%d,%d,%d)> returning (%s)\n",
! 744: width,height,pixsz,(sp==NULL?"null ptr":"success")); fflush(msgfp); }
! 745: return ( sp );
! 746: } /* --- end-of-function new_subraster() --- */
! 747:
! 748:
! 749: /* ==========================================================================
! 750: * Function: new_chardef ( )
! 751: * Purpose: Allocates and initializes a chardef struct,
! 752: * but _not_ the embedded raster struct.
! 753: * --------------------------------------------------------------------------
! 754: * Arguments: none
! 755: * --------------------------------------------------------------------------
! 756: * Returns: ( chardef * ) ptr to allocated and initialized
! 757: * chardef struct, or NULL for any error.
! 758: * --------------------------------------------------------------------------
! 759: * Notes:
! 760: * ======================================================================= */
! 761: /* --- entry point --- */
! 762: chardef *new_chardef ( )
! 763: {
! 764: /* -------------------------------------------------------------------------
! 765: Allocations and Declarations
! 766: -------------------------------------------------------------------------- */
! 767: chardef *cp = (chardef *)NULL; /* chardef ptr returned to caller */
! 768: /* -------------------------------------------------------------------------
! 769: allocate and initialize chardef struct
! 770: -------------------------------------------------------------------------- */
! 771: cp = (chardef *)malloc(sizeof(chardef)); /* malloc chardef struct */
! 772: if ( cp == (chardef *)NULL ) /* malloc failed */
! 773: goto end_of_job; /* return error to caller */
! 774: cp->charnum = cp->location = 0; /* init character description */
! 775: cp->toprow = cp->topleftcol = 0; /* init upper-left corner */
! 776: cp->botrow = cp->botleftcol = 0; /* init lower-left corner */
! 777: cp->image.width = cp->image.height = 0; /* init raster dimensions */
! 778: cp->image.pixsz = 0; /* and #bits per pixel */
! 779: cp->image.pixmap = NULL; /* init raster pixmap as null */
! 780: /* -------------------------------------------------------------------------
! 781: Back to caller with address of chardef struct, or NULL ptr for any error.
! 782: -------------------------------------------------------------------------- */
! 783: end_of_job:
! 784: return ( cp );
! 785: } /* --- end-of-function new_chardef() --- */
! 786:
! 787:
! 788: /* ==========================================================================
! 789: * Function: delete_raster ( rp )
! 790: * Purpose: Destructor for raster.
! 791: * Frees memory for raster bitmap and struct.
! 792: * --------------------------------------------------------------------------
! 793: * Arguments: rp (I) ptr to raster struct to be deleted.
! 794: * --------------------------------------------------------------------------
! 795: * Returns: ( int ) 1 if completed successfully,
! 796: * or 0 otherwise (for any error).
! 797: * --------------------------------------------------------------------------
! 798: * Notes:
! 799: * ======================================================================= */
! 800: /* --- entry point --- */
! 801: int delete_raster ( raster *rp )
! 802: {
! 803: /* -------------------------------------------------------------------------
! 804: free raster bitmap and struct
! 805: -------------------------------------------------------------------------- */
! 806: if ( rp != (raster *)NULL ) /* can't free null ptr */
! 807: {
! 808: if ( rp->pixmap != (pixbyte *)NULL ) /* can't free null ptr */
! 809: free((void *)rp->pixmap); /* free pixmap within raster */
! 810: free((void *)rp); /* lastly, free raster struct */
! 811: } /* --- end-of-if(rp!=NULL) --- */
! 812: return ( 1 ); /* back to caller, 1=okay 0=failed */
! 813: } /* --- end-of-function delete_raster() --- */
! 814:
! 815:
! 816: /* ==========================================================================
! 817: * Function: delete_subraster ( sp )
! 818: * Purpose: Deallocates a subraster (and embedded raster)
! 819: * --------------------------------------------------------------------------
! 820: * Arguments: sp (I) ptr to subraster struct to be deleted.
! 821: * --------------------------------------------------------------------------
! 822: * Returns: ( int ) 1 if completed successfully,
! 823: * or 0 otherwise (for any error).
! 824: * --------------------------------------------------------------------------
! 825: * Notes:
! 826: * ======================================================================= */
! 827: /* --- entry point --- */
! 828: int delete_subraster ( subraster *sp )
! 829: {
! 830: /* -------------------------------------------------------------------------
! 831: free subraster struct
! 832: -------------------------------------------------------------------------- */
! 833: int delete_raster(); /* to delete embedded raster */
! 834: if ( sp != (subraster *)NULL ) /* can't free null ptr */
! 835: {
! 836: if ( sp->type != CHARASTER ) /* not static character data */
! 837: if ( sp->image != NULL ) /*raster allocated within subraster*/
! 838: delete_raster(sp->image); /* so free embedded raster */
! 839: free((void *)sp); /* and free subraster struct itself*/
! 840: } /* --- end-of-if(sp!=NULL) --- */
! 841: return ( 1 ); /* back to caller, 1=okay 0=failed */
! 842: } /* --- end-of-function delete_subraster() --- */
! 843:
! 844:
! 845: /* ==========================================================================
! 846: * Function: delete_chardef ( cp )
! 847: * Purpose: Deallocates a chardef (and bitmap of embedded raster)
! 848: * --------------------------------------------------------------------------
! 849: * Arguments: cp (I) ptr to chardef struct to be deleted.
! 850: * --------------------------------------------------------------------------
! 851: * Returns: ( int ) 1 if completed successfully,
! 852: * or 0 otherwise (for any error).
! 853: * --------------------------------------------------------------------------
! 854: * Notes:
! 855: * ======================================================================= */
! 856: /* --- entry point --- */
! 857: int delete_chardef ( chardef *cp )
! 858: {
! 859: /* -------------------------------------------------------------------------
! 860: free chardef struct
! 861: -------------------------------------------------------------------------- */
! 862: if ( cp != (chardef *)NULL ) /* can't free null ptr */
! 863: {
! 864: if ( cp->image.pixmap != NULL ) /* pixmap allocated within raster */
! 865: free((void *)cp->image.pixmap); /* so free embedded pixmap */
! 866: free((void *)cp); /* and free chardef struct itself */
! 867: } /* --- end-of-if(cp!=NULL) --- */
! 868: /* -------------------------------------------------------------------------
! 869: Back to caller with 1=okay, 0=failed.
! 870: -------------------------------------------------------------------------- */
! 871: return ( 1 );
! 872: } /* --- end-of-function delete_chardef() --- */
! 873:
! 874:
! 875: /* ==========================================================================
! 876: * Function: rastcpy ( rp )
! 877: * Purpose: makes duplicate copy of rp
! 878: * --------------------------------------------------------------------------
! 879: * Arguments: rp (I) ptr to raster struct to be copied
! 880: * --------------------------------------------------------------------------
! 881: * Returns: ( raster * ) ptr to new copy rp,
! 882: * or NULL for any error.
! 883: * --------------------------------------------------------------------------
! 884: * Notes: o
! 885: * ======================================================================= */
! 886: /* --- entry point --- */
! 887: raster *rastcpy ( raster *rp )
! 888: {
! 889: /* -------------------------------------------------------------------------
! 890: Allocations and Declarations
! 891: -------------------------------------------------------------------------- */
! 892: raster *new_raster(), *newrp=NULL; /*copied raster returned to caller*/
! 893: int height= (rp==NULL?0:rp->height), /* original and copied height */
! 894: width = (rp==NULL?0:rp->width), /* original and copied width */
! 895: pixsz = (rp==NULL?0:rp->pixsz), /* #bits per pixel */
! 896: nbytes= (rp==NULL?0:(pixmapsz(rp))); /* #bytes in rp's pixmap */
! 897: /* -------------------------------------------------------------------------
! 898: allocate rotated raster and fill it
! 899: -------------------------------------------------------------------------- */
! 900: /* --- allocate copied raster with same width,height, and copy bitmap --- */
! 901: if ( rp != NULL ) /* nothing to copy if ptr null */
! 902: if ( (newrp = new_raster(width,height,pixsz)) /*same width,height in copy*/
! 903: != NULL ) /* check that allocate succeeded */
! 904: memcpy(newrp->pixmap,rp->pixmap,nbytes); /* fill copied raster pixmap */
! 905: return ( newrp ); /* return copied raster to caller */
! 906: } /* --- end-of-function rastcpy() --- */
! 907:
! 908:
! 909: /* ==========================================================================
! 910: * Function: subrastcpy ( sp )
! 911: * Purpose: makes duplicate copy of sp
! 912: * --------------------------------------------------------------------------
! 913: * Arguments: sp (I) ptr to subraster struct to be copied
! 914: * --------------------------------------------------------------------------
! 915: * Returns: ( subraster * ) ptr to new copy sp,
! 916: * or NULL for any error.
! 917: * --------------------------------------------------------------------------
! 918: * Notes: o
! 919: * ======================================================================= */
! 920: /* --- entry point --- */
! 921: subraster *subrastcpy ( subraster *sp )
! 922: {
! 923: /* -------------------------------------------------------------------------
! 924: Allocations and Declarations
! 925: -------------------------------------------------------------------------- */
! 926: subraster *new_subraster(), *newsp=NULL; /* allocate new subraster */
! 927: raster *rastcpy(), *newrp=NULL; /* and new raster image within it */
! 928: int delete_subraster(); /* dealloc newsp if rastcpy() fails*/
! 929: /* -------------------------------------------------------------------------
! 930: make copy, and return it to caller
! 931: -------------------------------------------------------------------------- */
! 932: if ( sp == NULL ) goto end_of_job; /* nothing to copy */
! 933: /* --- allocate new subraster "envelope" for copy --- */
! 934: if ( (newsp=new_subraster(0,0,0)) /* allocate subraster "envelope" */
! 935: == NULL ) goto end_of_job; /* and quit if we fail to allocate */
! 936: /* --- transparently copy original envelope to new one --- */
! 937: memcpy((void *)newsp,(void *)sp,sizeof(subraster)); /* copy envelope */
! 938: /* --- make a copy of the rasterized image itself, if there is one --- */
! 939: if ( sp->image != NULL ) /* there's an image embedded in sp */
! 940: if ( (newrp = rastcpy(sp->image)) /* so copy rasterized image in sp */
! 941: == NULL ) /* failed to copy successfully */
! 942: { delete_subraster(newsp); /* won't need newsp any more */
! 943: newsp = NULL; /* because we're returning error */
! 944: goto end_of_job; } /* back to caller with error signal*/
! 945: /* --- set new params in new envelope --- */
! 946: newsp->image = newrp; /* new raster image we just copied */
! 947: switch ( sp->type ) /* set new raster image type */
! 948: { case STRINGRASTER: case CHARASTER: newsp->type = STRINGRASTER; break;
! 949: case ASCIISTRING: newsp->type = ASCIISTRING; break;
! 950: case IMAGERASTER: default: newsp->type = IMAGERASTER; break; }
! 951: /* --- return copy of sp to caller --- */
! 952: end_of_job:
! 953: return ( newsp ); /* copy back to caller */
! 954: } /* --- end-of-function subrastcpy() --- */
! 955:
! 956:
! 957: /* ==========================================================================
! 958: * Function: rastrot ( rp )
! 959: * Purpose: rotates rp image 90 degrees right/clockwise
! 960: * --------------------------------------------------------------------------
! 961: * Arguments: rp (I) ptr to raster struct to be rotated
! 962: * --------------------------------------------------------------------------
! 963: * Returns: ( raster * ) ptr to new raster rotated ralative to rp,
! 964: * or NULL for any error.
! 965: * --------------------------------------------------------------------------
! 966: * Notes: o An underbrace is } rotated 90 degrees clockwise,
! 967: * a hat is <, etc.
! 968: * ======================================================================= */
! 969: /* --- entry point --- */
! 970: raster *rastrot ( raster *rp )
! 971: {
! 972: /* -------------------------------------------------------------------------
! 973: Allocations and Declarations
! 974: -------------------------------------------------------------------------- */
! 975: raster *new_raster(), *rotated=NULL; /*rotated raster returned to caller*/
! 976: int height = rp->height, irow, /* original height, row index */
! 977: width = rp->width, icol, /* original width, column index */
! 978: pixsz = rp->pixsz; /* #bits per pixel */
! 979: /* -------------------------------------------------------------------------
! 980: allocate rotated raster and fill it
! 981: -------------------------------------------------------------------------- */
! 982: /* --- allocate rotated raster with flipped width<-->height --- */
! 983: if ( (rotated = new_raster(height,width,pixsz)) /* flip width,height */
! 984: != NULL ) /* check that allocation succeeded */
! 985: /* --- fill rotated raster --- */
! 986: for ( irow=0; irow<height; irow++ ) /* for each row of rp */
! 987: for ( icol=0; icol<width; icol++ ) /* and each column of rp */
! 988: { int value = getpixel(rp,irow,icol);
! 989: /* setpixel(rotated,icol,irow,value); } */
! 990: setpixel(rotated,icol,(height-1-irow),value); }
! 991: return ( rotated ); /* return rotated raster to caller */
! 992: } /* --- end-of-function rastrot() --- */
! 993:
! 994:
! 995: /* ==========================================================================
! 996: * Function: rastput ( target, source, top, left, isopaque )
! 997: * Purpose: Overlays source onto target,
! 998: * with the 0,0-bit of source onto the top,left-bit of target.
! 999: * --------------------------------------------------------------------------
! 1000: * Arguments: target (I) ptr to target raster struct
! 1001: * source (I) ptr to source raster struct
! 1002: * top (I) int containing 0 ... target->height - 1
! 1003: * left (I) int containing 0 ... target->width - 1
! 1004: * isopaque (I) int containing false (zero) to allow
! 1005: * original 1-bits of target to "show through"
! 1006: * 0-bits of source.
! 1007: * --------------------------------------------------------------------------
! 1008: * Returns: ( int ) 1 if completed successfully,
! 1009: * or 0 otherwise (for any error).
! 1010: * --------------------------------------------------------------------------
! 1011: * Notes:
! 1012: * ======================================================================= */
! 1013: /* --- entry point --- */
! 1014: int rastput ( raster *target, raster *source,
! 1015: int top, int left, int isopaque )
! 1016: {
! 1017: /* -------------------------------------------------------------------------
! 1018: Allocations and Declarations
! 1019: -------------------------------------------------------------------------- */
! 1020: int irow, icol, /* indexes over source raster */
! 1021: twidth=target->width, theight=target->height, /*target width,height*/
! 1022: tpix, ntpix = twidth*theight; /* #pixels in target */
! 1023: int isfatal = 0, /* true to abend on out-of-bounds error */
! 1024: isstrict = 0/*1*/, /* true for strict bounds check - no "wrap"*/
! 1025: isokay = 1; /* true if no pixels out-of-bounds */
! 1026: /* -------------------------------------------------------------------------
! 1027: superimpose source onto target, one bit at a time
! 1028: -------------------------------------------------------------------------- */
! 1029: if ( isstrict && (top<0 || left<0) ) /* args fail strict test */
! 1030: isokay = 0; /* so just return error */
! 1031: else
! 1032: for ( irow=0; irow<source->height; irow++ ) /* for each scan line */
! 1033: {
! 1034: tpix = (top+irow)*target->width + left - 1; /*first target pixel (-1)*/
! 1035: for ( icol=0; icol<source->width; icol++ ) /* each pixel in scan line */
! 1036: {
! 1037: int svalue = getpixel(source,irow,icol); /* source pixel value */
! 1038: ++tpix; /* bump target pixel */
! 1039: if ( msgfp!=NULL && msglevel>=9999 ) /* debugging output */
! 1040: { fprintf(msgfp,"rastput> tpix,ntpix=%d,%d top,irow,theight=%d,%d,%d "
! 1041: "left,icol,twidth=%d,%d,%d\n", tpix,ntpix, top,irow,theight,
! 1042: left,icol,twidth); fflush(msgfp); }
! 1043: if ( tpix >= ntpix /* bounds check failed */
! 1044: || (isstrict && (irow+top>=theight || icol+left>=twidth)) )
! 1045: { isokay = 0; /* reset okay flag */
! 1046: if ( isfatal ) goto end_of_job; /* abort if error is fatal */
! 1047: else break; } /*or just go on to next row*/
! 1048: if ( tpix >= 0 ) /* bounds check okay */
! 1049: if ( svalue!=0 || isopaque ) /*got dark or opaque source*/
! 1050: setpixel(target,irow+top,icol+left,svalue); /*overlay source on target*/
! 1051: } /* --- end-of-for(icol) --- */
! 1052: } /* --- end-of-for(irow) --- */
! 1053: /* -------------------------------------------------------------------------
! 1054: Back to caller with 1=okay, 0=failed.
! 1055: -------------------------------------------------------------------------- */
! 1056: end_of_job:
! 1057: return ( isokay /*isfatal? (tpix<ntpix? 1:0) : 1*/ );
! 1058: } /* --- end-of-function rastput() --- */
! 1059:
! 1060:
! 1061: /* ==========================================================================
! 1062: * Function: rastcompose ( sp1, sp2, offset2, isalign, isfree )
! 1063: * Purpose: Overlays sp2 on top of sp1, leaving both unchanged
! 1064: * and returning a newly-allocated composite subraster.
! 1065: * Frees/deletes input sp1 and/or sp2 depending on value
! 1066: * of isfree (0=none, 1=sp1, 2=sp2, 3=both).
! 1067: * --------------------------------------------------------------------------
! 1068: * Arguments: sp1 (I) subraster * to "underneath" subraster,
! 1069: * whose baseline is preserved
! 1070: * sp2 (I) subraster * to "overlaid" subraster
! 1071: * offset2 (I) int containing 0 or number of pixels
! 1072: * to horizontally shift sp2 relative to sp1,
! 1073: * either positive (right) or negative
! 1074: * isalign (I) int containing 1 to align baselines,
! 1075: * or 0 to vertically center sp2 over sp1
! 1076: * isfree (I) int containing 1=free sp1 before return,
! 1077: * 2=free sp2, 3=free both, 0=free none.
! 1078: * --------------------------------------------------------------------------
! 1079: * Returns: ( subraster * ) pointer to constructed subraster
! 1080: * or NULL for any error
! 1081: * --------------------------------------------------------------------------
! 1082: * Notes:
! 1083: * ======================================================================= */
! 1084: /* --- entry point --- */
! 1085: subraster *rastcompose ( subraster *sp1, subraster *sp2, int offset2,
! 1086: int isalign, int isfree )
! 1087: {
! 1088: /* -------------------------------------------------------------------------
! 1089: Allocations and Declarations
! 1090: -------------------------------------------------------------------------- */
! 1091: subraster *new_subraster(), *sp=(subraster *)NULL; /* returned subraster */
! 1092: raster *rp=(raster *)NULL; /* new composite raster in sp */
! 1093: int delete_subraster(); /* in case isfree non-zero */
! 1094: int rastput(); /*place sp1,sp2 in composite raster*/
! 1095: int base1 = sp1->baseline, /*baseline for underlying subraster*/
! 1096: height1 = (sp1->image)->height, /* height for underlying subraster */
! 1097: width1 = (sp1->image)->width, /* width for underlying subraster */
! 1098: pixsz1 = (sp1->image)->pixsz, /* pixsz for underlying subraster */
! 1099: base2 = sp2->baseline, /*baseline for overlaid subraster */
! 1100: height2 = (sp2->image)->height, /* height for overlaid subraster */
! 1101: width2 = (sp2->image)->width, /* width for overlaid subraster */
! 1102: pixsz2 = (sp2->image)->pixsz; /* pixsz for overlaid subraster */
! 1103: int height=0, width=0, pixsz=0, base=0; /* overlaid composite */
! 1104: /* -------------------------------------------------------------------------
! 1105: Initialization
! 1106: -------------------------------------------------------------------------- */
! 1107: /* --- determine height, width and baseline of composite raster --- */
! 1108: if ( isalign ) /* baselines of sp1,sp2 aligned */
! 1109: { height = max2(base1+1,base2+1) /* max height above baseline */
! 1110: + max2(height1-base1-1,height2-base2-1); /*+ max descending below*/
! 1111: base = max2(base1,base2); } /* max space above baseline */
! 1112: else /* baselines not aligned */
! 1113: { height = max2(height1,height2); /* max height */
! 1114: base = base1 + (height-height1)/2; } /* baseline for sp1 */
! 1115: width = max2(width1,width2+abs(offset2)); /* max width */
! 1116: pixsz = max2(pixsz1,pixsz2); /* bitmap,bytemap becomes bytemap */
! 1117: /* -------------------------------------------------------------------------
! 1118: allocate concatted composite subraster
! 1119: -------------------------------------------------------------------------- */
! 1120: /* --- allocate returned subraster (and then initialize it) --- */
! 1121: if ( (sp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 1122: == (subraster *)NULL ) goto end_of_job; /* failed, so quit */
! 1123: /* --- initialize subraster parameters --- */
! 1124: sp->type = IMAGERASTER; /* image */
! 1125: sp->baseline = base; /* composite baseline */
! 1126: sp->size = sp1->size; /* underlying char is sp1 */
! 1127: /* --- extract raster from subraster --- */
! 1128: rp = sp->image; /* raster allocated in subraster */
! 1129: /* -------------------------------------------------------------------------
! 1130: overlay sp1 and sp2 in new composite raster
! 1131: -------------------------------------------------------------------------- */
! 1132: if ( isalign )
! 1133: { rastput (rp, sp1->image, base-base1, (width-width1)/2, 1); /*underlying*/
! 1134: rastput (rp, sp2->image, base-base2, /*overlaid*/
! 1135: (width-width2)/2+offset2, 0); }
! 1136: else
! 1137: { rastput (rp, sp1->image, base-base1, (width-width1)/2, 1); /*underlying*/
! 1138: rastput (rp, sp2->image, (height-height2)/2, /*overlaid*/
! 1139: (width-width2)/2+offset2, 0); }
! 1140: /* -------------------------------------------------------------------------
! 1141: free input if requested
! 1142: -------------------------------------------------------------------------- */
! 1143: if ( isfree > 0 ) /* caller wants input freed */
! 1144: { if ( isfree==1 || isfree>2 ) delete_subraster(sp1); /* free sp1 */
! 1145: if ( isfree >= 2 ) delete_subraster(sp2); } /* and/or sp2 */
! 1146: /* -------------------------------------------------------------------------
! 1147: Back to caller with pointer to concatted subraster or with null for error
! 1148: -------------------------------------------------------------------------- */
! 1149: end_of_job:
! 1150: return ( sp ); /* back with subraster or null ptr */
! 1151: } /* --- end-of-function rastcompose() --- */
! 1152:
! 1153:
! 1154: /* ==========================================================================
! 1155: * Function: rastcat ( sp1, sp2, isfree )
! 1156: * Purpose: "Concatanates" subrasters sp1||sp2, leaving both unchanged
! 1157: * and returning a newly-allocated subraster.
! 1158: * Frees/deletes input sp1 and/or sp2 depending on value
! 1159: * of isfree (0=none, 1=sp1, 2=sp2, 3=both).
! 1160: * --------------------------------------------------------------------------
! 1161: * Arguments: sp1 (I) subraster * to left-hand subraster
! 1162: * sp2 (I) subraster * to right-hand subraster
! 1163: * isfree (I) int containing 1=free sp1 before return,
! 1164: * 2=free sp2, 3=free both, 0=free none.
! 1165: * --------------------------------------------------------------------------
! 1166: * Returns: ( subraster * ) pointer to constructed subraster sp1||sp2
! 1167: * or NULL for any error
! 1168: * --------------------------------------------------------------------------
! 1169: * Notes:
! 1170: * ======================================================================= */
! 1171: /* --- entry point --- */
! 1172: subraster *rastcat ( subraster *sp1, subraster *sp2, int isfree )
! 1173: {
! 1174: /* -------------------------------------------------------------------------
! 1175: Allocations and Declarations
! 1176: -------------------------------------------------------------------------- */
! 1177: subraster *new_subraster(), *sp=(subraster *)NULL; /* returned subraster */
! 1178: raster *rp=(raster *)NULL; /* new concatted raster */
! 1179: int delete_subraster(); /* in case isfree non-zero */
! 1180: int rastput(); /*place sp1,sp2 in concatted raster*/
! 1181: int type_raster(); /* debugging display */
! 1182: int base1 = sp1->baseline, /*baseline for left-hand subraster*/
! 1183: height1 = (sp1->image)->height, /* height for left-hand subraster */
! 1184: width1 = (sp1->image)->width, /* width for left-hand subraster */
! 1185: pixsz1 = (sp1->image)->pixsz, /* pixsz for left-hand subraster */
! 1186: type1 = sp1->type, /* image type for left-hand */
! 1187: base2 = sp2->baseline, /*baseline for right-hand subraster*/
! 1188: height2 = (sp2->image)->height, /* height for right-hand subraster */
! 1189: width2 = (sp2->image)->width, /* width for right-hand subraster */
! 1190: pixsz2 = (sp2->image)->pixsz, /* pixsz for right-hand subraster */
! 1191: type2 = sp2->type; /* image type for right-hand */
! 1192: int height=0, width=0, pixsz=0, base=0; /*concatted sp1||sp2 composite*/
! 1193: int issquash = (squashmargin!=0?1:0), /* true to "squash" sp1||sp2 */
! 1194: isopaque = (issquash?0:1), /* not oppaque if squashing */
! 1195: rastsquash(), isblank=0, nsquash=0, /* #cols to squash */
! 1196: oldsquashmargin = squashmargin; /* save original squashmargin */
! 1197: int blanksignal = (-991234); /*rastsquash signal right-hand blank*/
! 1198: mathchardef *symdef1 = sp1->symdef, /*mathchardef of last left-hand char*/
! 1199: *symdef2 = sp2->symdef; /* mathchardef of right-hand char */
! 1200: int class1 = (symdef1==NULL?ORDINARY:symdef1->class), /* symdef->class */
! 1201: class2 = (symdef2==NULL?ORDINARY:symdef2->class), /* or default */
! 1202: smash1 = (symdef1!=NULL)&&(class1==ORDINARY||class1==VARIABLE||
! 1203: class1==OPENING||class1==CLOSING||class1==PUNCTION),
! 1204: smash2 = (symdef2!=NULL)&&(class2==ORDINARY||class2==VARIABLE||
! 1205: class2==OPENING||class2==CLOSING||class2==PUNCTION),
! 1206: space = fontsize/2+1; /* #cols between sp1 and sp2 */
! 1207: /* -------------------------------------------------------------------------
! 1208: Initialization
! 1209: -------------------------------------------------------------------------- */
! 1210: /* --- determine inter-character space from character class --- */
! 1211: if ( !isstring )
! 1212: space = max2(2,(symspace[class1][class2] + fontsize-3)); /* space */
! 1213: else space = 1; /* space for ascii string */
! 1214: /* --- determine squash --- */
! 1215: if ( !isstring ) /* don't squash strings */
! 1216: if ( issquash ) { /* raster squash wanted */
! 1217: int maxsquash = rastsquash(sp1,sp2), /* calculate max squash space */
! 1218: margin = squashmargin; /* init margin without delta */
! 1219: if ( (1 && smash1 && smash2) /* concatanating two chars */
! 1220: || (1 && type1!=IMAGERASTER && type2!=IMAGERASTER) )
! 1221: /*maxsquash = 0;*/ /* turn off squash */
! 1222: margin = max2(space-1,0); /* force small squashmargin */
! 1223: else /* adjust for delta if images */
! 1224: if ( issquashdelta ) /* squashmargin is a delta value */
! 1225: margin += fontsize; /* add displaystyle base to margin */
! 1226: if ( maxsquash == blanksignal ) /* sp2 is intentional blank */
! 1227: isblank = 1; /* set blank flag signal */
! 1228: else /* see how much extra space we have*/
! 1229: if ( maxsquash > margin ) /* enough space for adjustment */
! 1230: nsquash = maxsquash-margin; /* make adjustment */
! 1231: if ( msgfp!=NULL && msglevel>=99 ) /* display squash results */
! 1232: { fprintf(msgfp,"rastcat> maxsquash=%d, margin=%d, nsquash=%d\n",
! 1233: maxsquash,margin,nsquash);
! 1234: fprintf(msgfp,"rastcat> type1=%d,2=%d, class1=%d,2=%d\n", type1,type2,
! 1235: (symdef1==NULL?-999:class1),(symdef2==NULL?-999:class2));
! 1236: fflush(msgfp); }
! 1237: } /* --- end-of-if(issquash) --- */
! 1238: /* --- determine height, width and baseline of composite raster --- */
! 1239: if ( !isstring )
! 1240: { height = max2(base1+1,base2+1) /* max height above baseline */
! 1241: + max2(height1-base1-1,height2-base2-1); /*+ max descending below*/
! 1242: width = width1+width2 + space-nsquash; /*add widths and space-squash*/
! 1243: width = max3(width,width1,width2); } /* don't "over-squash" composite */
! 1244: else /* ascii string */
! 1245: { height = 1; /* default */
! 1246: width = width1 + width2 + space - 1; } /* no need for two nulls */
! 1247: pixsz = max2(pixsz1,pixsz2); /* bitmap||bytemap becomes bytemap */
! 1248: base = max2(base1,base2); /* max space above baseline */
! 1249: if ( msgfp!=NULL && msglevel>=9999 ) /* display components */
! 1250: { fprintf(msgfp,"rastcat> Left-hand ht,width,pixsz,base = %d,%d,%d,%d\n",
! 1251: height1,width1,pixsz1,base1);
! 1252: type_raster(sp1->image,msgfp); /* display left-hand raster */
! 1253: fprintf(msgfp,"rastcat> Right-hand ht,width,pixsz,base = %d,%d,%d,%d\n",
! 1254: height2,width2,pixsz2,base2);
! 1255: type_raster(sp2->image,msgfp); /* display right-hand raster */
! 1256: fprintf(msgfp,
! 1257: "rastcat> Composite ht,width,squash,pixsz,base = %d,%d,%d,%d,%d\n",
! 1258: height,width,nsquash,pixsz,base);
! 1259: fflush(msgfp); } /* flush msgfp buffer */
! 1260: /* -------------------------------------------------------------------------
! 1261: allocate concatted composite subraster
! 1262: -------------------------------------------------------------------------- */
! 1263: /* --- allocate returned subraster (and then initialize it) --- */
! 1264: if ( msgfp!=NULL && msglevel>=9999 )
! 1265: { fprintf(msgfp,"rastcat> calling new_subraster(%d,%d,%d)\n",
! 1266: width,height,pixsz); fflush(msgfp); }
! 1267: if ( (sp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 1268: == (subraster *)NULL ) /* failed */
! 1269: { if ( msgfp!=NULL && msglevel>=1 ) /* report failure */
! 1270: { fprintf(msgfp,"rastcat> new_subraster(%d,%d,%d) failed\n",
! 1271: width,height,pixsz); fflush(msgfp); }
! 1272: goto end_of_job; } /* failed, so quit */
! 1273: /* --- initialize subraster parameters --- */
! 1274: /* sp->type = (!isstring?STRINGRASTER:ASCIISTRING); */ /*concatted string*/
! 1275: if ( !isstring )
! 1276: sp->type = type2;/*(type1==type2?type2:IMAGERASTER);*/ /*string or image*/
! 1277: else
! 1278: sp->type = ASCIISTRING; /* concatted ascii string */
! 1279: sp->symdef = symdef2; /* rightmost char is sp2 */
! 1280: sp->baseline = base; /* composite baseline */
! 1281: sp->size = sp2->size; /* rightmost char is sp2 */
! 1282: if ( isblank ) /* need to propagate blanksignal */
! 1283: sp->type = blanksignal; /* may not be completely safe??? */
! 1284: /* --- extract raster from subraster --- */
! 1285: rp = sp->image; /* raster allocated in subraster */
! 1286: /* -------------------------------------------------------------------------
! 1287: overlay sp1 and sp2 in new composite raster
! 1288: -------------------------------------------------------------------------- */
! 1289: if ( msgfp!=NULL && msglevel>=9999 )
! 1290: { fprintf(msgfp,"rastcat> calling rastput() to concatanate left||right\n");
! 1291: fflush(msgfp); } /* flush msgfp buffer */
! 1292: if ( !isstring )
! 1293: rastput (rp, sp1->image, base-base1, /* overlay left-hand */
! 1294: max2(0,nsquash-width1), 1); /* plus any residual squash space */
! 1295: else
! 1296: memcpy(rp->pixmap,(sp1->image)->pixmap,width1-1); /*init left string*/
! 1297: if ( msgfp!=NULL && msglevel>=9999 )
! 1298: { type_raster(sp->image,msgfp); /* display composite raster */
! 1299: fflush(msgfp); } /* flush msgfp buffer */
! 1300: if ( !isstring )
! 1301: rastput (rp, sp2->image, base-base2, /* overlay right-hand */
! 1302: max2(0,width1+space-nsquash), isopaque); /* minus any squashed space */
! 1303: else
! 1304: { strcpy((char *)(rp->pixmap)+width1-1+space,(char *)((sp2->image)->pixmap));
! 1305: ((char *)(rp->pixmap))[width1+width2+space-2] = '\000'; } /*null-term*/
! 1306: if ( msgfp!=NULL && msglevel>=9999 )
! 1307: { type_raster(sp->image,msgfp); /* display composite raster */
! 1308: fflush(msgfp); } /* flush msgfp buffer */
! 1309: /* -------------------------------------------------------------------------
! 1310: free input if requested
! 1311: -------------------------------------------------------------------------- */
! 1312: if ( isfree > 0 ) /* caller wants input freed */
! 1313: { if ( isfree==1 || isfree>2 ) delete_subraster(sp1); /* free sp1 */
! 1314: if ( isfree >= 2 ) delete_subraster(sp2); } /* and/or sp2 */
! 1315: /* -------------------------------------------------------------------------
! 1316: Back to caller with pointer to concatted subraster or with null for error
! 1317: -------------------------------------------------------------------------- */
! 1318: end_of_job:
! 1319: squashmargin = oldsquashmargin; /* reset original squashmargin */
! 1320: return ( sp ); /* back with subraster or null ptr */
! 1321: } /* --- end-of-function rastcat() --- */
! 1322:
! 1323:
! 1324: /* ==========================================================================
! 1325: * Function: rastack ( sp1, sp2, base, space, iscenter, isfree )
! 1326: * Purpose: Stack subrasters sp2 atop sp1, leaving both unchanged
! 1327: * and returning a newly-allocated subraster,
! 1328: * whose baseline is sp1's if base=1, or sp2's if base=2.
! 1329: * Frees/deletes input sp1 and/or sp2 depending on value
! 1330: * of isfree (0=none, 1=sp1, 2=sp2, 3=both).
! 1331: * --------------------------------------------------------------------------
! 1332: * Arguments: sp1 (I) subraster * to lower subraster
! 1333: * sp2 (I) subraster * to upper subraster
! 1334: * base (I) int containing 1 if sp1 is baseline,
! 1335: * or 2 if sp2 is baseline.
! 1336: * space (I) int containing #rows blank space inserted
! 1337: * between sp1's image and sp2's image.
! 1338: * iscenter (I) int containing 1 to center both sp1 and sp2
! 1339: * in stacked array, 0 to left-justify both
! 1340: * isfree (I) int containing 1=free sp1 before return,
! 1341: * 2=free sp2, 3=free both, 0=free none.
! 1342: * --------------------------------------------------------------------------
! 1343: * Returns: ( subraster * ) pointer to constructed subraster sp2 atop sp1
! 1344: * or NULL for any error
! 1345: * --------------------------------------------------------------------------
! 1346: * Notes:
! 1347: * ======================================================================= */
! 1348: /* --- entry point --- */
! 1349: subraster *rastack ( subraster *sp1, subraster *sp2,
! 1350: int base, int space, int iscenter, int isfree )
! 1351: {
! 1352: /* -------------------------------------------------------------------------
! 1353: Allocations and Declarations
! 1354: -------------------------------------------------------------------------- */
! 1355: subraster *new_subraster(), *sp=(subraster *)NULL; /* returned subraster */
! 1356: raster *rp=(raster *)NULL; /* new stacked raster in sp */
! 1357: int delete_subraster(); /* in case isfree non-zero */
! 1358: int rastput(); /* place sp1,sp2 in stacked raster */
! 1359: int base1 = sp1->baseline, /* baseline for lower subraster */
! 1360: height1 = (sp1->image)->height, /* height for lower subraster */
! 1361: width1 = (sp1->image)->width, /* width for lower subraster */
! 1362: pixsz1 = (sp1->image)->pixsz, /* pixsz for lower subraster */
! 1363: base2 = sp2->baseline, /* baseline for upper subraster */
! 1364: height2 = (sp2->image)->height, /* height for upper subraster */
! 1365: width2 = (sp2->image)->width, /* width for upper subraster */
! 1366: pixsz2 = (sp2->image)->pixsz; /* pixsz for upper subraster */
! 1367: int height=0, width=0, pixsz=0, baseline=0; /*for stacked sp2 atop sp1*/
! 1368: mathchardef *symdef1 = sp1->symdef, /* mathchardef of right lower char */
! 1369: *symdef2 = sp2->symdef; /* mathchardef of right upper char */
! 1370: /* -------------------------------------------------------------------------
! 1371: Initialization
! 1372: -------------------------------------------------------------------------- */
! 1373: /* --- determine height, width and baseline of composite raster --- */
! 1374: height = height1 + space + height2; /* sum of heights plus space */
! 1375: width = max2(width1,width2); /* max width is overall width */
! 1376: pixsz = max2(pixsz1,pixsz2); /* bitmap||bytemap becomes bytemap */
! 1377: baseline = (base==1? height2+space+base1 : (base==2? base2 : 0));
! 1378: /* -------------------------------------------------------------------------
! 1379: allocate stacked composite subraster (with embedded raster)
! 1380: -------------------------------------------------------------------------- */
! 1381: /* --- allocate returned subraster (and then initialize it) --- */
! 1382: if ( (sp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 1383: == (subraster *)NULL ) goto end_of_job; /* failed, so quit */
! 1384: /* --- initialize subraster parameters --- */
! 1385: sp->type = IMAGERASTER; /* stacked rasters */
! 1386: sp->symdef = (base==1? symdef1 : (base==2? symdef2 : NULL)); /* symdef */
! 1387: sp->baseline = baseline; /* composite baseline */
! 1388: sp->size = (base==1? sp1->size : (base==2? sp2->size : NORMALSIZE)); /*size*/
! 1389: /* --- extract raster from subraster --- */
! 1390: rp = sp->image; /* raster embedded in subraster */
! 1391: /* -------------------------------------------------------------------------
! 1392: overlay sp1 and sp2 in new composite raster
! 1393: -------------------------------------------------------------------------- */
! 1394: if ( iscenter == 1 ) /* center both sp1 and sp2 */
! 1395: { rastput (rp, sp2->image, 0, (width-width2)/2, 1); /* overlay upper */
! 1396: rastput (rp, sp1->image, height2+space, (width-width1)/2, 1); } /*lower*/
! 1397: else /* left-justify both sp1 and sp2 */
! 1398: { rastput (rp, sp2->image, 0, 0, 1); /* overlay upper */
! 1399: rastput (rp, sp1->image, height2+space, 0, 1); } /*lower*/
! 1400: /* -------------------------------------------------------------------------
! 1401: free input if requested
! 1402: -------------------------------------------------------------------------- */
! 1403: if ( isfree > 0 ) /* caller wants input freed */
! 1404: { if ( isfree==1 || isfree>2 ) delete_subraster(sp1); /* free sp1 */
! 1405: if ( isfree>=2 ) delete_subraster(sp2); } /* and/or sp2 */
! 1406: /* -------------------------------------------------------------------------
! 1407: Back to caller with pointer to stacked subraster or with null for error
! 1408: -------------------------------------------------------------------------- */
! 1409: end_of_job:
! 1410: return ( sp ); /* back with subraster or null ptr */
! 1411: } /* --- end-of-function rastack() --- */
! 1412:
! 1413:
! 1414: /* ==========================================================================
! 1415: * Function: rastile ( tiles, ntiles )
! 1416: * Purpose: Allocate and build up a composite raster
! 1417: * from the ntiles components/characters supplied in tiles.
! 1418: * --------------------------------------------------------------------------
! 1419: * Arguments: tiles (I) subraster * to array of subraster structs
! 1420: * describing the components and their locations
! 1421: * ntiles (I) int containing number of subrasters in tiles[]
! 1422: * --------------------------------------------------------------------------
! 1423: * Returns: ( raster * ) ptr to composite raster,
! 1424: * or NULL for any error.
! 1425: * --------------------------------------------------------------------------
! 1426: * Notes: o The top,left corner of a raster is row=0,col=0
! 1427: * with row# increasing as you move down,
! 1428: * and col# increasing as you move right.
! 1429: * Metafont numbers rows with the baseline=0,
! 1430: * so the top row is a positive number that
! 1431: * decreases as you move down.
! 1432: * o rastile() is no longer used.
! 1433: * It was used by an earlier rasterize() algorithm,
! 1434: * and I've left it in place should it be needed again.
! 1435: * But recent changes haven't been tested/exercised.
! 1436: * ======================================================================= */
! 1437: /* --- entry point --- */
! 1438: raster *rastile ( subraster *tiles, int ntiles )
! 1439: {
! 1440: /* -------------------------------------------------------------------------
! 1441: Allocations and Declarations
! 1442: -------------------------------------------------------------------------- */
! 1443: raster *new_raster(), *composite=(raster *)NULL; /*raster back to caller*/
! 1444: int width=0, height=0, pixsz=0, /*width,height,pixsz of composite raster*/
! 1445: toprow=9999, rightcol=-999, /* extreme upper-right corner of tiles */
! 1446: botrow=-999, leftcol=9999; /* extreme lower-left corner of tiles */
! 1447: int itile; /* tiles[] index */
! 1448: int rastput(); /* overlay each tile in composite raster */
! 1449: /* -------------------------------------------------------------------------
! 1450: run through tiles[] to determine dimensions for composite raster
! 1451: -------------------------------------------------------------------------- */
! 1452: /* --- determine row and column bounds of composite raster --- */
! 1453: for ( itile=0; itile<ntiles; itile++ )
! 1454: {
! 1455: subraster *tile = &(tiles[itile]); /* ptr to current tile */
! 1456: /* --- upper-left corner of composite --- */
! 1457: toprow = min2(toprow, tile->toprow);
! 1458: leftcol = min2(leftcol, tile->leftcol);
! 1459: /* --- lower-right corner of composite --- */
! 1460: botrow = max2(botrow, tile->toprow + (tile->image)->height - 1);
! 1461: rightcol = max2(rightcol, tile->leftcol + (tile->image)->width - 1);
! 1462: /* --- pixsz of composite --- */
! 1463: pixsz = max2(pixsz,(tile->image)->pixsz);
! 1464: } /* --- end-of-for(itile) --- */
! 1465: /* --- calculate width and height from bounds --- */
! 1466: width = rightcol - leftcol + 1;
! 1467: height = botrow - toprow + 1;
! 1468: /* --- sanity check (quit if bad dimensions) --- */
! 1469: if ( width<1 || height<1 ) goto end_of_job;
! 1470: /* -------------------------------------------------------------------------
! 1471: allocate composite raster, and embed tiles[] within it
! 1472: -------------------------------------------------------------------------- */
! 1473: /* --- allocate composite raster --- */
! 1474: if ( (composite=new_raster(width,height,pixsz)) /*allocate composite raster*/
! 1475: == (raster *)NULL ) goto end_of_job; /* and quit if failed */
! 1476: /* --- embed tiles[] in composite --- */
! 1477: for ( itile=0; itile<ntiles; itile++ )
! 1478: { subraster *tile = &(tiles[itile]); /* ptr to current tile */
! 1479: rastput (composite, tile->image, /* overlay tile image at...*/
! 1480: tile->toprow-toprow, tile->leftcol-leftcol, 1); } /*upper-left corner*/
! 1481: /* -------------------------------------------------------------------------
! 1482: Back to caller with composite raster (or null for any error)
! 1483: -------------------------------------------------------------------------- */
! 1484: end_of_job:
! 1485: return ( composite ); /* back with composite or null ptr */
! 1486: } /* --- end-of-function rastile() --- */
! 1487:
! 1488:
! 1489: /* ==========================================================================
! 1490: * Function: rastsquash ( sp1, sp2 )
! 1491: * Purpose: When concatanating sp1||sp2, calculate #pixels
! 1492: * we can "squash sp2 left"
! 1493: * --------------------------------------------------------------------------
! 1494: * Arguments: sp1 (I) subraster * to left-hand raster
! 1495: * sp2 (I) subraster * to right-hand raster
! 1496: * --------------------------------------------------------------------------
! 1497: * Returns: ( int ) max #pixels we can squash sp1||sp2,
! 1498: * or "blanksignal" if sp2 intentionally blank,
! 1499: * or 0 for any error.
! 1500: * --------------------------------------------------------------------------
! 1501: * Notes: o
! 1502: * ======================================================================= */
! 1503: /* --- entry point --- */
! 1504: int rastsquash ( subraster *sp1, subraster *sp2 )
! 1505: {
! 1506: /* -------------------------------------------------------------------------
! 1507: Allocations and Declarations
! 1508: -------------------------------------------------------------------------- */
! 1509: int nsquash = 0; /* #pixels to squash sp1||sp2 */
! 1510: int base1 = sp1->baseline, /*baseline for left-hand subraster*/
! 1511: height1 = (sp1->image)->height, /* height for left-hand subraster */
! 1512: width1 = (sp1->image)->width, /* width for left-hand subraster */
! 1513: base2 = sp2->baseline, /*baseline for right-hand subraster*/
! 1514: height2 = (sp2->image)->height, /* height for right-hand subraster */
! 1515: width2 = (sp2->image)->width; /* width for right-hand subraster */
! 1516: int base = max2(base1,base2), /* max ascenders - 1 above baseline*/
! 1517: top1=base-base1, top2=base-base2, /* top irow indexes for sp1, sp2 */
! 1518: bot1=top1+height1-1, bot2=top2+height2-1, /* bot irow indexes */
! 1519: height = max2(bot1,bot2)+1; /* total height */
! 1520: int irow1=0,irow2=0, icol=0; /* row,col indexes */
! 1521: int firstcol1[1025], nfirst1=0, /* 1st sp1 col containing set pixel*/
! 1522: firstcol2[1025], nfirst2=0; /* 1st sp2 col containing set pixel*/
! 1523: int blanksignal = (-991234); /*rastsquash signal right-hand blank*/
! 1524: int smin=9999, xmin=9999,ymin=9999; /* min separation (s=x+y) */
! 1525: int type_raster(); /* display debugging output */
! 1526: /* -------------------------------------------------------------------------
! 1527: find right edge of sp1 and left edge of sp2 (these will be abutting edges)
! 1528: -------------------------------------------------------------------------- */
! 1529: /* --- check args --- */
! 1530: if ( isstring ) goto end_of_job; /* ignore string rasters */
! 1531: if ( height > 1023 ) goto end_of_job; /* don't try to squash huge image */
! 1532: if ( sp2->type == blanksignal ) /*blanksignal was propagated to us*/
! 1533: goto end_of_job; /* don't squash intentional blank */
! 1534: /* --- init firstcol1[], firstcol2[] --- */
! 1535: for ( irow1=0; irow1<height; irow1++ ) /* for each row */
! 1536: firstcol1[irow1] = firstcol2[irow1] = blanksignal; /* signal empty rows */
! 1537: /* --- set firstcol2[] indicating left edge of sp2 --- */
! 1538: for ( irow2=top2; irow2<=bot2; irow2++ ) /* for each row inside sp2 */
! 1539: for ( icol=0; icol<width2; icol++ ) /* find first non-empty col in row */
! 1540: if ( getpixel(sp2->image,irow2-top2,icol) != 0 ) /* found a set pixel */
! 1541: { firstcol2[irow2] = icol; /* icol is #cols from left edge */
! 1542: nfirst2++; /* bump #rows containing set pixels*/
! 1543: break; } /* and go on to next row */
! 1544: if ( nfirst2 < 1 ) /*right-hand sp2 is completely blank*/
! 1545: { nsquash = blanksignal; /* signal intentional blanks */
! 1546: goto end_of_job; } /* don't squash intentional blanks */
! 1547: /* --- now check if preceding image in sp1 was an intentional blank --- */
! 1548: if ( sp1->type == blanksignal ) /*blanksignal was propagated to us*/
! 1549: goto end_of_job; /* don't squash intentional blank */
! 1550: /* --- set firstcol1[] indicating right edge of sp1 --- */
! 1551: for ( irow1=top1; irow1<=bot1; irow1++ ) /* for each row inside sp1 */
! 1552: for ( icol=width1-1; icol>=0; icol-- ) /* find last non-empty col in row */
! 1553: if ( getpixel(sp1->image,irow1-top1,icol) != 0 ) /* found a set pixel */
! 1554: { firstcol1[irow1] = (width1-1)-icol; /* save #cols from right edge */
! 1555: nfirst1++; /* bump #rows containing set pixels*/
! 1556: break; } /* and go on to next row */
! 1557: if ( nfirst1 < 1 ) /*left-hand sp1 is completely blank*/
! 1558: goto end_of_job; /* don't squash intentional blanks */
! 1559: /* -------------------------------------------------------------------------
! 1560: find minimum separation
! 1561: -------------------------------------------------------------------------- */
! 1562: for ( irow2=top2; irow2<=bot2; irow2++ ) { /* check each row inside sp2 */
! 1563: int margin1, margin2=firstcol2[irow2]; /* #cols to first set pixel */
! 1564: if ( margin2 != blanksignal ) /* irow2 not an empty/blank row */
! 1565: for ( irow1=max2(irow2-smin,top1); ; irow1++ )
! 1566: if ( irow1 > min2(irow2+smin,bot1) ) break; /* upper bound check */
! 1567: else
! 1568: if ( (margin1=firstcol1[irow1]) != blanksignal ) { /*have non-blank row*/
! 1569: int dx=(margin1+margin2), dy=absval(irow2-irow1), ds=dx+dy; /* deltas */
! 1570: if ( ds >= smin ) continue; /* min unchanged */
! 1571: if ( dy>squashmargin && dx<xmin && smin<9999 ) continue; /* dy alone */
! 1572: smin=ds; xmin=dx; ymin=dy; /* set new min */
! 1573: } /* --- end-of-if(margin1!=blanksignal) --- */
! 1574: if ( smin<2 ) goto end_of_job; /* can't squash */
! 1575: } /* --- end-of-for(irow2) --- */
! 1576: /*nsquash = min2(xmin,width2);*/ /* permissible squash */
! 1577: nsquash = xmin; /* permissible squash */
! 1578: /* -------------------------------------------------------------------------
! 1579: Back to caller with #pixels to squash sp1||sp2
! 1580: -------------------------------------------------------------------------- */
! 1581: end_of_job:
! 1582: /* --- debugging output --- */
! 1583: if ( msgfp!=NULL && msglevel >= 99 ) /* display for debugging */
! 1584: { fprintf(msgfp,"rastsquash> nsquash=%d, squashmargin=%d\n",
! 1585: nsquash,squashmargin);
! 1586: if ( msglevel >= 999 ) /* also display rasters */
! 1587: { fprintf(msgfp,"rastsquash>left-hand image...\n");
! 1588: if(sp1!=NULL) type_raster(sp1->image,msgfp); /* left image */
! 1589: fprintf(msgfp,"rastsquash>right-hand image...\n");
! 1590: if(sp2!=NULL) type_raster(sp2->image,msgfp); } /* right image */
! 1591: fflush(msgfp); }
! 1592: return ( nsquash ); /* back with #squash pixels */
! 1593: } /* --- end-of-function rastsquash() --- */
! 1594:
! 1595:
! 1596: /* ==========================================================================
! 1597: * Function: accent_subraster ( accent, width, height, pixsz )
! 1598: * Purpose: Allocate a new subraster of width x height
! 1599: * (or maybe different dimensions, depending on accent),
! 1600: * and draw an accent (\hat or \vec or \etc) that fills it
! 1601: * --------------------------------------------------------------------------
! 1602: * Arguments: accent (I) int containing either HATACCENT or VECACCENT,
! 1603: * etc, indicating the type of accent desired
! 1604: * width (I) int containing desired width of accent (#cols)
! 1605: * height (I) int containing desired height of accent(#rows)
! 1606: * pixsz (I) int containing 1 for bitmap, 8 for bytemap
! 1607: * --------------------------------------------------------------------------
! 1608: * Returns: ( subraster * ) ptr to newly-allocated subraster with accent,
! 1609: * or NULL for any error.
! 1610: * --------------------------------------------------------------------------
! 1611: * Notes: o Some accents have internally-determined dimensions,
! 1612: * and caller should check dimensions in returned subraster
! 1613: * ======================================================================= */
! 1614: /* --- entry point --- */
! 1615: subraster *accent_subraster ( int accent, int width, int height, int pixsz )
! 1616: {
! 1617: /* -------------------------------------------------------------------------
! 1618: Allocations and Declarations
! 1619: -------------------------------------------------------------------------- */
! 1620: /* --- general info --- */
! 1621: raster *new_raster(), *rp=NULL; /*raster containing desired accent*/
! 1622: subraster *new_subraster(), *sp=NULL; /* subraster returning accent */
! 1623: int delete_raster(), delete_subraster(); /*free allocated raster on err*/
! 1624: int line_raster(), /* draws lines */
! 1625: thickness = 1; /* line thickness */
! 1626: /*int pixval = (pixsz==1? 1 : (pixsz==8?255:(-1)));*/ /*black pixel value*/
! 1627: /* --- other working info --- */
! 1628: int col0, col1, /* cols for line */
! 1629: row0, row1; /* rows for line */
! 1630: subraster *get_delim(), *accsp=NULL; /*find suitable cmex10 symbol/accent*/
! 1631: /* --- info for under/overbraces, tildes, etc --- */
! 1632: char brace[16]; /*"{" for over, "}" for under, etc*/
! 1633: raster *rastrot(), /* rotate { for overbrace, etc */
! 1634: *rastcpy(); /* may need copy of original */
! 1635: subraster *arrow_subraster(); /* rightarrow for vec */
! 1636: subraster *rastack(); /* stack accent atop extra space */
! 1637: /* -------------------------------------------------------------------------
! 1638: outer switch() traps accents that may change caller's height,width
! 1639: -------------------------------------------------------------------------- */
! 1640: switch ( accent )
! 1641: {
! 1642: default:
! 1643: /* -----------------------------------------------------------------------
! 1644: inner switch() first allocates fixed-size raster for accents that don't
! 1645: ------------------------------------------------------------------------ */
! 1646: if ( (rp = new_raster(width,height,pixsz)) /* allocate fixed-size raster */
! 1647: != NULL ) /* and if we succeeded... */
! 1648: switch ( accent ) /* ...draw requested accent in it */
! 1649: {
! 1650: /* --- unrecognized request --- */
! 1651: default: delete_raster(rp); /* unrecognized accent requested */
! 1652: rp = NULL; break; /* so free raster and signal error */
! 1653: /* --- bar request --- */
! 1654: case UNDERBARACCENT:
! 1655: case BARACCENT:
! 1656: thickness = height-1; /* adjust thickness */
! 1657: if ( accent == BARACCENT ) /* bar is above expression */
! 1658: line_raster(rp,0,0,0,width-1,thickness); /*leave blank line at bot*/
! 1659: else /* underbar is below expression */
! 1660: line_raster(rp,1,0,1,width-1,thickness); /*leave blank line at top*/
! 1661: break;
! 1662: /* --- dot request --- */
! 1663: case DOTACCENT:
! 1664: thickness = height-1; /* adjust thickness */
! 1665: line_raster(rp,0,width/2,1,(width/2)+1,thickness); /* centered dot */
! 1666: break;
! 1667: /* --- ddot request --- */
! 1668: case DDOTACCENT:
! 1669: thickness = height-1; /* adjust thickness */
! 1670: col0 = max2(width/3-(thickness-1),0); /* one-third of width */
! 1671: col1 = min2((2*width)/3+(thickness-1),width-thickness); /*two thirds*/
! 1672: line_raster(rp,0,col0,1,col0+1,thickness); /* set a dot at 1st third*/
! 1673: line_raster(rp,0,col1,1,col1+1,thickness); /* and another at 2nd */
! 1674: break;
! 1675: /* --- hat request --- */
! 1676: case HATACCENT:
! 1677: thickness = (width<=12? 2 : 3); /* adjust thickness */
! 1678: line_raster(rp,height-1,0,0,width/2,thickness); /* / part of hat*/
! 1679: line_raster(rp,0,(width-1)/2,height-1,width-1,thickness); /* \ part*/
! 1680: break;
! 1681: /* --- sqrt request --- */
! 1682: case SQRTACCENT:
! 1683: col1 = SQRTWIDTH(height) - 1; /* right col of sqrt symbol */
! 1684: col0 = (col1+2)/3; /* midpoint col of sqrt */
! 1685: row0 = (height+1)/2; /* midpoint row of sqrt */
! 1686: row1 = height-1; /* bottom row of sqrt */
! 1687: line_raster(rp,row0,0,row1,col0,thickness); /* descending portion */
! 1688: line_raster(rp,row1,col0,0,col1,thickness); /* ascending portion */
! 1689: line_raster(rp,0,col1,0,width-1,thickness); /*overbar of thickness 1*/
! 1690: break;
! 1691: } /* --- end-of-inner-switch(accent) --- */
! 1692: break; /* break from outer accent switch */
! 1693: /* --- underbrace, overbrace request --- */
! 1694: case UNDERBRACE:
! 1695: case OVERBRACE:
! 1696: if ( accent == UNDERBRACE ) strcpy(brace,"}"); /* start with } brace */
! 1697: if ( accent == OVERBRACE ) strcpy(brace,"{"); /* start with { brace */
! 1698: if ( (accsp=get_delim(brace,width,CMEX10)) /* use width for height */
! 1699: != NULL ) /* found desired brace */
! 1700: { rp = rastrot(accsp->image); /* rotate 90 degrees clockwise */
! 1701: delete_subraster(accsp); } /* and free subraster "envelope" */
! 1702: break;
! 1703: /* --- hat request --- */
! 1704: case HATACCENT:
! 1705: if ( accent == HATACCENT ) strcpy(brace,"<"); /* start with < */
! 1706: if ( (accsp=get_delim(brace,width,CMEX10)) /* use width for height */
! 1707: != NULL ) /* found desired brace */
! 1708: { rp = rastrot(accsp->image); /* rotate 90 degrees clockwise */
! 1709: delete_subraster(accsp); } /* and free subraster "envelope" */
! 1710: break;
! 1711: /* --- vec request --- */
! 1712: case VECACCENT:
! 1713: height = 2*(height/2) + 1; /* force height odd */
! 1714: if ( (accsp=arrow_subraster(width,height,pixsz,1,0)) /*build rightarrow*/
! 1715: != NULL ) /* succeeded */
! 1716: { rp = accsp->image; /* "extract" raster with bitmap */
! 1717: free((void *)accsp); } /* and free subraster "envelope" */
! 1718: break;
! 1719: /* --- tilde request --- */
! 1720: case TILDEACCENT:
! 1721: accsp=(width<25? get_delim("\\sim",-width,CMSY10) :
! 1722: get_delim("~",-width,CMEX10)); /*width search for tilde*/
! 1723: if ( accsp != NULL ) /* found desired tilde */
! 1724: if ( (sp=rastack(new_subraster(1,1,pixsz),accsp,1,0,1,3))/*space below*/
! 1725: != NULL ) /* have tilde with space below it */
! 1726: { rp = sp->image; /* "extract" raster with bitmap */
! 1727: free((void *)sp); } /* and free subraster "envelope" */
! 1728: break;
! 1729: } /* --- end-of-outer-switch(accent) --- */
! 1730: /* -------------------------------------------------------------------------
! 1731: if we constructed accent raster okay, embed it in a subraster and return it
! 1732: -------------------------------------------------------------------------- */
! 1733: /* --- if all okay, allocate subraster to contain constructed raster --- */
! 1734: if ( rp != NULL ) /* accent raster constructed okay */
! 1735: if ( (sp=new_subraster(0,0,0)) /* allocate subraster "envelope" */
! 1736: == NULL ) /* and if we fail to allocate */
! 1737: delete_raster(rp); /* free now-unneeded raster */
! 1738: else /* subraster allocated okay */
! 1739: { /* --- init subraster parameters, embedding raster in it --- */
! 1740: sp->type = IMAGERASTER; /* constructed image */
! 1741: sp->image = rp; /* raster we just constructed */
! 1742: sp->size = (-1); /* can't set font size here */
! 1743: sp->baseline = 0; } /* can't set baseline here */
! 1744: /* --- return subraster containing desired accent to caller --- */
! 1745: return ( sp ); /* return accent or NULL to caller */
! 1746: } /* --- end-of-function accent_subraster() --- */
! 1747:
! 1748:
! 1749: /* ==========================================================================
! 1750: * Function: arrow_subraster ( width, height, pixsz, drctn, isBig )
! 1751: * Purpose: Allocate a raster/subraster and draw left/right arrow in it
! 1752: * --------------------------------------------------------------------------
! 1753: * Arguments: width (I) int containing number of cols for arrow
! 1754: * height (I) int containing number of rows for arrow
! 1755: * pixsz (I) int containing 1 for bitmap, 8 for bytemap
! 1756: * drctn (I) int containing +1 for right arrow,
! 1757: * or -1 for left, 0 for leftright
! 1758: * isBig (I) int containing 1/true for \Long arrows,
! 1759: * or false for \long arrows, i.e.,
! 1760: * true for ===> or false for --->.
! 1761: * --------------------------------------------------------------------------
! 1762: * Returns: ( subraster * ) ptr to constructed left/right arrow
! 1763: * or NULL for any error.
! 1764: * --------------------------------------------------------------------------
! 1765: * Notes: o
! 1766: * ======================================================================= */
! 1767: /* --- entry point --- */
! 1768: subraster *arrow_subraster ( int width, int height, int pixsz,
! 1769: int drctn, int isBig )
! 1770: {
! 1771: /* -------------------------------------------------------------------------
! 1772: Allocations and Declarations
! 1773: -------------------------------------------------------------------------- */
! 1774: subraster *new_subraster(), *arrowsp=NULL; /* allocate arrow subraster */
! 1775: int rule_raster(); /* draw arrow line */
! 1776: int irow, midrow=height/2; /* index, midrow is arrowhead apex */
! 1777: int icol, thickness=(height>15?2:1); /* arrowhead thickness and index */
! 1778: int pixval = (pixsz==1? 1 : (pixsz==8?255:(-1))); /* black pixel value */
! 1779: int ipix, /* raster pixmap[] index */
! 1780: npix = width*height; /* #pixels malloced in pixmap[] */
! 1781: /* -------------------------------------------------------------------------
! 1782: allocate raster/subraster and draw arrow line
! 1783: -------------------------------------------------------------------------- */
! 1784: if ( height < 3 ) { height=3; midrow=1; } /* set minimum height */
! 1785: if ( (arrowsp=new_subraster(width,height,pixsz)) /* allocate empty raster */
! 1786: == NULL ) goto end_of_job; /* and quit if failed */
! 1787: if ( !isBig ) /* single line */
! 1788: rule_raster(arrowsp->image,midrow,0,width,1,0); /*draw line across midrow*/
! 1789: else
! 1790: { int delta = (width>6? (height>15? 3: (height>7? 2 : 1)) : 1);
! 1791: rule_raster(arrowsp->image,midrow-delta,delta,width-2*delta,1,0);
! 1792: rule_raster(arrowsp->image,midrow+delta,delta,width-2*delta,1,0); }
! 1793: /* -------------------------------------------------------------------------
! 1794: construct arrowhead(s)
! 1795: -------------------------------------------------------------------------- */
! 1796: for ( irow=0; irow<height; irow++ ) /* for each row of arrow */
! 1797: {
! 1798: int delta = abs(irow-midrow); /*arrowhead offset for irow*/
! 1799: /* --- right arrowhead --- */
! 1800: if ( drctn >= 0 ) /* right arrowhead wanted */
! 1801: for ( icol=0; icol<thickness; icol++ ) /* for arrowhead thickness */
! 1802: { ipix = ((irow+1)*width - 1) - delta - icol; /* rightmost-delta-icol */
! 1803: if ( ipix >= 0 ) /* bounds check */
! 1804: if ( pixsz == 1 ) /* have a bitmap */
! 1805: setlongbit((arrowsp->image)->pixmap,ipix);/*turn on arrowhead bit*/
! 1806: else /* should have a bytemap */
! 1807: if ( pixsz == 8 ) /* check pixsz for bytemap */
! 1808: ((arrowsp->image)->pixmap)[ipix] = pixval; } /*set arrowhead byte*/
! 1809: /* --- left arrowhead (same as right except for ipix calculation) --- */
! 1810: if ( drctn <= 0 ) /* left arrowhead wanted */
! 1811: for ( icol=0; icol<thickness; icol++ ) /* for arrowhead thickness */
! 1812: { ipix = irow*width + delta + icol; /* leftmost bit+delta+icol */
! 1813: if ( ipix < npix ) /* bounds check */
! 1814: if ( pixsz == 1 ) /* have a bitmap */
! 1815: setlongbit((arrowsp->image)->pixmap,ipix);/*turn on arrowhead bit*/
! 1816: else /* should have a bytemap */
! 1817: if ( pixsz == 8 ) /* check pixsz for bytemap */
! 1818: ((arrowsp->image)->pixmap)[ipix] = pixval; } /*set arrowhead byte*/
! 1819: } /* --- end-of-for(irow) --- */
! 1820: end_of_job:
! 1821: return ( arrowsp ); /*back to caller with arrow or NULL*/
! 1822: } /* --- end-of-function arrow_subraster() --- */
! 1823:
! 1824:
! 1825: /* ==========================================================================
! 1826: * Function: uparrow_subraster ( width, height, pixsz, drctn, isBig )
! 1827: * Purpose: Allocate a raster/subraster and draw up/down arrow in it
! 1828: * --------------------------------------------------------------------------
! 1829: * Arguments: width (I) int containing number of cols for arrow
! 1830: * height (I) int containing number of rows for arrow
! 1831: * pixsz (I) int containing 1 for bitmap, 8 for bytemap
! 1832: * drctn (I) int containing +1 for up arrow,
! 1833: * or -1 for down, or 0 for updown
! 1834: * isBig (I) int containing 1/true for \Long arrows,
! 1835: * or false for \long arrows, i.e.,
! 1836: * true for ===> or false for --->.
! 1837: * --------------------------------------------------------------------------
! 1838: * Returns: ( subraster * ) ptr to constructed up/down arrow
! 1839: * or NULL for any error.
! 1840: * --------------------------------------------------------------------------
! 1841: * Notes: o
! 1842: * ======================================================================= */
! 1843: /* --- entry point --- */
! 1844: subraster *uparrow_subraster ( int width, int height, int pixsz,
! 1845: int drctn, int isBig )
! 1846: {
! 1847: /* -------------------------------------------------------------------------
! 1848: Allocations and Declarations
! 1849: -------------------------------------------------------------------------- */
! 1850: subraster *new_subraster(), *arrowsp=NULL; /* allocate arrow subraster */
! 1851: int rule_raster(); /* draw arrow line */
! 1852: int icol, midcol=width/2; /* index, midcol is arrowhead apex */
! 1853: int irow, thickness=(width>15?2:1); /* arrowhead thickness and index */
! 1854: int pixval = (pixsz==1? 1 : (pixsz==8?255:(-1))); /* black pixel value */
! 1855: int ipix, /* raster pixmap[] index */
! 1856: npix = width*height; /* #pixels malloced in pixmap[] */
! 1857: /* -------------------------------------------------------------------------
! 1858: allocate raster/subraster and draw arrow line
! 1859: -------------------------------------------------------------------------- */
! 1860: if ( width < 3 ) { width=3; midcol=1; } /* set minimum width */
! 1861: if ( (arrowsp=new_subraster(width,height,pixsz)) /* allocate empty raster */
! 1862: == NULL ) goto end_of_job; /* and quit if failed */
! 1863: if ( !isBig ) /* single line */
! 1864: rule_raster(arrowsp->image,0,midcol,1,height,0); /*draw line down midcol*/
! 1865: else
! 1866: { int delta = (height>6? (width>15? 3: (width>7? 2 : 1)) : 1);
! 1867: rule_raster(arrowsp->image,delta,midcol-delta,1,height-2*delta,0);
! 1868: rule_raster(arrowsp->image,delta,midcol+delta,1,height-2*delta,0); }
! 1869: /* -------------------------------------------------------------------------
! 1870: construct arrowhead(s)
! 1871: -------------------------------------------------------------------------- */
! 1872: for ( icol=0; icol<width; icol++ ) /* for each col of arrow */
! 1873: {
! 1874: int delta = abs(icol-midcol); /*arrowhead offset for icol*/
! 1875: /* --- up arrowhead --- */
! 1876: if ( drctn >= 0 ) /* up arrowhead wanted */
! 1877: for ( irow=0; irow<thickness; irow++ ) /* for arrowhead thickness */
! 1878: { ipix = (irow+delta)*width + icol; /* leftmost+icol */
! 1879: if ( ipix < npix ) /* bounds check */
! 1880: if ( pixsz == 1 ) /* have a bitmap */
! 1881: setlongbit((arrowsp->image)->pixmap,ipix);/*turn on arrowhead bit*/
! 1882: else /* should have a bytemap */
! 1883: if ( pixsz == 8 ) /* check pixsz for bytemap */
! 1884: ((arrowsp->image)->pixmap)[ipix] = pixval; } /*set arrowhead byte*/
! 1885: /* --- down arrowhead (same as up except for ipix calculation) --- */
! 1886: if ( drctn <= 0 ) /* down arrowhead wanted */
! 1887: for ( irow=0; irow<thickness; irow++ ) /* for arrowhead thickness */
! 1888: { ipix = (height-1-delta-irow)*width + icol; /* leftmost + icol */
! 1889: if ( ipix > 0 ) /* bounds check */
! 1890: if ( pixsz == 1 ) /* have a bitmap */
! 1891: setlongbit((arrowsp->image)->pixmap,ipix);/*turn on arrowhead bit*/
! 1892: else /* should have a bytemap */
! 1893: if ( pixsz == 8 ) /* check pixsz for bytemap */
! 1894: ((arrowsp->image)->pixmap)[ipix] = pixval; } /*set arrowhead byte*/
! 1895: } /* --- end-of-for(irow) --- */
! 1896: end_of_job:
! 1897: return ( arrowsp ); /*back to caller with arrow or NULL*/
! 1898: } /* --- end-of-function uparrow_subraster() --- */
! 1899:
! 1900:
! 1901: /* ==========================================================================
! 1902: * Function: rule_raster ( rp, top, left, width, height, type )
! 1903: * Purpose: Draw a solid or dashed line (or box) in existing raster rp,
! 1904: * starting at top,left with dimensions width,height.
! 1905: * --------------------------------------------------------------------------
! 1906: * Arguments: rp (I) raster * to raster in which rule
! 1907: * will be drawn
! 1908: * top (I) int containing row at which top-left corner
! 1909: * of rule starts (0 is topmost)
! 1910: * left (I) int containing col at which top-left corner
! 1911: * of rule starts (0 is leftmost)
! 1912: * width (I) int containing number of cols for rule
! 1913: * height (I) int containing number of rows for rule
! 1914: * type (I) int containing 0 for solid rule,
! 1915: * 1 for horizontal dashes, 2 for vertical
! 1916: * --------------------------------------------------------------------------
! 1917: * Returns: ( int ) 1 if rule drawn okay,
! 1918: * or 0 for any error.
! 1919: * --------------------------------------------------------------------------
! 1920: * Notes: o Rule line is implicitly "horizontal" or "vertical" depending
! 1921: * on relative width,height dimensions. It's a box if they're
! 1922: * more or less comparable.
! 1923: * ======================================================================= */
! 1924: /* --- entry point --- */
! 1925: int rule_raster ( raster *rp, int top, int left,
! 1926: int width, int height, int type )
! 1927: {
! 1928: /* -------------------------------------------------------------------------
! 1929: Allocations and Declarations
! 1930: -------------------------------------------------------------------------- */
! 1931: int irow, icol; /* indexes over rp raster */
! 1932: int ipix, /* raster pixmap[] index */
! 1933: npix = rp->width * rp->height; /* #pixels malloced in rp->pixmap[] */
! 1934: int isfatal = 0; /* true to abend on out-of-bounds error */
! 1935: int hdash=1, vdash=2; /* type for horizontal, vertical dashes */
! 1936: int dashlen=3, spacelen=2, /* #pixels for dash followed by space */
! 1937: isdraw=1; /* true when drawing dash (init for solid) */
! 1938: /* -------------------------------------------------------------------------
! 1939: Check args
! 1940: -------------------------------------------------------------------------- */
! 1941: if ( rp == (raster *)NULL ) /* no raster arg supplied */
! 1942: if ( workingbox != (subraster *)NULL ) /* see if we have a workingbox */
! 1943: rp = workingbox->image; /* use workingbox if possible */
! 1944: else return ( 0 ); /* otherwise signal error to caller */
! 1945: /* -------------------------------------------------------------------------
! 1946: Fill line/box
! 1947: -------------------------------------------------------------------------- */
! 1948: for ( irow=top; irow<top+height; irow++ ) /*each scan line*/
! 1949: {
! 1950: if ( type == vdash ) /*set isdraw for vert dash*/
! 1951: isdraw = (((irow-top)%(dashlen+spacelen)) < dashlen);
! 1952: ipix = irow*rp->width + left - 1; /*first pixel preceding icol*/
! 1953: for ( icol=left; icol<left+width; icol++ ) /* each pixel in scan line */
! 1954: {
! 1955: if ( type == hdash ) /*set isdraw for horiz dash*/
! 1956: isdraw = (((icol-left)%(dashlen+spacelen)) < dashlen);
! 1957: if ( ++ipix >= npix ) /* bounds check failed */
! 1958: if ( isfatal ) goto end_of_job; /* abort if error is fatal */
! 1959: else break; /*or just go on to next row*/
! 1960: else /*ibit is within rp bounds*/
! 1961: if ( isdraw ) /*and we're drawing this bit*/
! 1962: if ( rp->pixsz == 1 ) /* have a bitmap */
! 1963: setlongbit(rp->pixmap,ipix); /* so turn on bit in line */
! 1964: else /* should have a bytemap */
! 1965: if ( rp->pixsz == 8 ) /* check pixsz for bytemap */
! 1966: ((unsigned char *)(rp->pixmap))[ipix] = 255; /* set black byte */
! 1967: } /* --- end-of-for(icol) --- */
! 1968: } /* --- end-of-for(irow) --- */
! 1969: end_of_job:
! 1970: return ( isfatal? (ipix<npix? 1:0) : 1 );
! 1971: } /* --- end-of-function rule_raster() --- */
! 1972:
! 1973:
! 1974: /* ==========================================================================
! 1975: * Function: line_raster ( rp, row0, col0, row1, col1, thickness )
! 1976: * Purpose: Draw a line from row0,col0 to row1,col1 of thickness
! 1977: * in existing raster rp.
! 1978: * --------------------------------------------------------------------------
! 1979: * Arguments: rp (I) raster * to raster in which a line
! 1980: * will be drawn
! 1981: * row0 (I) int containing row at which
! 1982: * line will start (0 is topmost)
! 1983: * col0 (I) int containing col at which
! 1984: * line will start (0 is leftmost)
! 1985: * row1 (I) int containing row at which
! 1986: * line will end (rp->height-1 is bottom-most)
! 1987: * col1 (I) int containing col at which
! 1988: * line will end (rp->width-1 is rightmost)
! 1989: * thickness (I) int containing number of pixels/bits
! 1990: * thick the line will be
! 1991: * --------------------------------------------------------------------------
! 1992: * Returns: ( int ) 1 if line drawn okay,
! 1993: * or 0 for any error.
! 1994: * --------------------------------------------------------------------------
! 1995: * Notes: o if row0==row1, a horizontal line is drawn
! 1996: * between col0 and col1, with row0(==row1) the top row
! 1997: * and row0+(thickness-1) the bottom row
! 1998: * o if col0==col1, a vertical bar is drawn
! 1999: * between row0 and row1, with col0(==col1) the left col
! 2000: * and col0+(thickness-1) the right col
! 2001: * o if both the above, you get a square thickness x thickness
! 2002: * whose top-left corner is row0,col0.
! 2003: * ======================================================================= */
! 2004: /* --- entry point --- */
! 2005: int line_raster ( raster *rp, int row0, int col0,
! 2006: int row1, int col1, int thickness )
! 2007: {
! 2008: /* -------------------------------------------------------------------------
! 2009: Allocations and Declarations
! 2010: -------------------------------------------------------------------------- */
! 2011: int irow, icol, /* indexes over rp raster */
! 2012: locol=col0, hicol=col1, /* col limits at irow */
! 2013: lorow=row0, hirow=row1; /* row limits at icol */
! 2014: int ipix, /* raster pixmap[] index */
! 2015: npix = rp->width * rp->height; /* #pixels malloced in rp->pixmap[] */
! 2016: int isfatal = 0; /* true to abend on out-of-bounds error */
! 2017: int isline=(row1==row0), isbar=(col1==col0); /*true if slope a=0,\infty*/
! 2018: double dy = row1-row0 /* + (row1>=row0? +1.0 : -1.0) */, /* delta-x */
! 2019: dx = col1-col0 /* + (col1>=col0? +1.0 : -1.0) */, /* delta-y */
! 2020: a= (isbar||isline? 0.0 : dy/dx), /* slope = tan(theta) = dy/dx */
! 2021: xcol, xrow; /* calculated col at irow, or row at icol */
! 2022: double ar = ASPECTRATIO, /* aspect ratio width/height of one pixel */
! 2023: xwidth= (isline? 0.0 : /*#pixels per row to get sloped line thcknss*/
! 2024: ((double)thickness)*sqrt((dx*dx)+(dy*dy*ar*ar))/fabs(dy*ar)),
! 2025: xheight = 1.0;
! 2026: int line_recurse(), isrecurse=1; /* true to draw line recursively */
! 2027: /* -------------------------------------------------------------------------
! 2028: Check args
! 2029: -------------------------------------------------------------------------- */
! 2030: if ( rp == (raster *)NULL ) /* no raster arg supplied */
! 2031: if ( workingbox != (subraster *)NULL ) /* see if we have a workingbox */
! 2032: rp = workingbox->image; /* use workingbox if possible */
! 2033: else return ( 0 ); /* otherwise signal error to caller */
! 2034: /* -------------------------------------------------------------------------
! 2035: Initialization
! 2036: -------------------------------------------------------------------------- */
! 2037: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 2038: fprintf(msgfp,"line_raster> row,col0=%d,%d row,col1=%d,%d, thickness=%d\n"
! 2039: "\t dy,dx=%3.1f,%3.1f, a=%4.3f, xwidth=%4.3f\n",
! 2040: row0,col0, row1,col1, thickness, dy,dx, a, xwidth);
! 2041: /* --- check for recursive line drawing --- */
! 2042: if ( isrecurse ) /* drawing lines recursively */
! 2043: { line_recurse(rp,(double)row0,(double)col0,
! 2044: (double)row1,(double)col1,thickness);
! 2045: return ( 1 ); }
! 2046: /* --- set params for horizontal line or vertical bar --- */
! 2047: if ( isline ) /*interpret row as top row*/
! 2048: row1 = row0 + (thickness-1); /* set bottom row for line */
! 2049: if ( 0&&isbar ) /*interpret col as left col*/
! 2050: hicol = col0 + (thickness-1); /* set right col for bar */
! 2051: /* -------------------------------------------------------------------------
! 2052: draw line one row at a time
! 2053: -------------------------------------------------------------------------- */
! 2054: for ( irow=min2(row0,row1); irow<=max2(row0,row1); irow++ ) /*each scan line*/
! 2055: {
! 2056: if ( !isbar && !isline ) /* neither vert nor horiz */
! 2057: { xcol = col0 + ((double)(irow-row0))/a; /* "middle" col in irow */
! 2058: locol = max2((int)(xcol-0.5*(xwidth-1.0)),0); /* leftmost col */
! 2059: hicol = min2((int)(xcol+0.5*(xwidth-0.0)),max2(col0,col1)); } /*right*/
! 2060: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 2061: fprintf(msgfp,"\t irow=%d, xcol=%4.2f, lo,hicol=%d,%d\n",
! 2062: irow,xcol,locol,hicol);
! 2063: ipix = irow*rp->width + min2(locol,hicol) - 1; /*first pix preceding icol*/
! 2064: for ( icol=min2(locol,hicol); icol<=max2(locol,hicol); icol++ ) /*each pix*/
! 2065: if ( ++ipix >= npix ) /* bounds check failed */
! 2066: if ( isfatal ) goto end_of_job; /* abort if error is fatal */
! 2067: else break; /*or just go on to next row*/
! 2068: else /* turn on pixel in line */
! 2069: if ( rp->pixsz == 1 ) /* have a pixel bitmap */
! 2070: setlongbit(rp->pixmap,ipix); /* so turn on bit in line */
! 2071: else /* should have a bytemap */
! 2072: if ( rp->pixsz == 8 ) /* check pixsz for bytemap */
! 2073: ((unsigned char *)(rp->pixmap))[ipix] = 255; /* set black byte */
! 2074: } /* --- end-of-for(irow) --- */
! 2075: /* -------------------------------------------------------------------------
! 2076: now _redraw_ line one col at a time to avoid "gaps"
! 2077: -------------------------------------------------------------------------- */
! 2078: if ( 1 )
! 2079: for ( icol=min2(col0,col1); icol<=max2(col0,col1); icol++ )/*each scan line*/
! 2080: {
! 2081: if ( !isbar && !isline ) /* neither vert nor horiz */
! 2082: { xrow = row0 + ((double)(icol-col0))*a; /* "middle" row in icol */
! 2083: lorow = max2((int)(xrow-0.5*(xheight-1.0)),0); /* topmost row */
! 2084: hirow = min2((int)(xrow+0.5*(xheight-0.0)),max2(row0,row1)); } /*bot*/
! 2085: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 2086: fprintf(msgfp,"\t icol=%d, xrow=%4.2f, lo,hirow=%d,%d\n",
! 2087: icol,xrow,lorow,hirow);
! 2088: ipix = irow*rp->width + min2(locol,hicol) - 1; /*first pix preceding icol*/
! 2089: for ( irow=min2(lorow,hirow); irow<=max2(lorow,hirow); irow++ ) /*each pix*/
! 2090: if ( irow<0 || irow>=rp->height
! 2091: || icol<0 || icol>=rp->width ) /* bounds check */
! 2092: if ( isfatal ) goto end_of_job; /* abort if error is fatal */
! 2093: else continue; /*or just go on to next row*/
! 2094: else
! 2095: setpixel(rp,irow,icol,255); /* set pixel at irow,icol */
! 2096: } /* --- end-of-for(irow) --- */
! 2097: /* -------------------------------------------------------------------------
! 2098: Back to caller with 1=okay, 0=failed.
! 2099: -------------------------------------------------------------------------- */
! 2100: end_of_job:
! 2101: return ( isfatal? (ipix<npix? 1:0) : 1 );
! 2102: } /* --- end-of-function line_raster() --- */
! 2103:
! 2104:
! 2105: /* ==========================================================================
! 2106: * Function: line_recurse ( rp, row0, col0, row1, col1, thickness )
! 2107: * Purpose: Draw a line from row0,col0 to row1,col1 of thickness
! 2108: * in existing raster rp.
! 2109: * --------------------------------------------------------------------------
! 2110: * Arguments: rp (I) raster * to raster in which a line
! 2111: * will be drawn
! 2112: * row0 (I) double containing row at which
! 2113: * line will start (0 is topmost)
! 2114: * col0 (I) double containing col at which
! 2115: * line will start (0 is leftmost)
! 2116: * row1 (I) double containing row at which
! 2117: * line will end (rp->height-1 is bottom-most)
! 2118: * col1 (I) double containing col at which
! 2119: * line will end (rp->width-1 is rightmost)
! 2120: * thickness (I) int containing number of pixels/bits
! 2121: * thick the line will be
! 2122: * --------------------------------------------------------------------------
! 2123: * Returns: ( int ) 1 if line drawn okay,
! 2124: * or 0 for any error.
! 2125: * --------------------------------------------------------------------------
! 2126: * Notes: o Recurses, drawing left- and right-halves of line
! 2127: * until a horizontal or vertical segment is found
! 2128: * ======================================================================= */
! 2129: /* --- entry point --- */
! 2130: int line_recurse ( raster *rp, double row0, double col0,
! 2131: double row1, double col1, int thickness )
! 2132: {
! 2133: /* -------------------------------------------------------------------------
! 2134: Allocations and Declarations
! 2135: -------------------------------------------------------------------------- */
! 2136: double delrow = fabs(row1-row0), /* 0 if line horizontal */
! 2137: delcol = fabs(col1-col0), /* 0 if line vertical */
! 2138: tolerance = 0.5; /* draw line when it goes to point */
! 2139: double midrow = 0.5*(row0+row1), /* midpoint row */
! 2140: midcol = 0.5*(col0+col1); /* midpoint col */
! 2141: /* -------------------------------------------------------------------------
! 2142: recurse if either delta > tolerance
! 2143: -------------------------------------------------------------------------- */
! 2144: if ( delrow > tolerance /* row hasn't converged */
! 2145: || delcol > tolerance ) /* col hasn't converged */
! 2146: { line_recurse(rp,row0,col0,midrow,midcol,thickness); /* left half */
! 2147: line_recurse(rp,midrow,midcol,row1,col1,thickness); /* right half */
! 2148: return ( 1 ); }
! 2149: /* -------------------------------------------------------------------------
! 2150: draw converged point
! 2151: -------------------------------------------------------------------------- */
! 2152: setpixel(rp,iround(midrow),iround(midcol),255); /*set pixel at midrow,midcol*/
! 2153: return ( 1 );
! 2154: } /* --- end-of-function line_recurse() --- */
! 2155:
! 2156:
! 2157: /* ==========================================================================
! 2158: * Function: circle_raster ( rp, row0, col0, row1, col1,
! 2159: * thickness, quads )
! 2160: * Purpose: Draw quad(rant)s of an ellipse in box determined by
! 2161: * diagonally opposite corner points (row0,col0) and
! 2162: * (row1,col1), of thickness pixels in existing raster rp.
! 2163: * --------------------------------------------------------------------------
! 2164: * Arguments: rp (I) raster * to raster in which an ellipse
! 2165: * will be drawn
! 2166: * row0 (I) int containing 1st corner row bounding ellipse
! 2167: * (0 is topmost)
! 2168: * col0 (I) int containing 1st corner col bounding ellipse
! 2169: * (0 is leftmost)
! 2170: * row1 (I) int containing 2nd corner row bounding ellipse
! 2171: * (rp->height-1 is bottom-most)
! 2172: * col1 (I) int containing 2nd corner col bounding ellipse
! 2173: * (rp->width-1 is rightmost)
! 2174: * thickness (I) int containing number of pixels/bits
! 2175: * thick the ellipse arc line will be
! 2176: * quads (I) char * to null-terminated string containing
! 2177: * any subset/combination of "1234" specifying
! 2178: * which quadrant(s) of ellipse to draw.
! 2179: * NULL ptr draws all four quadrants;
! 2180: * otherwise 1=upper-right quadrant,
! 2181: * 2=uper-left, 3=lower-left, 4=lower-right,
! 2182: * i.e., counterclockwise from 1=positive quad.
! 2183: * --------------------------------------------------------------------------
! 2184: * Returns: ( int ) 1 if ellipse drawn okay,
! 2185: * or 0 for any error.
! 2186: * --------------------------------------------------------------------------
! 2187: * Notes: o row0==row1 or col0==col1 are errors
! 2188: * o using ellipse equation x^2/a^2 + y^2/b^2 = 1
! 2189: * ======================================================================= */
! 2190: /* --- entry point --- */
! 2191: int circle_raster ( raster *rp, int row0, int col0,
! 2192: int row1, int col1, int thickness, char *quads )
! 2193: {
! 2194: /* -------------------------------------------------------------------------
! 2195: Allocations and Declarations
! 2196: -------------------------------------------------------------------------- */
! 2197: /* --- lower-left and upper-right bounding points (in our coords) --- */
! 2198: int lorow = min2(row0,row1), /* lower bounding row (top of box) */
! 2199: locol = min2(col0,col1), /* lower bounding col (left of box)*/
! 2200: hirow = max2(row0,row1), /* upper bounding row (bot of box) */
! 2201: hicol = max2(col0,col1); /* upper bounding col (right of box)*/
! 2202: /* --- a and b ellipse params --- */
! 2203: int width = hicol-locol+1, /* width of bounding box */
! 2204: height= hirow-lorow+1, /* height of bounding box */
! 2205: islandscape = (width>=height? 1:0); /*true if ellipse lying on side*/
! 2206: double a = ((double)width)/2.0, /* x=a when y=0 */
! 2207: b = ((double)height)/2.0, /* y=b when x=0 */
! 2208: abmajor = (islandscape? a : b), /* max2(a,b) */
! 2209: abminor = (islandscape? b : a), /* min2(a,b) */
! 2210: abmajor2 = abmajor*abmajor, /* abmajor^2 */
! 2211: abminor2 = abminor*abminor; /* abminor^2 */
! 2212: /* --- other stuff --- */
! 2213: int imajor=0, nmajor=max2(width,height), /*index, #pixels on major axis*/
! 2214: iminor=0, nminor=min2(width,height); /* solved index on minor axis */
! 2215: int irow, icol, /* raster indexes at circumference */
! 2216: rsign=1, csign=1; /* row,col signs, both +1 in quad 1*/
! 2217: double midrow= ((double)(row0+row1))/2.0, /* center row */
! 2218: midcol= ((double)(col0+col1))/2.0; /* center col */
! 2219: double xy, xy2, /* major axis ellipse coord */
! 2220: yx2, yx; /* solved minor ellipse coord */
! 2221: int isokay = 1; /* true if no pixels out-of-bounds */
! 2222: char *qptr=NULL, *allquads="1234"; /* quadrants if input quads==NULL */
! 2223: int circle_recurse(), isrecurse=1; /* true to draw ellipse recursively*/
! 2224: /* -------------------------------------------------------------------------
! 2225: pixel-by-pixel along positive major axis, quit when it goes negative
! 2226: -------------------------------------------------------------------------- */
! 2227: if ( quads == NULL ) quads = allquads; /* draw all quads, or only user's */
! 2228: if ( msgfp!=NULL && msglevel>=39 ) /* debugging */
! 2229: fprintf(msgfp,"circle_raster> width,height;quads=%d,%d,%s\n",
! 2230: width,height,quads);
! 2231: if ( nmajor < 1 ) isokay = 0; /* problem with input args */
! 2232: else
! 2233: {
! 2234: if ( isrecurse ) /* use recursive algorithm */
! 2235: {
! 2236: for ( qptr=quads; *qptr!='\000'; qptr++ ) /* for each character in quads */
! 2237: {
! 2238: double theta0=0.0, theta1=0.0; /* set thetas based on quadrant */
! 2239: switch ( *qptr ) /* check for quadrant 1,2,3,4 */
! 2240: { default: /* unrecognized, assume quadrant 1 */
! 2241: case '1': theta0= 0.0; theta1= 90.0; break; /* first quadrant */
! 2242: case '2': theta0= 90.0; theta1=180.0; break; /* second quadrant */
! 2243: case '3': theta0=180.0; theta1=270.0; break; /* third quadrant */
! 2244: case '4': theta0=270.0; theta1=360.0; break; } /* fourth quadrant */
! 2245: circle_recurse(rp,row0,col0,row1,col1,thickness,theta0,theta1);
! 2246: } /* --- end-of-for(qptr) --- */
! 2247: return ( 1 );
! 2248: } /* --- end-of-if(isrecurse) --- */
! 2249: for ( imajor=(nmajor+1)/2; ; imajor-- )
! 2250: {
! 2251: /* --- xy is coord along major axis, yx is "solved" along minor axis --- */
! 2252: xy = ((double)imajor); /* xy = abmajor ... 0 */
! 2253: if ( xy < 0.0 ) break; /* negative side symmetrical */
! 2254: yx2 = abminor2*(1.0 - xy*xy/abmajor2); /* "solve" ellipse equation */
! 2255: yx = (yx2>0.0? sqrt(yx2) : 0.0); /* take sqrt if possible */
! 2256: iminor = iround(yx); /* nearest integer */
! 2257: /* --- set pixels for each requested quadrant --- */
! 2258: for ( qptr=quads; *qptr!='\000'; qptr++ ) /* for each character in quads */
! 2259: {
! 2260: rsign = (-1); csign = 1; /* init row,col in user quadrant 1 */
! 2261: switch ( *qptr ) /* check for quadrant 1,2,3,4 */
! 2262: { default: break; /* unrecognized, assume quadrant 1 */
! 2263: case '4': rsign = 1; break; /* row,col both pos in quadrant 4 */
! 2264: case '3': rsign = 1; /* row pos, col neg in quadrant 3 */
! 2265: case '2': csign = (-1); break; } /* row,col both neg in quadrant 2 */
! 2266: irow = iround(midrow + (double)rsign*(islandscape?yx:xy));
! 2267: irow = min2(hirow,max2(lorow,irow)); /* keep irow in bounds */
! 2268: icol = iround(midcol + (double)csign*(islandscape?xy:yx));
! 2269: icol = min2(hicol,max2(locol,icol)); /* keep icol in bounds */
! 2270: if ( msgfp!=NULL && msglevel>=49 ) /* debugging */
! 2271: fprintf(msgfp,"\t...imajor=%d; iminor,quad,irow,icol=%d,%c,%d,%d\n",
! 2272: imajor,iminor,*qptr,irow,icol);
! 2273: if ( irow<0 || irow>=rp->height /* row outside raster */
! 2274: || icol<0 || icol>=rp->width ) /* col outside raster */
! 2275: { isokay = 0; /* signal out-of-bounds pixel */
! 2276: continue; } /* but still try remaining points */
! 2277: setpixel(rp,irow,icol,255); /* set pixel at irow,icol */
! 2278: } /* --- end-of-for(qptr) --- */
! 2279: } /* --- end-of-for(imajor) --- */
! 2280: /* ------------------------------------------------------------------------
! 2281: now do it _again_ along minor axis to avoid "gaps"
! 2282: ------------------------------------------------------------------------- */
! 2283: if ( 1 && iminor>0 )
! 2284: for ( iminor=(nminor+1)/2; ; iminor-- )
! 2285: {
! 2286: /* --- yx is coord along minor axis, xy is "solved" along major axis --- */
! 2287: yx = ((double)iminor); /* yx = abminor ... 0 */
! 2288: if ( yx < 0.0 ) break; /* negative side symmetrical */
! 2289: xy2 = abmajor2*(1.0 - yx*yx/abminor2); /* "solve" ellipse equation */
! 2290: xy = (xy2>0.0? sqrt(xy2) : 0.0); /* take sqrt if possible */
! 2291: imajor = iround(xy); /* nearest integer */
! 2292: /* --- set pixels for each requested quadrant --- */
! 2293: for ( qptr=quads; *qptr!='\000'; qptr++ ) /* for each character in quads */
! 2294: {
! 2295: rsign = (-1); csign = 1; /* init row,col in user quadrant 1 */
! 2296: switch ( *qptr ) /* check for quadrant 1,2,3,4 */
! 2297: { default: break; /* unrecognized, assume quadrant 1 */
! 2298: case '4': rsign = 1; break; /* row,col both pos in quadrant 4 */
! 2299: case '3': rsign = 1; /* row pos, col neg in quadrant 3 */
! 2300: case '2': csign = (-1); break; } /* row,col both neg in quadrant 2 */
! 2301: irow = iround(midrow + (double)rsign*(islandscape?yx:xy));
! 2302: irow = min2(hirow,max2(lorow,irow)); /* keep irow in bounds */
! 2303: icol = iround(midcol + (double)csign*(islandscape?xy:yx));
! 2304: icol = min2(hicol,max2(locol,icol)); /* keep icol in bounds */
! 2305: if ( msgfp!=NULL && msglevel>=49 ) /* debugging */
! 2306: fprintf(msgfp,"\t...iminor=%d; imajor,quad,irow,icol=%d,%c,%d,%d\n",
! 2307: iminor,imajor,*qptr,irow,icol);
! 2308: if ( irow<0 || irow>=rp->height /* row outside raster */
! 2309: || icol<0 || icol>=rp->width ) /* col outside raster */
! 2310: { isokay = 0; /* signal out-of-bounds pixel */
! 2311: continue; } /* but still try remaining points */
! 2312: setpixel(rp,irow,icol,255); /* set pixel at irow,icol */
! 2313: } /* --- end-of-for(qptr) --- */
! 2314: } /* --- end-of-for(iminor) --- */
! 2315: } /* --- end-of-if/else(nmajor<1) --- */
! 2316: return ( isokay );
! 2317: } /* --- end-of-function circle_raster() --- */
! 2318:
! 2319:
! 2320: /* ==========================================================================
! 2321: * Function: circle_recurse ( rp, row0, col0, row1, col1,
! 2322: * thickness, theta0, theta1 )
! 2323: * Purpose: Recursively draws arc theta0<=theta<=theta1 of the ellipse
! 2324: * in box determined by diagonally opposite corner points
! 2325: * (row0,col0) and (row1,col1), of thickness pixels in raster rp.
! 2326: * --------------------------------------------------------------------------
! 2327: * Arguments: rp (I) raster * to raster in which an ellipse
! 2328: * will be drawn
! 2329: * row0 (I) int containing 1st corner row bounding ellipse
! 2330: * (0 is topmost)
! 2331: * col0 (I) int containing 1st corner col bounding ellipse
! 2332: * (0 is leftmost)
! 2333: * row1 (I) int containing 2nd corner row bounding ellipse
! 2334: * (rp->height-1 is bottom-most)
! 2335: * col1 (I) int containing 2nd corner col bounding ellipse
! 2336: * (rp->width-1 is rightmost)
! 2337: * thickness (I) int containing number of pixels/bits
! 2338: * thick the ellipse arc line will be
! 2339: * theta0 (I) double containing first angle -360 -> +360
! 2340: * theta1 (I) double containing second angle -360 -> +360
! 2341: * 0=x-axis, positive moving counterclockwise
! 2342: * --------------------------------------------------------------------------
! 2343: * Returns: ( int ) 1 if ellipse drawn okay,
! 2344: * or 0 for any error.
! 2345: * --------------------------------------------------------------------------
! 2346: * Notes: o row0==row1 or col0==col1 are errors
! 2347: * o using ellipse equation x^2/a^2 + y^2/b^2 = 1
! 2348: * Then, with x=r*cos(theta), y=r*sin(theta), ellipse
! 2349: * equation is r = ab/sqrt(a^2*sin^2(theta)+b^2*cos^2(theta))
! 2350: * ======================================================================= */
! 2351: /* --- entry point --- */
! 2352: int circle_recurse ( raster *rp, int row0, int col0,
! 2353: int row1, int col1, int thickness, double theta0, double theta1 )
! 2354: {
! 2355: /* -------------------------------------------------------------------------
! 2356: Allocations and Declarations
! 2357: -------------------------------------------------------------------------- */
! 2358: /* --- lower-left and upper-right bounding points (in our coords) --- */
! 2359: int lorow = min2(row0,row1), /* lower bounding row (top of box) */
! 2360: locol = min2(col0,col1), /* lower bounding col (left of box)*/
! 2361: hirow = max2(row0,row1), /* upper bounding row (bot of box) */
! 2362: hicol = max2(col0,col1); /* upper bounding col (right of box)*/
! 2363: /* --- a and b ellipse params --- */
! 2364: int width = hicol-locol+1, /* width of bounding box */
! 2365: height= hirow-lorow+1; /* height of bounding box */
! 2366: double a = ((double)width)/2.0, /* col x=a when row y=0 */
! 2367: b = ((double)height)/2.0, /* row y=b when col x=0 */
! 2368: ab=a*b, a2=a*a, b2=b*b; /* product and squares */
! 2369: /* --- arc parameters --- */
! 2370: double rads = 0.017453292, /* radians per degree = 1/57.29578 */
! 2371: lotheta = rads*dmod(min2(theta0,theta1),360), /* smaller angle */
! 2372: hitheta = rads*dmod(max2(theta0,theta1),360), /* larger angle */
! 2373: locos=cos(lotheta), losin=sin(lotheta), /* trigs for lotheta */
! 2374: hicos=cos(hitheta), hisin=sin(hitheta), /* trigs for hitheta */
! 2375: rlo = ab/sqrt(b2*locos*locos+a2*losin*losin), /* r for lotheta */
! 2376: rhi = ab/sqrt(b2*hicos*hicos+a2*hisin*hisin), /* r for hitheta */
! 2377: xlo=rlo*locos, ylo=rlo*losin, /*col,row pixel coords for lotheta*/
! 2378: xhi=rhi*hicos, yhi=rhi*hisin, /*col,row pixel coords for hitheta*/
! 2379: xdelta=fabs(xhi-xlo), ydelta=fabs(yhi-ylo), /* col,row deltas */
! 2380: tolerance = 0.5; /* convergence tolerance */
! 2381: /* -------------------------------------------------------------------------
! 2382: recurse if either delta > tolerance
! 2383: -------------------------------------------------------------------------- */
! 2384: if ( ydelta > tolerance /* row hasn't converged */
! 2385: || xdelta > tolerance ) /* col hasn't converged */
! 2386: { double midtheta = 0.5*(theta0+theta1); /* mid angle for arc */
! 2387: circle_recurse(rp,row0,col0,row1,col1,thickness,theta0,midtheta); /*lo*/
! 2388: circle_recurse(rp,row0,col0,row1,col1,thickness,midtheta,theta1); }/*hi*/
! 2389: /* -------------------------------------------------------------------------
! 2390: draw converged point
! 2391: -------------------------------------------------------------------------- */
! 2392: else
! 2393: { double xcol=0.5*(xlo+xhi), yrow=0.5*(ylo+yhi), /* relative to center*/
! 2394: centerrow = 0.5*((double)(lorow+hirow)), /* ellipse y-center */
! 2395: centercol = 0.5*((double)(locol+hicol)), /* ellipse x-center */
! 2396: midrow=centerrow-yrow, midcol=centercol+xcol; /* pixel coords */
! 2397: setpixel(rp,iround(midrow),iround(midcol),255); } /* set midrow,midcol */
! 2398: return ( 1 );
! 2399: } /* --- end-of-function circle_recurse() --- */
! 2400:
! 2401:
! 2402: /* ==========================================================================
! 2403: * Function: bezier_raster ( rp, r0,c0, r1,c1, rt,ct )
! 2404: * Purpose: Recursively draw bezier from r0,c0 to r1,c1
! 2405: * (with tangent point rt,ct) in existing raster rp.
! 2406: * --------------------------------------------------------------------------
! 2407: * Arguments: rp (I) raster * to raster in which a line
! 2408: * will be drawn
! 2409: * r0 (I) double containing row at which
! 2410: * bezier will start (0 is topmost)
! 2411: * c0 (I) double containing col at which
! 2412: * bezier will start (0 is leftmost)
! 2413: * r1 (I) double containing row at which
! 2414: * bezier will end (rp->height-1 is bottom-most)
! 2415: * c1 (I) double containing col at which
! 2416: * bezier will end (rp->width-1 is rightmost)
! 2417: * rt (I) double containing row for tangent point
! 2418: * ct (I) double containing col for tangent point
! 2419: * --------------------------------------------------------------------------
! 2420: * Returns: ( int ) 1 if line drawn okay,
! 2421: * or 0 for any error.
! 2422: * --------------------------------------------------------------------------
! 2423: * Notes: o Recurses, drawing left- and right-halves of bezier curve
! 2424: * until a point is found
! 2425: * ======================================================================= */
! 2426: /* --- entry point --- */
! 2427: int bezier_raster ( raster *rp, double r0, double c0,
! 2428: double r1, double c1, double rt, double ct )
! 2429: {
! 2430: /* -------------------------------------------------------------------------
! 2431: Allocations and Declarations
! 2432: -------------------------------------------------------------------------- */
! 2433: double delrow = fabs(r1-r0), /* 0 if same row */
! 2434: delcol = fabs(c1-c0), /* 0 if same col */
! 2435: tolerance = 0.5; /* draw curve when it goes to point*/
! 2436: double midrow = 0.5*(r0+r1), /* midpoint row */
! 2437: midcol = 0.5*(c0+c1); /* midpoint col */
! 2438: int irow=0, icol=0; /* point to be drawn */
! 2439: int status = 1; /* return status */
! 2440: /* -------------------------------------------------------------------------
! 2441: recurse if either delta > tolerance
! 2442: -------------------------------------------------------------------------- */
! 2443: if ( delrow > tolerance /* row hasn't converged */
! 2444: || delcol > tolerance ) /* col hasn't converged */
! 2445: { bezier_raster(rp, r0,c0, /* left half */
! 2446: 0.5*(rt+midrow), 0.5*(ct+midcol),
! 2447: 0.5*(r0+rt), 0.5*(c0+ct) );
! 2448: bezier_raster(rp, 0.5*(rt+midrow), 0.5*(ct+midcol), /* right half */
! 2449: r1,c1,
! 2450: 0.5*(r1+rt), 0.5*(c1+ct) );
! 2451: return ( 1 ); }
! 2452: /* -------------------------------------------------------------------------
! 2453: draw converged point
! 2454: -------------------------------------------------------------------------- */
! 2455: /* --- get integer point --- */
! 2456: irow = iround(midrow); /* row pixel coord */
! 2457: icol = iround(midcol); /* col pixel coord */
! 2458: /* --- bounds check --- */
! 2459: if ( irow>=0 && irow<rp->height /* row in bounds */
! 2460: && icol>=0 && icol<rp->width ) /* col in bounds */
! 2461: setpixel(rp,irow,icol,255); /* so set pixel at irow,icol*/
! 2462: else status = 0; /* bad status if out-of-bounds */
! 2463: return ( status );
! 2464: } /* --- end-of-function bezier_raster() --- */
! 2465:
! 2466:
! 2467: /* ==========================================================================
! 2468: * Function: border_raster ( rp, ntop, nbot, isline, isfree )
! 2469: * Purpose: Allocate a new raster containing a copy of input rp,
! 2470: * along with ntop extra rows at top and nbot at bottom,
! 2471: * and whose width is either adjusted correspondingly,
! 2472: * or is automatically enlarged to a multiple of 8
! 2473: * with original bitmap centered
! 2474: * --------------------------------------------------------------------------
! 2475: * Arguments: rp (I) raster * to raster on which a border
! 2476: * is to be placed
! 2477: * ntop (I) int containing number extra rows at top.
! 2478: * if negative, abs(ntop) used, and same
! 2479: * number of extra cols added at left.
! 2480: * nbot (I) int containing number extra rows at bottom.
! 2481: * if negative, abs(nbot) used, and same
! 2482: * number of extra cols added at right.
! 2483: * isline (I) int containing 0 to leave border pixels clear
! 2484: * or >0 to draw a line around border of width
! 2485: * isline.
! 2486: * isfree (I) int containing true to free rp before return
! 2487: * --------------------------------------------------------------------------
! 2488: * Returns: ( raster * ) ptr to bordered raster,
! 2489: * or NULL for any error.
! 2490: * --------------------------------------------------------------------------
! 2491: * Notes: o
! 2492: * ======================================================================= */
! 2493: /* --- entry point --- */
! 2494: raster *border_raster ( raster *rp, int ntop, int nbot,
! 2495: int isline, int isfree )
! 2496: {
! 2497: /* -------------------------------------------------------------------------
! 2498: Allocations and Declarations
! 2499: -------------------------------------------------------------------------- */
! 2500: raster *new_raster(), *bp=(raster *)NULL; /*raster back to caller*/
! 2501: int rastput(); /* overlay rp in new bordered raster */
! 2502: int width = (rp==NULL?0:rp->width), /* height of raster */
! 2503: height = (rp==NULL?0:rp->height), /* width of raster */
! 2504: istopneg=0, isbotneg=0, /* true if ntop or nbot negative */
! 2505: leftmargin = 0; /* adjust width to whole number of bytes */
! 2506: int delete_raster(); /* to free input rp if isdelete is true */
! 2507: /* -------------------------------------------------------------------------
! 2508: Initialization
! 2509: -------------------------------------------------------------------------- */
! 2510: if ( rp == NULL ) goto end_of_job; /* no input raster provided */
! 2511: if ( isstring || (1 && rp->height==1) ) /* explicit string signal or infer */
! 2512: { bp=rp; goto end_of_job; } /* return ascii string unchanged */
! 2513: /* --- check for negative args --- */
! 2514: if ( ntop < 0 ) { ntop = -ntop; istopneg=1; } /*flip positive and set flag*/
! 2515: if ( nbot < 0 ) { nbot = -nbot; isbotneg=1; } /*flip positive and set flag*/
! 2516: /* --- adjust height for ntop and nbot margins --- */
! 2517: height += (ntop+nbot); /* adjust height for margins */
! 2518: /* --- adjust width for left and right margins --- */
! 2519: if ( istopneg || isbotneg ) /*caller wants nleft=ntop and/or nright=nbot*/
! 2520: { /* --- adjust width (and leftmargin) as requested by caller -- */
! 2521: if ( istopneg ) { width += ntop; leftmargin = ntop; }
! 2522: if ( isbotneg ) width += nbot; }
! 2523: else
! 2524: { /* --- or adjust width (and leftmargin) to whole number of bytes --- */
! 2525: leftmargin = (width%8==0? 0 : 8-(width%8)); /*makes width multiple of 8*/
! 2526: width += leftmargin; /* width now multiple of 8 */
! 2527: leftmargin /= 2; } /* center original raster */
! 2528: /* -------------------------------------------------------------------------
! 2529: allocate bordered raster, and embed rp within it
! 2530: -------------------------------------------------------------------------- */
! 2531: /* --- allocate bordered raster --- */
! 2532: if ( (bp=new_raster(width,height,rp->pixsz)) /*allocate bordered raster*/
! 2533: == (raster *)NULL ) goto end_of_job; /* and quit if failed */
! 2534: /* --- embed rp in it --- */
! 2535: rastput(bp,rp,ntop,leftmargin,1); /* rp embedded in bp */
! 2536: /* -------------------------------------------------------------------------
! 2537: draw border if requested
! 2538: -------------------------------------------------------------------------- */
! 2539: if ( isline )
! 2540: { int irow, icol, nthick=isline; /*height,width index, line thickness*/
! 2541: /* --- draw left- and right-borders --- */
! 2542: for ( irow=0; irow<height; irow++ ) /* for each row of bp */
! 2543: for ( icol=0; icol<nthick; icol++ ) /* and each pixel of thickness */
! 2544: { setpixel(bp,irow,icol,255); /* left border */
! 2545: setpixel(bp,irow,width-1-icol,255); } /* right border */
! 2546: /* --- draw top- and bottom-borders --- */
! 2547: for ( icol=0; icol<width; icol++ ) /* for each col of bp */
! 2548: for ( irow=0; irow<nthick; irow++ ) /* and each pixel of thickness */
! 2549: { setpixel(bp,irow,icol,255); /* top border */
! 2550: setpixel(bp,height-1-irow,icol,255); } /* bottom border */
! 2551: } /* --- end-of-if(isline) --- */
! 2552: /* -------------------------------------------------------------------------
! 2553: free rp if no longer needed
! 2554: -------------------------------------------------------------------------- */
! 2555: if ( isfree ) /*caller no longer needs rp*/
! 2556: delete_raster(rp); /* so free it for him */
! 2557: /* -------------------------------------------------------------------------
! 2558: Back to caller with bordered raster (or null for any error)
! 2559: -------------------------------------------------------------------------- */
! 2560: end_of_job:
! 2561: return ( bp ); /* back with bordered or null ptr */
! 2562: } /* --- end-of-function border_raster() --- */
! 2563:
! 2564:
! 2565: /* ==========================================================================
! 2566: * Function: type_raster ( rp, fp )
! 2567: * Purpose: Emit an ascii dump representing rp, on fp.
! 2568: * --------------------------------------------------------------------------
! 2569: * Arguments: rp (I) ptr to raster struct for which an
! 2570: * ascii dump is to be constructed.
! 2571: * fp (I) File ptr to output device (defaults to
! 2572: * stdout if passed as NULL).
! 2573: * --------------------------------------------------------------------------
! 2574: * Returns: ( int ) 1 if completed successfully,
! 2575: * or 0 otherwise (for any error).
! 2576: * --------------------------------------------------------------------------
! 2577: * Notes:
! 2578: * ======================================================================= */
! 2579: /* --- entry point --- */
! 2580: int type_raster ( raster *rp, FILE *fp )
! 2581: {
! 2582: /* -------------------------------------------------------------------------
! 2583: Allocations and Declarations
! 2584: -------------------------------------------------------------------------- */
! 2585: static int display_width = 72; /* max columns for display */
! 2586: static char display_chars[16] = /* display chars for bytemap */
! 2587: { ' ','1','2','3','4','5','6','7','8','9','A','B','C','D','E','*' };
! 2588: char scanline[133]; /* ascii image for one scan line */
! 2589: int scan_width; /* #chars in scan (<=display_width)*/
! 2590: int irow, locol,hicol=(-1); /* height index, width indexes */
! 2591: /* --------------------------------------------------------------------------
! 2592: initialization
! 2593: -------------------------------------------------------------------------- */
! 2594: /* --- redirect null fp --- */
! 2595: if ( fp == (FILE *)NULL ) fp = stdout; /* default fp to stdout if null */
! 2596: /* --- check for ascii string --- */
! 2597: if ( isstring /* pixmap has string, not raster */
! 2598: || (1 && rp->height==1) ) /* infer input rp is a string */
! 2599: {
! 2600: char *string = (char *)(rp->pixmap); /*interpret pixmap as ascii string*/
! 2601: int width = strlen(string); /* #chars in ascii string */
! 2602: while ( width > display_width-2 ) /* too big for one line */
! 2603: { fprintf(fp,"\"%.*s\"\n",display_width-2,string); /*display leading chars*/
! 2604: string += (display_width-2); /* bump string past displayed chars*/
! 2605: width -= (display_width-2); } /* decrement remaining width */
! 2606: fprintf(fp,"\"%.*s\"\n",width,string); /* display trailing chars */
! 2607: return ( 1 );
! 2608: } /* --- end-of-if(isstring) --- */
! 2609: /* --------------------------------------------------------------------------
! 2610: display ascii dump of bitmap image (in segments if display_width < rp->width)
! 2611: -------------------------------------------------------------------------- */
! 2612: while ( (locol=hicol+1) < rp->width ) /*start where prev segment left off*/
! 2613: {
! 2614: /* --- set hicol for this pass (locol set above) --- */
! 2615: hicol += display_width; /* show as much as display allows */
! 2616: if (hicol >= rp->width) hicol = rp->width - 1; /*but not more than raster*/
! 2617: scan_width = hicol-locol+1; /* #chars in this scan */
! 2618: if ( locol > 0 ) fprintf(fp,"----------\n"); /*separator between segments*/
! 2619: /* ------------------------------------------------------------------------
! 2620: display all scan lines for this local...hicol segment range
! 2621: ------------------------------------------------------------------------ */
! 2622: for ( irow=0; irow<rp->height; irow++ ) /* all scan lines for col range */
! 2623: {
! 2624: /* --- allocations and declarations --- */
! 2625: int ipix, /* pixmap[] index for this scan */
! 2626: lopix = irow*rp->width + locol; /*first pixmap[] pixel in this scan*/
! 2627: /* --- set chars in scanline[] based on pixels in rp->pixmap[] --- */
! 2628: for ( ipix=0; ipix<scan_width; ipix++ ) /* set each char */
! 2629: if ( rp->pixsz == 1 ) /*' '=0 or '*'=1 to display bitmap*/
! 2630: scanline[ipix] = (getlongbit(rp->pixmap,lopix+ipix)==1? '*':'.');
! 2631: else /* should have a bytemap */
! 2632: if ( rp->pixsz == 8 ) /* double-check pixsz for bytemap */
! 2633: { int pixval = (int)((rp->pixmap)[lopix+ipix]), /*pixel's byte value*/
! 2634: ichar = min2(15,pixval/16); /* index for ' ', '1'...'e', '*' */
! 2635: scanline[ipix] = display_chars[ichar]; } /*set ' ' for 0-15, etc*/
! 2636: /* --- display completed scan line --- */
! 2637: fprintf(fp,"%.*s\n",scan_width,scanline);
! 2638: } /* --- end-of-for(irow) --- */
! 2639: } /* --- end-of-while(hicol<rp->width) --- */
! 2640: /* -------------------------------------------------------------------------
! 2641: Back to caller with 1=okay, 0=failed.
! 2642: -------------------------------------------------------------------------- */
! 2643: return ( 1 );
! 2644: } /* --- end-of-function type_raster() --- */
! 2645:
! 2646:
! 2647: /* ==========================================================================
! 2648: * Function: type_bytemap ( bp, grayscale, width, height, fp )
! 2649: * Purpose: Emit an ascii dump representing bp, on fp.
! 2650: * --------------------------------------------------------------------------
! 2651: * Arguments: bp (I) intbyte * to bytemap for which an
! 2652: * ascii dump is to be constructed.
! 2653: * grayscale (I) int containing #gray shades, 256 for 8-bit
! 2654: * width (I) int containing #cols in bytemap
! 2655: * height (I) int containing #rows in bytemap
! 2656: * fp (I) File ptr to output device (defaults to
! 2657: * stdout if passed as NULL).
! 2658: * --------------------------------------------------------------------------
! 2659: * Returns: ( int ) 1 if completed successfully,
! 2660: * or 0 otherwise (for any error).
! 2661: * --------------------------------------------------------------------------
! 2662: * Notes:
! 2663: * ======================================================================= */
! 2664: /* --- entry point --- */
! 2665: int type_bytemap ( intbyte *bp, int grayscale,
! 2666: int width, int height, FILE *fp )
! 2667: {
! 2668: /* -------------------------------------------------------------------------
! 2669: Allocations and Declarations
! 2670: -------------------------------------------------------------------------- */
! 2671: static int display_width = 72; /* max columns for display */
! 2672: int byte_width = 3, /* cols to display byte (ff+space) */
! 2673: maxbyte = 0; /* if maxbyte<16, set byte_width=2 */
! 2674: int white_byte = 0, /* show dots for white_byte's */
! 2675: black_byte = grayscale-1; /* show stars for black_byte's */
! 2676: char scanline[133]; /* ascii image for one scan line */
! 2677: int scan_width, /* #chars in scan (<=display_width)*/
! 2678: scan_cols; /* #cols in scan (hicol-locol+1) */
! 2679: int ibyte, /* bp[] index */
! 2680: irow, locol,hicol=(-1); /* height index, width indexes */
! 2681: /* --------------------------------------------------------------------------
! 2682: initialization
! 2683: -------------------------------------------------------------------------- */
! 2684: /* --- redirect null fp --- */
! 2685: if ( fp == (FILE *)NULL ) fp = stdout; /* default fp to stdout if null */
! 2686: /* --- check for ascii string --- */
! 2687: if ( isstring ) /* bp has ascii string, not raster */
! 2688: { width = strlen((char *)bp); /* #chars in ascii string */
! 2689: height = 1; } /* default */
! 2690: /* --- see if we can get away with byte_width=1 --- */
! 2691: for ( ibyte=0; ibyte<width*height; ibyte++ ) /* check all bytes */
! 2692: { int byteval = (int)bp[ibyte]; /* current byte value */
! 2693: if ( byteval < black_byte ) /* if it's less than black_byte */
! 2694: maxbyte = max2(maxbyte,byteval); } /* then find max non-black value */
! 2695: if ( maxbyte < 16 ) /* bytevals will fit in one column */
! 2696: byte_width = 1; /* so reset display byte_width */
! 2697: /* --------------------------------------------------------------------------
! 2698: display ascii dump of bitmap image (in segments if display_width < rp->width)
! 2699: -------------------------------------------------------------------------- */
! 2700: while ( (locol=hicol+1) < width ) /*start where prev segment left off*/
! 2701: {
! 2702: /* --- set hicol for this pass (locol set above) --- */
! 2703: hicol += display_width/byte_width; /* show as much as display allows */
! 2704: if (hicol >= width) hicol = width - 1; /* but not more than bytemap */
! 2705: scan_cols = hicol-locol+1; /* #cols in this scan */
! 2706: scan_width = byte_width*scan_cols; /* #chars in this scan */
! 2707: if ( locol>0 && !isstring ) fprintf(fp,"----------\n"); /* separator */
! 2708: /* ------------------------------------------------------------------------
! 2709: display all scan lines for this local...hicol segment range
! 2710: ------------------------------------------------------------------------ */
! 2711: for ( irow=0; irow<height; irow++ ) /* all scan lines for col range */
! 2712: {
! 2713: /* --- allocations and declarations --- */
! 2714: int lobyte = irow*width + locol; /* first bp[] byte in this scan */
! 2715: char scanbyte[32]; /* sprintf() buffer for byte */
! 2716: /* --- set chars in scanline[] based on bytes in bytemap bp[] --- */
! 2717: memset(scanline,' ',scan_width); /* blank out scanline */
! 2718: for ( ibyte=0; ibyte<scan_cols; ibyte++ ) /* set chars for each col */
! 2719: { int byteval = (int)bp[lobyte+ibyte]; /* value of current byte */
! 2720: memset(scanbyte,'.',byte_width); /* dot-fill scanbyte */
! 2721: if ( byteval == black_byte ) /* but if we have a black byte */
! 2722: memset(scanbyte,'*',byte_width); /* star-fill scanbyte instead */
! 2723: if ( byte_width > 1 ) /* don't blank out single char */
! 2724: scanbyte[byte_width-1] = ' '; /* blank-fill rightmost character */
! 2725: if ( byteval != white_byte /* format bytes that are non-white */
! 2726: && byteval != black_byte ) /* and that are non-black */
! 2727: sprintf(scanbyte,"%*x ",max2(1,byte_width-1),byteval); /*hex-format*/
! 2728: memcpy(scanline+ibyte*byte_width,scanbyte,byte_width); } /*in line*/
! 2729: /* --- display completed scan line --- */
! 2730: fprintf(fp,"%.*s\n",scan_width,scanline);
! 2731: } /* --- end-of-for(irow) --- */
! 2732: } /* --- end-of-while(hicol<width) --- */
! 2733: /* -------------------------------------------------------------------------
! 2734: Back to caller with 1=okay, 0=failed.
! 2735: -------------------------------------------------------------------------- */
! 2736: return ( 1 );
! 2737: } /* --- end-of-function type_bytemap() --- */
! 2738:
! 2739:
! 2740: /* ==========================================================================
! 2741: * Function: xbitmap_raster ( rp, fp )
! 2742: * Purpose: Emit a mime xbitmap representing rp, on fp.
! 2743: * --------------------------------------------------------------------------
! 2744: * Arguments: rp (I) ptr to raster struct for which a mime
! 2745: * xbitmap is to be constructed.
! 2746: * fp (I) File ptr to output device (defaults to
! 2747: * stdout if passed as NULL).
! 2748: * --------------------------------------------------------------------------
! 2749: * Returns: ( int ) 1 if completed successfully,
! 2750: * or 0 otherwise (for any error).
! 2751: * --------------------------------------------------------------------------
! 2752: * Notes:
! 2753: * ======================================================================= */
! 2754: /* --- entry point --- */
! 2755: int xbitmap_raster ( raster *rp, FILE *fp )
! 2756: {
! 2757: /* -------------------------------------------------------------------------
! 2758: Allocations and Declarations
! 2759: -------------------------------------------------------------------------- */
! 2760: char *title = "image"; /* dummy title */
! 2761: int hex_bitmap(); /* dump bitmap as hex bytes */
! 2762: /* --------------------------------------------------------------------------
! 2763: emit text to display mime xbitmap representation of rp->bitmap image
! 2764: -------------------------------------------------------------------------- */
! 2765: /* --- first redirect null fp --- */
! 2766: if ( fp == (FILE *)NULL ) fp = stdout; /* default fp to stdout if null */
! 2767: /* --- check for ascii string --- */
! 2768: if ( isstring ) /* pixmap has string, not raster */
! 2769: return ( 0 ); /* can't handle ascii string */
! 2770: /* --- emit prologue strings and hex dump of bitmap for mime xbitmap --- */
! 2771: fprintf( fp, "Content-type: image/x-xbitmap\n\n" );
! 2772: fprintf( fp, "#define %s_width %d\n#define %s_height %d\n",
! 2773: title,rp->width, title,rp->height );
! 2774: fprintf( fp, "static char %s_bits[] = {\n", title );
! 2775: hex_bitmap(rp,fp,0,0); /* emit hex dump of bitmap bytes */
! 2776: fprintf (fp,"};\n"); /* ending with "};" for C array */
! 2777: /* -------------------------------------------------------------------------
! 2778: Back to caller with 1=okay, 0=failed.
! 2779: -------------------------------------------------------------------------- */
! 2780: return ( 1 );
! 2781: } /* --- end-of-function xbitmap_raster() --- */
! 2782:
! 2783:
! 2784: /* ==========================================================================
! 2785: * Function: cstruct_chardef ( cp, fp, col1 )
! 2786: * Purpose: Emit a C struct of cp on fp, starting in col1.
! 2787: * --------------------------------------------------------------------------
! 2788: * Arguments: cp (I) ptr to chardef struct for which
! 2789: * a C struct is to be generated.
! 2790: * fp (I) File ptr to output device (defaults to
! 2791: * stdout if passed as NULL).
! 2792: * col1 (I) int containing 0...65; output lines
! 2793: * are preceded by col1 blanks.
! 2794: * --------------------------------------------------------------------------
! 2795: * Returns: ( int ) 1 if completed successfully,
! 2796: * or 0 otherwise (for any error).
! 2797: * --------------------------------------------------------------------------
! 2798: * Notes:
! 2799: * ======================================================================= */
! 2800: /* --- entry point --- */
! 2801: int cstruct_chardef ( chardef *cp, FILE *fp, int col1 )
! 2802: {
! 2803: /* -------------------------------------------------------------------------
! 2804: Allocations and Declarations
! 2805: -------------------------------------------------------------------------- */
! 2806: char field[64]; /* field within output line */
! 2807: int cstruct_raster(), /* emit a raster */
! 2808: emit_string(); /* emit a string and comment */
! 2809: /* -------------------------------------------------------------------------
! 2810: emit charnum, location, name / hirow, hicol, lorow, locol
! 2811: -------------------------------------------------------------------------- */
! 2812: /* --- charnum, location, name --- */
! 2813: sprintf(field,"{ %3d,%5d,\n", cp->charnum,cp->location); /*char#,location*/
! 2814: emit_string ( fp, col1, field, "character number, location");
! 2815: /* --- toprow, topleftcol, botrow, botleftcol --- */
! 2816: sprintf(field," %3d,%2d, %3d,%2d,\n", /* format... */
! 2817: cp->toprow,cp->topleftcol, /* toprow, topleftcol, */
! 2818: cp->botrow,cp->botleftcol); /* and botrow, botleftcol */
! 2819: emit_string ( fp, col1, field, "topleft row,col, and botleft row,col");
! 2820: /* -------------------------------------------------------------------------
! 2821: emit raster and chardef's closing brace, and then return to caller
! 2822: -------------------------------------------------------------------------- */
! 2823: cstruct_raster(&cp->image,fp,col1+4); /* emit raster */
! 2824: emit_string ( fp, 0, " }", NULL); /* emit closing brace */
! 2825: return ( 1 ); /* back to caller with 1=okay, 0=failed */
! 2826: } /* --- end-of-function cstruct_chardef() --- */
! 2827:
! 2828:
! 2829: /* ==========================================================================
! 2830: * Function: cstruct_raster ( rp, fp, col1 )
! 2831: * Purpose: Emit a C struct of rp on fp, starting in col1.
! 2832: * --------------------------------------------------------------------------
! 2833: * Arguments: rp (I) ptr to raster struct for which
! 2834: * a C struct is to be generated.
! 2835: * fp (I) File ptr to output device (defaults to
! 2836: * stdout if passed as NULL).
! 2837: * col1 (I) int containing 0...65; output lines
! 2838: * are preceded by col1 blanks.
! 2839: * --------------------------------------------------------------------------
! 2840: * Returns: ( int ) 1 if completed successfully,
! 2841: * or 0 otherwise (for any error).
! 2842: * --------------------------------------------------------------------------
! 2843: * Notes:
! 2844: * ======================================================================= */
! 2845: /* --- entry point --- */
! 2846: int cstruct_raster ( raster *rp, FILE *fp, int col1 )
! 2847: {
! 2848: /* -------------------------------------------------------------------------
! 2849: Allocations and Declarations
! 2850: -------------------------------------------------------------------------- */
! 2851: char field[64]; /* field within output line */
! 2852: char typecast[64] = "(pixbyte *)"; /* type cast for pixmap string */
! 2853: int hex_bitmap(); /* to emit raster bitmap */
! 2854: int emit_string(); /* emit a string and comment */
! 2855: /* -------------------------------------------------------------------------
! 2856: emit width and height
! 2857: -------------------------------------------------------------------------- */
! 2858: sprintf(field,"{ %2d, %3d,%2d, %s\n", /* format width,height,pixsz */
! 2859: rp->width,rp->height,rp->pixsz,typecast);
! 2860: emit_string ( fp, col1, field, "widthxheight, pixsz,map...");
! 2861: /* -------------------------------------------------------------------------
! 2862: emit bitmap and closing brace, and return to caller
! 2863: -------------------------------------------------------------------------- */
! 2864: hex_bitmap(rp,fp,col1+2,1); /* emit bitmap */
! 2865: emit_string ( fp, 0, " }", NULL); /* emit closing brace */
! 2866: return ( 1 ); /* back to caller with 1=okay, 0=failed */
! 2867: } /* --- end-of-function cstruct_raster() --- */
! 2868:
! 2869:
! 2870: /* ==========================================================================
! 2871: * Function: hex_bitmap ( rp, fp, col1, isstr )
! 2872: * Purpose: Emit a hex dump of the bitmap of rp on fp, starting in col1.
! 2873: * If isstr (is string) is true, the dump is of the form
! 2874: * "\x01\x02\x03\x04\x05..."
! 2875: * Otherwise, if isstr is false, the dump is of the form
! 2876: * 0x01,0x02,0x03,0x04,0x05...
! 2877: * --------------------------------------------------------------------------
! 2878: * Arguments: rp (I) ptr to raster struct for which
! 2879: * a hex dump is to be constructed.
! 2880: * fp (I) File ptr to output device (defaults to
! 2881: * stdout if passed as NULL).
! 2882: * col1 (I) int containing 0...65; output lines
! 2883: * are preceded by col1 blanks.
! 2884: * isstr (I) int specifying dump format as described above
! 2885: * --------------------------------------------------------------------------
! 2886: * Returns: ( int ) 1 if completed successfully,
! 2887: * or 0 otherwise (for any error).
! 2888: * --------------------------------------------------------------------------
! 2889: * Notes:
! 2890: * ======================================================================= */
! 2891: /* --- entry point --- */
! 2892: int hex_bitmap ( raster *rp, FILE *fp, int col1, int isstr )
! 2893: {
! 2894: /* -------------------------------------------------------------------------
! 2895: Allocations and Declarations
! 2896: -------------------------------------------------------------------------- */
! 2897: int ibyte, nbytes=pixmapsz(rp); /* #bytes in raster */
! 2898: char stub[64]=" ";/* col1 leading blanks */
! 2899: int linewidth = 64, /* (roughly) rightmost column */
! 2900: colwidth = (isstr? 4:5); /* #cols required for each byte */
! 2901: int ncols = (linewidth-col1)/colwidth; /* new line after ncols bytes */
! 2902: /* --------------------------------------------------------------------------
! 2903: initialization
! 2904: -------------------------------------------------------------------------- */
! 2905: /* --- redirect null fp --- */
! 2906: if ( fp == (FILE *)NULL ) fp = stdout; /* default fp to stdout if null */
! 2907: /* --- emit initial stub if wanted --- */
! 2908: if ( col1 > 0 ) fprintf(fp,"%.*s",col1,stub); /* stub preceding 1st line */
! 2909: /* --------------------------------------------------------------------------
! 2910: emit hex dump of rp->bitmap image
! 2911: -------------------------------------------------------------------------- */
! 2912: if ( isstr ) fprintf(fp,"\""); /* opening " before first line */
! 2913: for ( ibyte=0; ibyte<nbytes; ibyte++ ) /* one byte at a time */
! 2914: {
! 2915: /* --- display a byte as hex char or number, depending on isstr --- */
! 2916: if ( isstr ) /* string format wanted */
! 2917: fprintf(fp,"\\x%02x",(rp->pixmap)[ibyte]); /*print byte as hex char*/
! 2918: else /* comma-separated format wanted */
! 2919: fprintf(fp,"0x%02x",(rp->pixmap)[ibyte]); /*print byte as hex number*/
! 2920: /* --- add a separator and newline, etc, as necessary --- */
! 2921: if ( ibyte < nbytes-1) /* not the last byte yet */
! 2922: {
! 2923: if ( !isstr ) fprintf(fp,","); /* follow hex number with comma */
! 2924: if ( (ibyte+1)%ncols==0 ) /* need new line after every ncols */
! 2925: if ( !isstr ) /* for hex numbers format ... */
! 2926: fprintf(fp,"\n%.*s",col1,stub); /* ...just need newline and stub */
! 2927: else /* for string format... */
! 2928: fprintf(fp,"\"\n%.*s\"",col1,stub); /* ...need closing, opening "s */
! 2929: } /* --- end-of-if(ibyte<nbytes-1) --- */
! 2930: } /* --- end-of-for(ibyte) --- */
! 2931: if ( isstr ) fprintf(fp,"\""); /* closing " after last line */
! 2932: return ( 1 ); /* back with 1=okay, 0=failed */
! 2933: } /* --- end-of-function hex_bitmap() --- */
! 2934:
! 2935:
! 2936: /* ==========================================================================
! 2937: * Function: emit_string ( fp, col1, string, comment )
! 2938: * Purpose: Emit string on fp, starting in col1,
! 2939: * and followed by right-justified comment.
! 2940: * --------------------------------------------------------------------------
! 2941: * Arguments: fp (I) File ptr to output device (defaults to
! 2942: * stdout if passed as NULL).
! 2943: * col1 (I) int containing 0 or #blanks preceding string
! 2944: * string (I) char * containing string to be emitted.
! 2945: * If last char of string is '\n',
! 2946: * the emitted line ends with a newline,
! 2947: * otherwise not.
! 2948: * comment (I) NULL or char * containing right-justified
! 2949: * comment (we enclose between /star and star/)
! 2950: * --------------------------------------------------------------------------
! 2951: * Returns: ( int ) 1 if completed successfully,
! 2952: * or 0 otherwise (for any error).
! 2953: * --------------------------------------------------------------------------
! 2954: * Notes: o
! 2955: * ======================================================================= */
! 2956: /* --- entry point --- */
! 2957: int emit_string ( FILE *fp, int col1, char *string, char *comment )
! 2958: {
! 2959: /* -------------------------------------------------------------------------
! 2960: Allocations and Declarations
! 2961: -------------------------------------------------------------------------- */
! 2962: char line[256]; /* construct line with caller's fields */
! 2963: int fieldlen; /* #chars in one of caller's fields */
! 2964: int linelen = 72; /*line length (for right-justified comment)*/
! 2965: int isnewline = 0; /* true to emit \n at end of line */
! 2966: /* --------------------------------------------------------------------------
! 2967: construct line containing prolog, string, epilog, and finally comment
! 2968: -------------------------------------------------------------------------- */
! 2969: /* --- init line --- */
! 2970: memset(line,' ',255); /* start line with blanks */
! 2971: /* --- embed string into line --- */
! 2972: if ( string != NULL ) /* if caller gave us a string... */
! 2973: { fieldlen = strlen(string); /* #cols required for string */
! 2974: if ( string[fieldlen-1] == '\n' ) /* check last char for newline */
! 2975: { isnewline = 1; /* got it, so set flag */
! 2976: fieldlen--; } /* but don't print it yet */
! 2977: memcpy(line+col1,string,fieldlen); /* embid string starting at col1 */
! 2978: col1 += fieldlen; } /* bump col past epilog */
! 2979: /* --- embed comment into line --- */
! 2980: if ( comment != NULL ) /* if caller gave us a comment... */
! 2981: { fieldlen = 6 + strlen(comment); /* plus /star, star/, 2 spaces */
! 2982: if ( linelen-fieldlen < col1 ) /* comment won't fit */
! 2983: fieldlen -= (col1 - (linelen-fieldlen)); /* truncate comment to fit */
! 2984: if ( fieldlen > 6 ) /* can fit all or part of comment */
! 2985: sprintf(line+linelen-fieldlen,"/%c %.*s %c/", /* so embed it in line */
! 2986: '*', fieldlen-6,comment, '*');
! 2987: col1 = linelen; } /* indicate line filled */
! 2988: /* --- line completed --- */
! 2989: line[col1] = '\000'; /* null-terminate completed line */
! 2990: /* -------------------------------------------------------------------------
! 2991: emit line, then back to caller with 1=okay, 0=failed.
! 2992: -------------------------------------------------------------------------- */
! 2993: /* --- first redirect null fp --- */
! 2994: if ( fp == (FILE *)NULL ) fp = stdout; /* default fp to stdout if null */
! 2995: /* --- emit line (and optional newline) --- */
! 2996: fprintf(fp,"%.*s",linelen,line); /* no more than linelen chars */
! 2997: if ( isnewline ) fprintf(fp,"\n"); /*caller wants terminating newline*/
! 2998: return ( 1 );
! 2999: } /* --- end-of-function emit_string() --- */
! 3000:
! 3001:
! 3002: /* ==========================================================================
! 3003: * Function: get_symdef ( symbol )
! 3004: * Purpose: returns mathchardef struct for symbol
! 3005: * --------------------------------------------------------------------------
! 3006: * Arguments: symbol (I) char * containing symbol
! 3007: * whose corresponding mathchardef is wanted
! 3008: * --------------------------------------------------------------------------
! 3009: * Returns: ( mathchardef * ) pointer to struct defining symbol,
! 3010: * or NULL for any error
! 3011: * --------------------------------------------------------------------------
! 3012: * Notes: o Input symbol need only contain a leading substring to match,
! 3013: * e.g., \gam passed in symbol will match \gamma in the table.
! 3014: * If the table contains two or more possible matches,
! 3015: * the shortest is returned, e.g., input \e will return with
! 3016: * data for \eta rather than \epsilon. To get \epsilon,
! 3017: * you must pass a leading substring long enough to eliminate
! 3018: * shorter table matches, i.e., in this case \ep
! 3019: * ======================================================================= */
! 3020: /* --- entry point --- */
! 3021: mathchardef *get_symdef ( char *symbol )
! 3022: {
! 3023: /* -------------------------------------------------------------------------
! 3024: Allocations and Declarations
! 3025: -------------------------------------------------------------------------- */
! 3026: mathchardef *symdefs = symtable; /* table of mathchardefs */
! 3027: int idef = 0, /* symdefs[] index */
! 3028: bestdef = (-9999); /*index of shortest matching symdef*/
! 3029: int symlen = strlen(symbol), /* length of input symbol */
! 3030: deflen, minlen=9999; /*length of shortest matching symdef*/
! 3031: int /*alnumsym = (symlen==1 && isalnum(*symbol)),*/ /*alphanumeric sym*/
! 3032: alphasym = (symlen==1 && isalpha(*symbol)); /* or alpha symbol */
! 3033: static char *displaysyms[][2] = { /*xlate to Big sym for \displaystyle*/
! 3034: {"\\int", "\\Bigint"},
! 3035: {"\\oint", "\\Bigoint"},
! 3036: {"\\sum", "\\Bigsum"},
! 3037: {"\\prod", "\\Bigprod"},
! 3038: {"\\coprod", "\\Bigcoprod"},
! 3039: {"\\cup", "\\Bigcup"},
! 3040: {"\\sqcup", "\\Bigsqcup"},
! 3041: {"\\cap", "\\Bigcap"},
! 3042: {"\\sqcap", "\\sqcap"}, /* don't have \Bigsqcap */
! 3043: {"\\odot", "\\Bigodot"},
! 3044: {"\\oplus", "\\Bigoplus"},
! 3045: {"\\otimes", "\\Bigotimes"},
! 3046: {"\\uplus", "\\Biguplus"},
! 3047: {"\\wedge", "\\Bigwedge"},
! 3048: {"\\vee", "\\Bigvee"},
! 3049: {NULL, NULL} };
! 3050: /* -------------------------------------------------------------------------
! 3051: If in \displaystyle mode, first xlate int to Bigint, etc.
! 3052: -------------------------------------------------------------------------- */
! 3053: if ( isdisplaystyle > 1 ) /* we're in \displaystyle mode */
! 3054: for ( idef=0; ; idef++ ) { /* lookup symbol in displaysyms */
! 3055: char *fromsym = displaysyms[idef][0], /* look for this symbol */
! 3056: *tosym = displaysyms[idef][1]; /* and xlate it to this symbol */
! 3057: if ( fromsym == NULL ) break; /* end-of-table */
! 3058: if ( !strcmp(symbol,fromsym) ) /* found a match */
! 3059: { if ( msglevel>=99 && msgfp!=NULL ) /* debugging output */
! 3060: { fprintf(msgfp,"get_symdef> isdisplaystyle=%d, xlated %s to %s\n",
! 3061: isdisplaystyle,symbol,tosym); fflush(msgfp); }
! 3062: symbol = tosym; /* so look up tosym instead */
! 3063: symlen = strlen(symbol); /* reset symbol length */
! 3064: break; } /* no need to search further */
! 3065: } /* --- end-of-for(idef) --- */
! 3066: /* -------------------------------------------------------------------------
! 3067: search symdefs[] in order for first occurrence of symbol
! 3068: -------------------------------------------------------------------------- */
! 3069: for ( idef=0; ;idef++ ) /* until trailer record found */
! 3070: if ( symdefs[idef].symbol == NULL ) break; /* reached end-of-table */
! 3071: else /* check against caller's symbol */
! 3072: if ( strncmp(symbol,symdefs[idef].symbol,symlen) == 0 ) /* found match */
! 3073: if ( symdefs[idef].handler != NULL /* mode irrelevant for directives */
! 3074: || istext==0 /* mathmode, so use first match */
! 3075: || (istext==1 && symdefs[idef].family==CMR10) /*textmode && rm text*/
! 3076: || (istext==2 && symdefs[idef].family==CMMI10) /*textmode && it text*/
! 3077: || (istext==3 && symdefs[idef].family==BBOLD10) /*textmode && bb text*/
! 3078: || (istext!=3 && !alphasym) ) /* not bb and not alpha */
! 3079: if ( (deflen=strlen(symdefs[idef].symbol)) < minlen ) /*new best match*/
! 3080: { bestdef = idef; /* save index of new best match */
! 3081: if ( (minlen = deflen) /* and save its len for next test */
! 3082: == symlen ) break; } /*perfect match, so return with it*/
! 3083: if ( bestdef < 0 ) /* failed to look up symbol */
! 3084: if ( istext != 0 ) /* we're in a restricted font mode */
! 3085: { int wastext = istext; /* save current mode */
! 3086: mathchardef *symdef = NULL; /* lookup result with istext=0 */
! 3087: istext = 0; /*try to look up symbol in any font*/
! 3088: symdef = get_symdef(symbol); /* repeat lookup with istext=0 */
! 3089: istext = wastext; /* reset font mode */
! 3090: return symdef; } /* caller gets istext=0 lookup */
! 3091: if ( msgfp!=NULL && msglevel>=999 ) /* debugging output */
! 3092: { fprintf(msgfp,"get_symdefs> symbol=%s matches symtable[%d]=%s\n",
! 3093: symbol,bestdef,(bestdef<0?"NotFound":symdefs[bestdef].symbol));
! 3094: fflush(msgfp); }
! 3095: return ( (bestdef<0? NULL : &(symdefs[bestdef])) ); /*NULL or best symdef[]*/
! 3096: } /* --- end-of-function get_symdef() --- */
! 3097:
! 3098:
! 3099: /* ==========================================================================
! 3100: * Function: get_chardef ( symdef, size )
! 3101: * Purpose: returns chardef ptr containing data for symdef at given size
! 3102: * --------------------------------------------------------------------------
! 3103: * Arguments: symdef (I) mathchardef * corresponding to symbol
! 3104: * whose corresponding chardef is wanted
! 3105: * size (I) int containing 0-4 for desired size
! 3106: * --------------------------------------------------------------------------
! 3107: * Returns: ( chardef * ) pointer to struct defining symbol at size,
! 3108: * or NULL for any error
! 3109: * --------------------------------------------------------------------------
! 3110: * Notes: o if size unavailable, the next-closer-to-normalsize
! 3111: * is returned instead.
! 3112: * ======================================================================= */
! 3113: /* --- entry point --- */
! 3114: chardef *get_chardef ( mathchardef *symdef, int size )
! 3115: {
! 3116: /* -------------------------------------------------------------------------
! 3117: Allocations and Declarations
! 3118: -------------------------------------------------------------------------- */
! 3119: fontfamily *fonts = fonttable; /* table of font families */
! 3120: chardef **fontdef, /*tables for desired font, by size*/
! 3121: *gfdata = (chardef *)NULL; /* chardef for symdef,size */
! 3122: int ifont; /* fonts[] index */
! 3123: int family, charnum; /* indexes retrieved from symdef */
! 3124: int sizeinc = 0, /*+1 or -1 to get closer to normal*/
! 3125: normalsize = 2; /* this size always present */
! 3126: int isBig = 0; /*true if symbol's 1st char is upper*/
! 3127: char *symptr = NULL; /* look for 1st alpha of symbol */
! 3128: /* -------------------------------------------------------------------------
! 3129: initialization
! 3130: -------------------------------------------------------------------------- */
! 3131: /* --- check symdef --- */
! 3132: if ( symdef == NULL ) return ( NULL ); /* get_symdef() probably failed */
! 3133: /* --- get local copy of indexes from symdef --- */
! 3134: family = symdef->family; /* font family containing symbol */
! 3135: charnum = symdef->charnum; /* char# of symbol within font */
! 3136: /* --- check for supersampling --- */
! 3137: if ( issupersampling ) /* check for supersampling fonts */
! 3138: if ( fonts != ssfonttable ) /* uh oh--probably internal error */
! 3139: { fonts = ssfonttable; } /* force it */
! 3140: /* --- check requested size, and set size increment --- */
! 3141: if ( 0 && issupersampling ) /* set size index for supersampling */
! 3142: size = LARGESTSIZE+1; /* index 1 past largest size */
! 3143: else /* low pass indexes 0...LARGESTSIZE */
! 3144: {
! 3145: if( size<0 ) size = 0; /* size was definitely too small */
! 3146: if( size>LARGESTSIZE ) size = LARGESTSIZE; /* or definitely too large */
! 3147: if( size<normalsize ) sizeinc = (+1); /*use next larger if size too small*/
! 3148: if( size>normalsize ) sizeinc = (-1); /*or next smaller if size too large*/
! 3149: }
! 3150: /* --- check for really big symbol (1st char of symbol name uppercase) --- */
! 3151: for ( symptr=symdef->symbol; *symptr!='\000'; symptr++ ) /*skip leading \'s*/
! 3152: if ( isalpha(*symptr) ) /* found leading alpha char */
! 3153: { isBig = isupper(*symptr); /* is 1st char of name uppercase? */
! 3154: if ( !isBig /* 1st char lowercase */
! 3155: && strlen(symptr) >= 4 ) /* but followed by at least 3 chars */
! 3156: isBig = !memcmp(symptr,"big\\",4) /* isBig if name starts with big\ */
! 3157: || !memcmp(symptr,"bigg",4); /* or with bigg */
! 3158: break; } /* don't check beyond 1st char */
! 3159: /* -------------------------------------------------------------------------
! 3160: find font family in table of fonts[]
! 3161: -------------------------------------------------------------------------- */
! 3162: /* --- look up font family --- */
! 3163: for ( ifont=0; ;ifont++ ) /* until trailer record found */
! 3164: if ( fonts[ifont].family < 0 ) return ( NULL ); /* error, no such family */
! 3165: else if ( fonts[ifont].family == family ) break; /* found font family */
! 3166: /* --- get local copy of table for this family by size --- */
! 3167: fontdef = fonts[ifont].fontdef; /* font by size */
! 3168: /* -------------------------------------------------------------------------
! 3169: get font in desired size, or closest available size, and return symbol
! 3170: -------------------------------------------------------------------------- */
! 3171: /* --- get font in desired size --- */
! 3172: while ( 1 ) /* find size or closest available */
! 3173: if ( fontdef[size] != NULL ) break; /* found available size */
! 3174: else /* adjust size closer to normal */
! 3175: if ( size == NORMALSIZE /* already normal so no more sizes,*/
! 3176: || sizeinc == 0 ) return ( NULL); /* or must be supersampling */
! 3177: else /*bump size 1 closer to NORMALSIZE*/
! 3178: size += sizeinc; /* see if adjusted size available */
! 3179: /* --- ptr to chardef struct --- */
! 3180: gfdata = &((fontdef[size])[charnum]); /*ptr to chardef for symbol in size*/
! 3181: /* -------------------------------------------------------------------------
! 3182: kludge to tweak CMEX10 (which appears to have incorrect descenders)
! 3183: -------------------------------------------------------------------------- */
! 3184: if ( family == CMEX10 ) /* cmex10 needs tweak */
! 3185: { int height = gfdata->toprow - gfdata->botrow + 1; /*total height of char*/
! 3186: gfdata->botrow = (isBig? (-height/3) : (-height/4));
! 3187: gfdata->toprow = gfdata->botrow + gfdata->image.height; }
! 3188: /* -------------------------------------------------------------------------
! 3189: return subraster containing chardef data for symbol in requested size
! 3190: -------------------------------------------------------------------------- */
! 3191: return ( gfdata ); /*ptr to chardef for symbol in size*/
! 3192: } /* --- end-of-function get_chardef() --- */
! 3193:
! 3194:
! 3195: /* ==========================================================================
! 3196: * Function: get_charsubraster ( symdef, size )
! 3197: * Purpose: returns new subraster ptr containing
! 3198: * data for symdef at given size
! 3199: * --------------------------------------------------------------------------
! 3200: * Arguments: symdef (I) mathchardef * corresponding to symbol
! 3201: * whose corresponding chardef is wanted
! 3202: * size (I) int containing 0-4 for desired size
! 3203: * --------------------------------------------------------------------------
! 3204: * Returns: ( subraster * ) pointer to struct defining symbol at size,
! 3205: * or NULL for any error
! 3206: * --------------------------------------------------------------------------
! 3207: * Notes: o just wraps a subraster envelope around get_chardef()
! 3208: * ======================================================================= */
! 3209: /* --- entry point --- */
! 3210: subraster *get_charsubraster ( mathchardef *symdef, int size )
! 3211: {
! 3212: /* -------------------------------------------------------------------------
! 3213: Allocations and Declarations
! 3214: -------------------------------------------------------------------------- */
! 3215: chardef *get_chardef(), *gfdata=NULL; /* chardef struct for symdef,size */
! 3216: int get_baseline(); /* baseline of gfdata */
! 3217: subraster *new_subraster(), *sp=NULL; /* subraster containing gfdata */
! 3218: int aasupsamp(), /*antialias char with supersampling*/
! 3219: grayscale=256; /* aasupersamp() parameters */
! 3220: /* -------------------------------------------------------------------------
! 3221: look up chardef for symdef at size, and embed data (gfdata) in subraster
! 3222: -------------------------------------------------------------------------- */
! 3223: if ( (gfdata=get_chardef(symdef,size)) /* look up chardef for symdef,size */
! 3224: != NULL ) /* and check that we found it */
! 3225: if ( (sp=new_subraster(0,0,0)) /* allocate subraster "envelope" */
! 3226: != NULL ) /* and check that we succeeded */
! 3227: {
! 3228: sp->type = CHARASTER; /* static character raster */
! 3229: sp->symdef = symdef; /* replace NULL with caller's arg */
! 3230: sp->size = size; /*replace default with caller's size*/
! 3231: sp->baseline = get_baseline(gfdata); /* get baseline of character */
! 3232: sp->image = &(gfdata->image); /* store ptr to its bitmap */
! 3233: if ( issupersampling ) /* antialias character right here */
! 3234: {
! 3235: raster *aa = NULL; /* antialiased char raster */
! 3236: int status = aasupsamp(sp->image,&aa,shrinkfactor,grayscale);
! 3237: if ( status ) /* supersampled successfully */
! 3238: { int baseline = sp->baseline; /* baseline before supersampling */
! 3239: int height = gfdata->image.height; /* #rows before supersampling */
! 3240: sp->image = aa; /* replace chardef with ss image */
! 3241: if ( baseline >= height-1 ) /* baseline at bottom of char */
! 3242: sp->baseline = aa->height -1; /* so keep it at bottom */
! 3243: else /* char has descenders */
! 3244: sp->baseline /= shrinkfactor; /* rescale baseline */
! 3245: sp->type = IMAGERASTER; } /* character is an image raster */
! 3246: } /* --- end-of-if(issupersampling) --- */
! 3247: } /* --- end-of-if(sp!=NULL) --- */
! 3248: if ( msgfp!=NULL && msglevel>=999 )
! 3249: { fprintf(msgfp,"get_charsubraster> requested symbol=\"%s\" baseline=%d\n",
! 3250: symdef->symbol, (sp==NULL?0:sp->baseline)); fflush(msgfp); }
! 3251: return ( sp ); /* back to caller */
! 3252: } /* --- end-of-function get_charsubraster() --- */
! 3253:
! 3254:
! 3255: /* ==========================================================================
! 3256: * Function: get_baseline ( gfdata )
! 3257: * Purpose: returns baseline for a chardef struct
! 3258: * --------------------------------------------------------------------------
! 3259: * Arguments: gfdata (I) chardef * containing chardef for symbol
! 3260: * whose baseline is wanted
! 3261: * --------------------------------------------------------------------------
! 3262: * Returns: ( int ) baseline for symdef,
! 3263: * or -1 for any error
! 3264: * --------------------------------------------------------------------------
! 3265: * Notes: o Unlike TeX, the top-left corners of our rasters are (0,0),
! 3266: * with (row,col) increasing as you move down and right.
! 3267: * Baselines are calculated with respect to this scheme,
! 3268: * so 0 would mean the very top row is on the baseline
! 3269: * and everything else descends below the baseline.
! 3270: * ======================================================================= */
! 3271: /* --- entry point --- */
! 3272: int get_baseline ( chardef *gfdata )
! 3273: {
! 3274: /* -------------------------------------------------------------------------
! 3275: Allocations and Declarations
! 3276: -------------------------------------------------------------------------- */
! 3277: int /*toprow = gfdata->toprow,*/ /*TeX top row from .gf file info*/
! 3278: botrow = gfdata->botrow, /*TeX bottom row from .gf file info*/
! 3279: height = gfdata->image.height; /* #rows comprising symbol */
! 3280: /* -------------------------------------------------------------------------
! 3281: give caller baseline
! 3282: -------------------------------------------------------------------------- */
! 3283: return ( (height-1) + botrow ); /* note: descenders have botrow<0 */
! 3284: } /* --- end-of-function get_baseline() --- */
! 3285:
! 3286:
! 3287: /* ==========================================================================
! 3288: * Function: get_delim ( char *symbol, int height, int family )
! 3289: * Purpose: returns subraster corresponding to the samllest
! 3290: * character containing symbol, but at least as large as height,
! 3291: * and in caller's family (if specified).
! 3292: * If no symbol character as large as height is available,
! 3293: * then the largest availabale character is returned instead.
! 3294: * --------------------------------------------------------------------------
! 3295: * Arguments: symbol (I) char * containing (substring of) desired
! 3296: * symbol, e.g., if symbol="(", then any
! 3297: * mathchardef like "(" or "\\(", etc, match.
! 3298: * height (I) int containing minimum acceptable height
! 3299: * for returned character
! 3300: * family (I) int containing -1 to consider all families,
! 3301: * or, e.g., CMEX10 for only that family
! 3302: * --------------------------------------------------------------------------
! 3303: * Returns: ( subraster * ) best matching character available,
! 3304: * or NULL for any error
! 3305: * --------------------------------------------------------------------------
! 3306: * Notes: o If height is passed as negative, its absolute value is used
! 3307: * but the best-fit width is searched for (rather than height)
! 3308: * ======================================================================= */
! 3309: /* --- entry point --- */
! 3310: subraster *get_delim ( char *symbol, int height, int family )
! 3311: {
! 3312: /* -------------------------------------------------------------------------
! 3313: Allocations and Declarations
! 3314: -------------------------------------------------------------------------- */
! 3315: mathchardef *symdefs = symtable; /* table of mathchardefs */
! 3316: subraster *get_charsubraster(), *sp=(subraster *)NULL; /* best match char */
! 3317: subraster *make_delim(); /* construct delim if can't find it*/
! 3318: chardef *get_chardef(), *gfdata=NULL; /* get chardef struct for a symdef */
! 3319: char lcsymbol[256], *symptr, /* lowercase symbol for comparison */
! 3320: *unescsymbol = symbol; /* unescaped symbol */
! 3321: int symlen = (symbol==NULL?0:strlen(symbol)), /* #chars in caller's sym*/
! 3322: deflen = 0; /* length of symdef (aka lcsymbol) */
! 3323: int idef = 0, /* symdefs[] index */
! 3324: bestdef = (-9999), /* index of best fit symdef */
! 3325: bigdef = (-9999); /*index of biggest (in case no best)*/
! 3326: int size = 0, /* size index 0...LARGESTSIZE */
! 3327: bestsize = (-9999), /* index of best fit size */
! 3328: bigsize = (-9999); /*index of biggest (in case no best)*/
! 3329: int defheight, bestheight=9999, /* height of best fit symdef */
! 3330: bigheight = (-9999); /*height of biggest(in case no best)*/
! 3331: int iswidth = 0; /* true if best-fit width desired */
! 3332: int isunesc = 0, /* true if leading escape removed */
! 3333: issq=0, isoint=0; /* true for \sqcup,etc, \oint,etc */
! 3334: char *bigint="bigint", *bigoint="bigoint"; /* substitutes for int, oint */
! 3335: /* -------------------------------------------------------------------------
! 3336: determine if searching height or width, and search symdefs[] for best-fit
! 3337: -------------------------------------------------------------------------- */
! 3338: /* --- arg checks --- */
! 3339: if ( symlen < 1 ) return (sp); /* no input symbol suplied */
! 3340: if ( strcmp(symbol,"e") == 0 ) return(sp); /* e causes segfault??? */
! 3341: /* --- ignore leading escapes for CMEX10 --- */
! 3342: if ( 1 ) /* ignore leading escape */
! 3343: if ( (family==CMEX10 || family==CMSYEX) ) { /* for CMEX10 or CMSYEX */
! 3344: if ( strstr(symbol,"sq") != NULL ) /* \sq symbol requested */
! 3345: issq = 1; /* seq \sq signal */
! 3346: if ( strstr(symbol,"oint") != NULL ) /* \oint symbol requested */
! 3347: isoint = 1; /* seq \oint signal */
! 3348: if ( *symbol=='\\' ) /* have leading \ */
! 3349: { unescsymbol = symbol+1; /* push past leading \ */
! 3350: if ( --symlen < 1 ) return(sp); /* one less char */
! 3351: if ( strcmp(unescsymbol,"int") == 0 ) /* \int requested by caller */
! 3352: unescsymbol = bigint; /* but big version looks better */
! 3353: if ( strcmp(unescsymbol,"oint") == 0 ) /* \oint requested by caller */
! 3354: unescsymbol = bigoint; /* but big version looks better */
! 3355: symlen = strlen(unescsymbol); /* explicitly recalculate length */
! 3356: isunesc = 1; } /* signal leading escape removed */
! 3357: } /* --- end-of-if(family) --- */
! 3358: /* --- determine whether searching for best-fit height or width --- */
! 3359: if ( height < 0 ) /* negative signals width search */
! 3360: { height = (-height); /* flip "height" positive */
! 3361: iswidth = 1; } /* set flag for width search */
! 3362: /* --- search symdefs[] for best-fit height (or width) --- */
! 3363: for ( idef=0; ;idef++ ) /* until trailer record found */
! 3364: {
! 3365: char *defsym = symdefs[idef].symbol; /* local copies */
! 3366: int deffam = symdefs[idef].family;
! 3367: if ( defsym == NULL ) break; /* reached end-of-table */
! 3368: else /* check against caller's symbol */
! 3369: if ( family<0 || deffam == family /* if explicitly in caller's family*/
! 3370: || (family==CMSYEX && (deffam==CMSY10||deffam==CMEX10)) )
! 3371: {
! 3372: strcpy(lcsymbol,defsym); /* local copy of symdefs[] symbol */
! 3373: if ( isunesc && *lcsymbol=='\\' ) /* ignored leading \ in symbol */
! 3374: strcpy(lcsymbol,lcsymbol+1); /* so squeeze it out of lcsymbol too*/
! 3375: if ( 0 ) /* don't ignore case */
! 3376: for ( symptr=lcsymbol; *symptr!='\000'; symptr++ ) /*for each symbol ch*/
! 3377: if ( isalpha(*symptr) ) *symptr=tolower(*symptr); /*lowercase the char*/
! 3378: deflen = strlen(lcsymbol); /* #chars in symbol we're checking */
! 3379: if ((symptr=strstr(lcsymbol,unescsymbol)) != NULL) /*found caller's sym*/
! 3380: if ( (isoint || strstr(lcsymbol,"oint")==NULL) /* skip unwanted "oint"*/
! 3381: && (issq || strstr(lcsymbol,"sq")==NULL) ) /* skip unwanted "sq" */
! 3382: if ( (deffam == CMSY10 ? /* CMSY10 or not CMSY10 */
! 3383: symptr == lcsymbol /* caller's sym is a prefix */
! 3384: && deflen == symlen: /* and same length */
! 3385: symptr == lcsymbol /* caller's sym is a prefix */
! 3386: || symptr == lcsymbol+deflen-symlen) ) /* or a suffix */
! 3387: for ( size=0; size<=LARGESTSIZE; size++ ) /* check all font sizes */
! 3388: if ( (gfdata=get_chardef(&(symdefs[idef]),size)) != NULL ) /*got one*/
! 3389: { defheight = gfdata->image.height; /* height of this character */
! 3390: if ( iswidth ) /* width search wanted instead... */
! 3391: defheight = gfdata->image.width; /* ...so substitute width */
! 3392: leftsymdef = &(symdefs[idef]); /* set symbol class, etc */
! 3393: if ( defheight>=height && defheight<bestheight ) /*new best fit*/
! 3394: { bestdef=idef; bestsize=size; /* save indexes of best fit */
! 3395: bestheight = defheight; } /* and save new best height */
! 3396: if ( defheight >= bigheight ) /* new biggest character */
! 3397: { bigdef=idef; bigsize=size; /* save indexes of biggest */
! 3398: bigheight = defheight; } /* and save new big height */
! 3399: } /* --- end-of-if(gfdata!=NULL) --- */
! 3400: } /* --- end-of-if(family) --- */
! 3401: } /* --- end-of-for(idef) --- */
! 3402: /* -------------------------------------------------------------------------
! 3403: construct subraster for best fit character, and return it to caller
! 3404: -------------------------------------------------------------------------- */
! 3405: if ( bestdef >= 0 ) /* found a best fit for caller */
! 3406: sp = get_charsubraster(&(symdefs[bestdef]),bestsize); /* best subraster */
! 3407: if ( sp==NULL && height-bigheight>5 ) /* try to construct delim */
! 3408: sp = make_delim(symbol,(iswidth?-height:height)); /* try to build delim */
! 3409: if ( sp==NULL && bigdef>=0 ) /* just give biggest to caller */
! 3410: sp = get_charsubraster(&(symdefs[bigdef]),bigsize); /* biggest subraster */
! 3411: return ( sp );
! 3412: } /* --- end-of-function get_delim() --- */
! 3413:
! 3414:
! 3415: /* ==========================================================================
! 3416: * Function: make_delim ( char *symbol, int height )
! 3417: * Purpose: constructs subraster corresponding to symbol
! 3418: * exactly as large as height,
! 3419: * --------------------------------------------------------------------------
! 3420: * Arguments: symbol (I) char * containing, e.g., if symbol="("
! 3421: * for desired delimiter
! 3422: * height (I) int containing height
! 3423: * for returned character
! 3424: * --------------------------------------------------------------------------
! 3425: * Returns: ( subraster * ) constructed delimiter
! 3426: * or NULL for any error
! 3427: * --------------------------------------------------------------------------
! 3428: * Notes: o If height is passed as negative, its absolute value is used
! 3429: * and interpreted as width (rather than height)
! 3430: * ======================================================================= */
! 3431: /* --- entry point --- */
! 3432: subraster *make_delim ( char *symbol, int height )
! 3433: {
! 3434: /* -------------------------------------------------------------------------
! 3435: Allocations and Declarations
! 3436: -------------------------------------------------------------------------- */
! 3437: subraster *sp = (subraster *)NULL, /* subraster returned to caller */
! 3438: *new_subraster(); /* allocate subraster */
! 3439: raster *rasp = (raster *)NULL; /* sp->image */
! 3440: int isokay=0, delete_subraster(); /* set true if delimiter drawn ok */
! 3441: int pixsz = 1; /* pixels are one bit each */
! 3442: int thickness = 1; /* drawn lines are one pixel thick */
! 3443: int aspectratio = 8; /* default height/width for parens */
! 3444: int iswidth = 0, /*true if width specified by height*/
! 3445: width = height; /* #pixels width (e.g., of ellipse)*/
! 3446: char *lp=NULL, *rp=NULL, *strchr(), /* check symbol for left or right */
! 3447: *lp2=NULL, *rp2=NULL; /* synonym for lp,rp */
! 3448: int circle_raster(), /* ellipse for ()'s in sp->image */
! 3449: rule_rsater(), /* horizontal or vertical lines */
! 3450: line_raster(); /* line between two points */
! 3451: /* -------------------------------------------------------------------------
! 3452: initialization
! 3453: -------------------------------------------------------------------------- */
! 3454: /* --- determine whether constructing height or width --- */
! 3455: if ( height < 0 ) /* negative "height" signals width */
! 3456: { width = height = (-height); /* flip height positive */
! 3457: iswidth = 1; } /* set flag for width */
! 3458: if ( height < 3 ) goto end_of_job; /* too small, must be error */
! 3459: /* --- set default width (or height) accordingly --- */
! 3460: if ( iswidth ) height = (width+(aspectratio+1)/2)/aspectratio;
! 3461: else width = (height+(aspectratio+1)/2)/aspectratio;
! 3462: if ( strchr(symbol,'=') != NULL /* left or right || bracket wanted */
! 3463: || strstr(symbol,"\\|") != NULL ) /* same || in standard tex notation*/
! 3464: width = max2(width,5); /* need space between two |'s */
! 3465: if ( width < 2 ) width=2; /* set min width */
! 3466: if ( strchr(symbol,'(') != NULL /* if left ( */
! 3467: || strchr(symbol,')') != NULL ) /* or right ) paren wanted */
! 3468: width = (3*width)/2; /* adjust width */
! 3469: /* --- allocate and initialize subraster for constructed delimiter --- */
! 3470: if ( (sp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 3471: == NULL ) goto end_of_job; /* quit if failed */
! 3472: /* --- initialize delimiter subraster parameters --- */
! 3473: sp->type = IMAGERASTER; /* image */
! 3474: sp->symdef = NULL; /* not applicable for image */
! 3475: sp->baseline = height/2 + 2; /* is a little above center good? */
! 3476: sp->size = NORMALSIZE; /* size (probably unneeded) */
! 3477: rasp = sp->image; /* pointer to image in subraster */
! 3478: /* -------------------------------------------------------------------------
! 3479: ( ) parens
! 3480: -------------------------------------------------------------------------- */
! 3481: if ( (lp=strchr(symbol,'(')) != NULL /* left ( paren wanted */
! 3482: || (rp=strchr(symbol,')')) != NULL ) /* right ) paren wanted */
! 3483: {
! 3484: int mywidth = min2(width,20); /* max width for ()'s */
! 3485: circle_raster ( rasp, /* embedded raster image */
! 3486: 0, 0, /* row0,col0 are upper-left corner */
! 3487: height-1, mywidth-1, /* row1,col1 are lower-right */
! 3488: thickness, /* line thickness is 1 pixel */
! 3489: (rp==NULL?"23":"41") ); /* "1234" quadrants to be drawn */
! 3490: isokay = 1; /* set flag */
! 3491: } /* --- end-of-if(left- or right-() paren wanted) --- */
! 3492: /* -------------------------------------------------------------------------
! 3493: [ ] brackets
! 3494: -------------------------------------------------------------------------- */
! 3495: else
! 3496: if ( (lp=strchr(symbol,'[')) != NULL /* left [ bracket wanted */
! 3497: || (rp=strchr(symbol,']')) != NULL ) /* right ] bracket wanted */
! 3498: {
! 3499: /* --- rule_raster ( rasp, top, left, width, height, type=0 ) --- */
! 3500: int mywidth = min2(width,12); /* max width for horizontal bars */
! 3501: thickness = 1; /* set lines 1 or 2 pixels thick */
! 3502: rule_raster(rasp, 0,0, mywidth,thickness, 0); /* top horizontal bar */
! 3503: rule_raster(rasp, height-thickness,0, mywidth,thickness, 0); /* bottom */
! 3504: if ( lp != NULL ) /* left [ bracket wanted */
! 3505: rule_raster(rasp, 0,0, thickness,height, 0); /* left vertical bar */
! 3506: if ( rp != NULL ) /* right ] bracket wanted */
! 3507: rule_raster(rasp, 0,mywidth-thickness, thickness,height, 0); /* right */
! 3508: isokay = 1; /* set flag */
! 3509: } /* --- end-of-if(left- or right-[] bracket wanted) --- */
! 3510: /* -------------------------------------------------------------------------
! 3511: < > brackets
! 3512: -------------------------------------------------------------------------- */
! 3513: else
! 3514: if ( (lp=strchr(symbol,'<')) != NULL /* left < bracket wanted */
! 3515: || (rp=strchr(symbol,'>')) != NULL ) /* right > bracket wanted */
! 3516: {
! 3517: /* --- line_raster ( rasp, row0, col0, row1, col1, thickness ) --- */
! 3518: int mywidth = min2(width,12); /* max width for brackets */
! 3519: thickness = 1; /* set line pixel thickness */
! 3520: if ( lp != NULL ) /* left < bracket wanted */
! 3521: { line_raster(rasp,height/2,0,0,mywidth-1,thickness);
! 3522: line_raster(rasp,height/2,0,height-1,mywidth-1,thickness); }
! 3523: if ( rp != NULL ) /* right > bracket wanted */
! 3524: { line_raster(rasp,height/2,mywidth-1,0,0,thickness);
! 3525: line_raster(rasp,height/2,mywidth-1,height-1,0,thickness); }
! 3526: isokay = 1; /* set flag */
! 3527: } /* --- end-of-if(left- or right-<> bracket wanted) --- */
! 3528: /* -------------------------------------------------------------------------
! 3529: \- for | | brackets or \= for || || brackets
! 3530: -------------------------------------------------------------------------- */
! 3531: else
! 3532: if ( (lp=strchr(symbol,'-')) != NULL /* left or right | bracket wanted */
! 3533: || (lp2=strchr(symbol,'|')) != NULL /* synonym for | bracket */
! 3534: || (rp=strchr(symbol,'=')) != NULL /* left or right || bracket wanted */
! 3535: || (rp2=strstr(symbol,"\\|"))!= NULL ) /* || in standard tex notation */
! 3536: {
! 3537: /* --- rule_raster ( rasp, top, left, width, height, type=0 ) --- */
! 3538: int midcol = width/2; /* middle col, left of mid if even */
! 3539: if ( rp != NULL /* left or right || bracket wanted */
! 3540: || rp2 != NULL ) /* or || in standard tex notation */
! 3541: { thickness = 1; /* each | of || one pixel thick */
! 3542: rule_raster(rasp, 0,max2(0,midcol-2), thickness,height, 0); /* left */
! 3543: rule_raster(rasp, 0,min2(width,midcol+2), thickness,height, 0); }
! 3544: else /*nb, lp2 spuriously set if rp2 set*/
! 3545: if ( lp != NULL /* left or right | bracket wanted */
! 3546: || lp2 != NULL ) /* ditto for synomym */
! 3547: { thickness = 1; /* set | two pixels thick */
! 3548: rule_raster(rasp, 0,midcol, thickness,height, 0); } /*mid vertical bar*/
! 3549: isokay = 1; /* set flag */
! 3550: } /* --- end-of-if(left- or right-[] bracket wanted) --- */
! 3551: /* -------------------------------------------------------------------------
! 3552: back to caller
! 3553: -------------------------------------------------------------------------- */
! 3554: end_of_job:
! 3555: if ( !isokay ) /* don't have requested delimiter */
! 3556: { delete_subraster(sp); /* so free unneeded structure */
! 3557: sp = NULL; } /* and signal error to caller */
! 3558: return ( sp ); /*back to caller with delim or NULL*/
! 3559: } /* --- end-of-function make_delim() --- */
! 3560:
! 3561:
! 3562: /* ==========================================================================
! 3563: * Function: texchar ( expression, chartoken )
! 3564: * Purpose: scans expression, returning either its first character,
! 3565: * or the next \sequence if that first char is \,
! 3566: * and a pointer to the first expression char past that.
! 3567: * --------------------------------------------------------------------------
! 3568: * Arguments: expression (I) char * to first char of null-terminated
! 3569: * string containing valid LaTeX expression
! 3570: * to be scanned
! 3571: * chartoken (O) char * to null-terminated string returning
! 3572: * either the first (non-whitespace) character
! 3573: * of expression if that char isn't \, or else
! 3574: * the \ and everything following it up to
! 3575: * the next non-alphabetic character (but at
! 3576: * least one char following the \ even if
! 3577: * it's non-alpha)
! 3578: * --------------------------------------------------------------------------
! 3579: * Returns: ( char * ) ptr to the first char of expression
! 3580: * past returned chartoken,
! 3581: * or NULL for any parsing error.
! 3582: * --------------------------------------------------------------------------
! 3583: * Notes: o Does *not* skip leading whitespace, but simply
! 3584: * returns any whitespace character as the next character.
! 3585: * ======================================================================= */
! 3586: /* --- entry point --- */
! 3587: char *texchar ( char *expression, char *chartoken )
! 3588: {
! 3589: /* -------------------------------------------------------------------------
! 3590: Allocations and Declarations
! 3591: -------------------------------------------------------------------------- */
! 3592: int esclen = 0, /*length of escape sequence*/
! 3593: maxesclen = 128; /* max len of esc sequence */
! 3594: char *ptoken = chartoken; /* ptr into chartoken */
! 3595: int iprefix = 0; /* prefix index */
! 3596: static char *prefixes[] = /*e.g., \big followed by ( */
! 3597: { /* "\\left", "\\right", */
! 3598: "\\big", "\\Big", "\\bigg", "\\Bigg",
! 3599: "\\bigl", "\\Bigl", "\\biggl", "\\Biggl",
! 3600: "\\bigr", "\\Bigr", "\\biggr", "\\Biggr", NULL };
! 3601: /* -------------------------------------------------------------------------
! 3602: just return the next char if it's not \
! 3603: -------------------------------------------------------------------------- */
! 3604: /* --- error check for end-of-string --- */
! 3605: *ptoken = '\000'; /* init in case of error */
! 3606: if ( expression == NULL ) return(NULL); /* nothing to scan */
! 3607: if ( *expression == '\000' ) return(NULL); /* nothing to scan */
! 3608: /* --- always returning first character (either \ or some other char) --- */
! 3609: *ptoken++ = *expression++; /* here's first character */
! 3610: /* --- if first char isn't \, then just return it to caller --- */
! 3611: if ( !isthischar(*(expression-1),ESCAPE) ) /* not a \, so return char */
! 3612: { *ptoken = '\000'; /* add a null terminator */
! 3613: goto end_of_job; } /* ptr past returned char */
! 3614: if ( *expression == '\000' ) /* \ is very last char */
! 3615: { *chartoken = '\000'; /* flush bad trailing \ */
! 3616: return(NULL); } /* and signal end-of-job */
! 3617: /* -------------------------------------------------------------------------
! 3618: we have an escape sequence, so return all alpha chars following \
! 3619: -------------------------------------------------------------------------- */
! 3620: /* --- accumulate chars until first non-alpha char found --- */
! 3621: for ( ; isalpha(*expression); esclen++ ) /* till first non-alpha... */
! 3622: { if ( esclen < maxesclen-3 ) /* more room in chartoken */
! 3623: *ptoken++ = *expression; /*copy alpha char, bump ptr*/
! 3624: expression++; } /* bump expression ptr */
! 3625: /* --- if we have a prefix, append next texchar, e.g., \big( --- */
! 3626: *ptoken = '\000'; /* set null for compare */
! 3627: for ( iprefix=0; prefixes[iprefix] != NULL; iprefix++ ) /* run thru list */
! 3628: if ( strcmp(chartoken,prefixes[iprefix]) == 0 ) /* have an exact match */
! 3629: { char nextchar[256]; int nextlen=0; /* texchar after prefix */
! 3630: skipwhite(expression); /* skip space after prefix*/
! 3631: expression = texchar(expression,nextchar); /* get nextchar */
! 3632: if ( (nextlen = strlen(nextchar)) > 0 ) /* #chars in nextchar */
! 3633: { strcpy(ptoken,nextchar); /* append nextchar */
! 3634: ptoken += strlen(nextchar); /* point to null terminator*/
! 3635: esclen += strlen(nextchar); } /* and bump escape length */
! 3636: break; } /* stop checking prefixes */
! 3637: /* --- every \ must be followed by at least one char, e.g., \[ --- */
! 3638: if ( esclen < 1 ) /* \ followed by non-alpha */
! 3639: *ptoken++ = *expression++; /*copy non-alpha, bump ptrs*/
! 3640: else { /* normal alpha \sequence */
! 3641: /* --- respect spaces in text mode, except first space after \escape --- */
! 3642: if ( istext > 0 ) /* in \rm or \it text mode */
! 3643: if ( istext != 3 ) /* but not \mathbb */
! 3644: if ( isthischar(*expression,WHITEDELIM) ) /* delim follows \sequence */
! 3645: expression++; } /* so flush delim */
! 3646: *ptoken = '\000'; /* null-terminate token */
! 3647: /* --- back to caller --- */
! 3648: end_of_job:
! 3649: if ( msgfp!=NULL && msglevel>=999 )
! 3650: { fprintf(msgfp,"texchar> returning token = \"%s\"\n",chartoken);
! 3651: fflush(msgfp); }
! 3652: return ( expression ); /*ptr to 1st non-alpha char*/
! 3653: } /* --- end-of-function texchar() --- */
! 3654:
! 3655:
! 3656: /* ==========================================================================
! 3657: * Function: texsubexpr (expression,subexpr,maxsubsz,
! 3658: * left,right,isescape,isdelim)
! 3659: * Purpose: scans expression, returning everything between a balanced
! 3660: * left{...right} subexpression if the first non-whitespace
! 3661: * char of expression is an (escaped or unescaped) left{,
! 3662: * or just the next texchar() otherwise,
! 3663: * and a pointer to the first expression char past that.
! 3664: * --------------------------------------------------------------------------
! 3665: * Arguments: expression (I) char * to first char of null-terminated
! 3666: * string containing valid LaTeX expression
! 3667: * to be scanned
! 3668: * subexpr (O) char * to null-terminated string returning
! 3669: * either everything between a balanced {...}
! 3670: * subexpression if the first char is {,
! 3671: * or the next texchar() otherwise.
! 3672: * maxsubsz (I) int containing max #bytes returned
! 3673: * in subexpr buffer (0 means unlimited)
! 3674: * left (I) char * specifying allowable left delimiters
! 3675: * that begin subexpression, e.g., "{[(<"
! 3676: * right (I) char * specifying matching right delimiters
! 3677: * in the same order as left, e.g., "}])>"
! 3678: * isescape (I) int controlling whether escaped and/or
! 3679: * unescaped left,right are matched;
! 3680: * see isbrace() comments below for details.
! 3681: * isdelim (I) int containing true (non-zero) to return
! 3682: * the leading left and trailing right delims
! 3683: * (if any were found) along with subexpr,
! 3684: * or containing false=0 to return subexpr
! 3685: * without its delimiters
! 3686: * --------------------------------------------------------------------------
! 3687: * Returns: ( char * ) ptr to the first char of expression
! 3688: * past returned subexpr (see Notes),
! 3689: * or NULL for any parsing error.
! 3690: * --------------------------------------------------------------------------
! 3691: * Notes: o If subexpr is of the form left{...right},
! 3692: * the outer {}'s are returned as part of subexpr
! 3693: * if isdelim is true; if isdelim is false the {}'s aren't
! 3694: * returned. In either case the returned pointer is
! 3695: * *always* bumped past the closing right}, even if
! 3696: * that closing right} isn't returned in subexpr.
! 3697: * o If subexpr is not of the form left{...right},
! 3698: * the returned pointer is on the character immediately
! 3699: * following the last character returned in subexpr
! 3700: * o \. acts as LaTeX \right. and matches any \left(
! 3701: * And it also acts as a LaTeX \left. and matches any \right)
! 3702: * ======================================================================= */
! 3703: /* --- entry point --- */
! 3704: char *texsubexpr ( char *expression, char *subexpr, int maxsubsz,
! 3705: char *left, char *right, int isescape, int isdelim )
! 3706: {
! 3707: /* -------------------------------------------------------------------------
! 3708: Allocations and Declarations
! 3709: -------------------------------------------------------------------------- */
! 3710: char *texchar(); /*next char (or \sequence) from expression*/
! 3711: char *leftptr, leftdelim[32] = "(\000", /* left( found in expression */
! 3712: rightdelim[32] = ")\000"; /* and matching right) */
! 3713: char *origexpression=expression, *origsubexpr=subexpr; /*original inputs*/
! 3714: int gotescape = 0, /* true if leading char of expression is \ */
! 3715: prevescape = 0; /* while parsing, true if preceding char \ */
! 3716: int isbrace(); /* check for left,right braces */
! 3717: int isanyright = 1; /* true matches any right with left, (...] */
! 3718: int isleftdot = 0; /* true if left brace is a \. */
! 3719: int nestlevel = 1; /* current # of nested braces */
! 3720: int subsz=0 /*, maxsubsz=8192*/; /* #chars in returned subexpr[] buffer*/
! 3721: /* -------------------------------------------------------------------------
! 3722: skip leading whitespace and just return the next char if it's not {
! 3723: -------------------------------------------------------------------------- */
! 3724: /* --- skip leading whitespace and error check for end-of-string --- */
! 3725: *subexpr = '\000'; /* init in case of error */
! 3726: if ( expression == NULL ) return(NULL); /*can't dereference null ptr*/
! 3727: skipwhite(expression); /* leading whitespace gone */
! 3728: if ( *expression == '\000' ) return(NULL); /* nothing left to scan */
! 3729: /* --- set maxsubsz --- */
! 3730: if ( maxsubsz < 1 ) maxsubsz = 8192; /* input 0 means unlimited */
! 3731: /* --- check for escape --- */
! 3732: if ( isthischar(*expression,ESCAPE) ) /* expression is escaped */
! 3733: gotescape = 1; /* so set flag accordingly */
! 3734: /* --- if first char isn't left{ or script, just return it to caller --- */
! 3735: if ( !isbrace(expression,left,isescape) ) /* not a left{ */
! 3736: if ( !isthischar(*expression,SCRIPTS) ) /* and not a script */
! 3737: return ( texchar(expression,subexpr) ); /* next char to caller */
! 3738: else /* --- kludge for super/subscripts to accommodate texscripts() --- */
! 3739: { *subexpr++ = *expression; /* signal script */
! 3740: *subexpr = '\000'; /* null-terminate subexpr */
! 3741: return ( expression ); } /* leave script in stream */
! 3742: /* --- extract left and find matching right delimiter --- */
! 3743: *leftdelim = *(expression+gotescape); /* the left( in expression */
! 3744: if ( (gotescape && *leftdelim == '.') /* we have a left \. */
! 3745: || (gotescape && isanyright) ) /*or are matching any right*/
! 3746: { isleftdot = 1; /* so just set flag */
! 3747: *leftdelim = '\000'; } /* and reset leftdelim */
! 3748: else /* find matching \right */
! 3749: if ( (leftptr=strchr(left,*leftdelim)) != NULL ) /* ptr to that left( */
! 3750: *rightdelim = right[(int)(leftptr-left)]; /* get the matching right) */
! 3751: else /* can't happen -- pgm bug */
! 3752: return ( NULL ); /*just signal eoj to caller*/
! 3753: /* -------------------------------------------------------------------------
! 3754: accumulate chars between balanced {}'s, i.e., till nestlevel returns to 0
! 3755: -------------------------------------------------------------------------- */
! 3756: /* --- first initialize by bumping past left{ or \{ --- */
! 3757: if ( isdelim ) *subexpr++ = *expression++; /*caller wants { in subexpr*/
! 3758: else expression++; /* always bump past left{ */
! 3759: if ( gotescape ) /*need to bump another char*/
! 3760: if ( isdelim ) *subexpr++ = *expression++; /* caller wants char, too */
! 3761: else expression++; /* else just bump past it */
! 3762: /* --- set maximum size for numerical arguments --- */
! 3763: if ( 0 ) /* check turned on or off? */
! 3764: if ( !isescape && !isdelim ) /*looking for numerical arg*/
! 3765: maxsubsz = 96; /* set max arg size */
! 3766: /* --- search for matching right} --- */
! 3767: while ( 1 ) /*until balanced right} */
! 3768: {
! 3769: /* --- error check for end-of-string --- */
! 3770: if ( *expression == '\000' ) /* premature end-of-string */
! 3771: { if ( 0 && (!isescape && !isdelim) ) /*looking for numerical arg,*/
! 3772: { expression = origexpression; /* so end-of-string is error*/
! 3773: subexpr = origsubexpr; } /* so reset all ptrs */
! 3774: if ( isdelim ) /* generate fake right */
! 3775: if ( gotescape ) /* need escaped right */
! 3776: { *subexpr++ = '\\'; /* set escape char */
! 3777: *subexpr++ = '.'; } /* and fake \right. */
! 3778: else /* escape not wanted */
! 3779: *subexpr++ = *rightdelim; /* so fake actual right */
! 3780: *subexpr = '\000'; /* null-terminate subexpr */
! 3781: return ( expression ); } /* back with final token */
! 3782: /* --- check preceding char for escape --- */
! 3783: if ( isthischar(*(expression-1),ESCAPE) ) /* previous char was \ */
! 3784: prevescape = 1-prevescape; /* so flip escape flag */
! 3785: else prevescape = 0; /* or turn flag off */
! 3786: /* --- check for { and } (un/escaped as per leading left) --- */
! 3787: if ( gotescape == prevescape ) /* escaped iff leading is */
! 3788: { /* --- check for (closing) right delim and see if we're done --- */
! 3789: if ( isthischar(*expression,rightdelim) /* found a right} */
! 3790: || (isleftdot && isthischar(*expression,right)) /*\left. matches all*/
! 3791: || (prevescape && isthischar(*expression,".")) ) /*or found \right. */
! 3792: if ( --nestlevel < 1 ) /*\right balances 1st \left*/
! 3793: { if ( isdelim ) /*caller wants } in subexpr*/
! 3794: *subexpr++ = *expression; /* so end subexpr with } */
! 3795: else /*check for \ before right}*/
! 3796: if ( prevescape ) /* have unwanted \ */
! 3797: *(subexpr-1) = '\000'; /* so replace it with null */
! 3798: *subexpr = '\000'; /* null-terminate subexpr */
! 3799: return ( expression+1 ); } /* back with char after } */
! 3800: /* --- check for (another) left{ --- */
! 3801: if ( isthischar(*expression,leftdelim) /* found another left{ */
! 3802: || (isleftdot && isthischar(*expression,left)) ) /* any left{ */
! 3803: nestlevel++;
! 3804: } /* --- end-of-if(gotescape==prevescape) --- */
! 3805: /* --- not done, so copy char to subexpr and continue with next char --- */
! 3806: if ( ++subsz < maxsubsz-5 ) /* more room in subexpr */
! 3807: *subexpr++ = *expression; /* so copy char and bump ptr*/
! 3808: expression++; /* bump expression ptr */
! 3809: } /* --- end-of-while(1) --- */
! 3810: } /* --- end-of-function texsubexpr() --- */
! 3811:
! 3812:
! 3813: /* ==========================================================================
! 3814: * Function: texscripts ( expression, subscript, superscript, which )
! 3815: * Purpose: scans expression, returning subscript and/or superscript
! 3816: * if expression is of the form _x^y or ^{x}_{y},
! 3817: * or any (valid LaTeX) permutation of the above,
! 3818: * and a pointer to the first expression char past "scripts"
! 3819: * --------------------------------------------------------------------------
! 3820: * Arguments: expression (I) char * to first char of null-terminated
! 3821: * string containing valid LaTeX expression
! 3822: * to be scanned
! 3823: * subscript (O) char * to null-terminated string returning
! 3824: * subscript (without _), if found, or "\000"
! 3825: * superscript (O) char * to null-terminated string returning
! 3826: * superscript (without ^), if found, or "\000"
! 3827: * which (I) int containing 1 for subscript only,
! 3828: * 2 for superscript only, >=3 for either/both
! 3829: * --------------------------------------------------------------------------
! 3830: * Returns: ( char * ) ptr to the first char of expression
! 3831: * past returned "scripts" (unchanged
! 3832: * except for skipped whitespace if
! 3833: * neither subscript nor superscript found),
! 3834: * or NULL for any parsing error.
! 3835: * --------------------------------------------------------------------------
! 3836: * Notes: o an input expression like ^a^b_c will return superscript="b",
! 3837: * i.e., totally ignoring all but the last "script" encountered
! 3838: * ======================================================================= */
! 3839: /* --- entry point --- */
! 3840: char *texscripts ( char *expression, char *subscript,
! 3841: char *superscript, int which )
! 3842: {
! 3843: /* -------------------------------------------------------------------------
! 3844: Allocations and Declarations
! 3845: -------------------------------------------------------------------------- */
! 3846: char *texsubexpr(); /* next subexpression from expression */
! 3847: int gotsub=0, gotsup=0; /* check that we don't eat, e.g., x_1_2 */
! 3848: /* -------------------------------------------------------------------------
! 3849: init "scripts" and skip leading whitespace
! 3850: -------------------------------------------------------------------------- */
! 3851: /* --- skip leading whitespace and check for end-of-string --- */
! 3852: *subscript = *superscript = '\000'; /* init in case no scripts */
! 3853: skipwhite(expression); /* leading whitespace gone */
! 3854: if ( *expression == '\000' ) return(expression); /* nothing left to scan */
! 3855: /* -------------------------------------------------------------------------
! 3856: get subscript and/or superscript from expression
! 3857: -------------------------------------------------------------------------- */
! 3858: while ( expression != NULL )
! 3859: if ( isthischar(*expression,SUBSCRIPT) /* found _ */
! 3860: && (which==1 || which>2 ) ) /* and caller wants it */
! 3861: { if ( gotsub /* found 2nd subscript */
! 3862: || subscript == NULL ) break; /* or no subscript buffer */
! 3863: gotsub = 1; /* set subscript flag */
! 3864: expression = texsubexpr(expression+1,subscript,0,"{","}",0,0); }
! 3865: else /* no _, check for ^ */
! 3866: if ( isthischar(*expression,SUPERSCRIPT) /* found ^ */
! 3867: && which>=2 ) /* and caller wants it */
! 3868: { if ( gotsup /* found 2nd superscript */
! 3869: || superscript == NULL ) break; /* or no superscript buffer*/
! 3870: gotsup = 1; /* set superscript flag */
! 3871: expression = texsubexpr(expression+1,superscript,0,"{","}",0,0); }
! 3872: else /* neither _ nor ^ */
! 3873: return ( expression ); /*return ptr past "scripts"*/
! 3874: return ( expression );
! 3875: } /* --- end-of-function texscripts() --- */
! 3876:
! 3877:
! 3878: /* ==========================================================================
! 3879: * Function: isbrace ( expression, braces, isescape )
! 3880: * Purpose: checks leading char(s) of expression for a brace,
! 3881: * either escaped or unescaped depending on isescape,
! 3882: * except that { and } are always matched, if they're
! 3883: * in braces, regardless of isescape.
! 3884: * --------------------------------------------------------------------------
! 3885: * Arguments: expression (I) char * to first char of null-terminated
! 3886: * string containing a valid LaTeX expression
! 3887: * whose leading char(s) are checked for braces
! 3888: * that begin subexpression, e.g., "{[(<"
! 3889: * braces (I) char * specifying matching brace delimiters
! 3890: * to be checked for, e.g., "{[(<" or "}])>"
! 3891: * isescape (I) int containing 0 to match only unescaped
! 3892: * braces, e.g., (...) or {...}, etc,
! 3893: * or containing 1 to match only escaped
! 3894: * braces, e.g., \(...\) or \[...\], etc,
! 3895: * or containing 2 to match either.
! 3896: * But note: if {,} are in braces
! 3897: * then they're *always* matched whether
! 3898: * escaped or not, regardless of isescape.
! 3899: * --------------------------------------------------------------------------
! 3900: * Returns: ( int ) 1 if the leading char(s) of expression
! 3901: * is a brace, or 0 if not.
! 3902: * --------------------------------------------------------------------------
! 3903: * Notes: o
! 3904: * ======================================================================= */
! 3905: /* --- entry point --- */
! 3906: int isbrace ( char *expression, char *braces, int isescape )
! 3907: {
! 3908: /* -------------------------------------------------------------------------
! 3909: Allocations and Declarations
! 3910: -------------------------------------------------------------------------- */
! 3911: int gotescape = 0, /* true if leading char is an escape */
! 3912: gotbrace = 0; /*true if first non-escape char is a brace*/
! 3913: /* -------------------------------------------------------------------------
! 3914: check for brace
! 3915: -------------------------------------------------------------------------- */
! 3916: /* --- first check for end-of-string --- */
! 3917: if ( *expression == '\000' ) return(0); /* nothing to check */
! 3918: /* --- check leading char for escape --- */
! 3919: if ( isthischar(*expression,ESCAPE) ) /* expression is escaped */
! 3920: { gotescape = 1; /* so set flag accordingly */
! 3921: expression++; } /* and bump past escape */
! 3922: /* --- check (maybe next char) for brace --- */
! 3923: if ( isthischar(*expression,braces) ) /* expression is braced */
! 3924: gotbrace = 1; /* so set flag accordingly */
! 3925: if ( gotescape && *expression == '.' ) /* \. matches any brace */
! 3926: gotbrace = 1; /* set flag */
! 3927: /* --- check for TeX brace { or } --- */
! 3928: if ( gotbrace && isthischar(*expression,"{}") ) /*expression has TeX brace*/
! 3929: if ( isescape ) isescape = 2; /* reset escape flag */
! 3930: /* -------------------------------------------------------------------------
! 3931: back to caller
! 3932: -------------------------------------------------------------------------- */
! 3933: if ( gotbrace && /* found a brace */
! 3934: ( isescape==2 || /* escape irrelevant */
! 3935: gotescape==isescape ) /* un/escaped as requested */
! 3936: ) return ( 1 ); return ( 0 ); /* return 1,0 accordingly */
! 3937: } /* --- end-of-function isbrace() --- */
! 3938:
! 3939:
! 3940: /* ==========================================================================
! 3941: * Function: preamble ( expression, size, subexpr )
! 3942: * Purpose: parses $-terminated preamble, if present, at beginning
! 3943: * of expression, re-setting size if necessary, and
! 3944: * returning any other parameters besides size in subexpr.
! 3945: * --------------------------------------------------------------------------
! 3946: * Arguments: expression (I) char * to first char of null-terminated
! 3947: * string containing LaTeX expression possibly
! 3948: * preceded by $-terminated preamble
! 3949: * size (I/O) int * containing 0-4 default font size,
! 3950: * and returning size modified by first
! 3951: * preamble parameter (or unchanged)
! 3952: * subexpr(O) char * returning any remaining preamble
! 3953: * parameters past size
! 3954: * --------------------------------------------------------------------------
! 3955: * Returns: ( char * ) ptr to first char past preamble in expression
! 3956: * or NULL for any parsing error.
! 3957: * --------------------------------------------------------------------------
! 3958: * Notes: o size can be any number >=0. If preceded by + or -, it's
! 3959: * interpreted as an increment to input size; otherwise
! 3960: * it's interpreted as the size.
! 3961: * o if subexpr is passed as NULL ptr, then returned expression
! 3962: * ptr will have "flushed" and preamble parameters after size
! 3963: * ======================================================================= */
! 3964: /* --- entry point --- */
! 3965: char *preamble ( char *expression, int *size, char *subexpr )
! 3966: {
! 3967: /* -------------------------------------------------------------------------
! 3968: Allocations and Declarations
! 3969: -------------------------------------------------------------------------- */
! 3970: char pretext[512], *prep=expression, /*pream from expression, ptr into it*/
! 3971: *dollar, *comma; /* preamble delimiters */
! 3972: int prelen = 0, /* preamble length */
! 3973: sizevalue = 0, /* value of size parameter */
! 3974: isfontsize = 0, /*true if leading fontsize present*/
! 3975: isdelta = 0; /*true to increment passed size arg*/
! 3976: /* -------------------------------------------------------------------------
! 3977: initialization
! 3978: -------------------------------------------------------------------------- */
! 3979: if ( subexpr != NULL ) /* caller passed us an address */
! 3980: *subexpr = '\000'; /* so init assuming no preamble */
! 3981: if ( expression == NULL ) goto end_of_job; /* no input */
! 3982: if ( *expression == '\000' ) goto end_of_job; /* input is an empty string */
! 3983: /* -------------------------------------------------------------------------
! 3984: process preamble if present
! 3985: -------------------------------------------------------------------------- */
! 3986: /*process_preamble:*/
! 3987: if ( (dollar=strchr(expression,'$')) /* $ signals preceding preamble */
! 3988: != NULL ) /* found embedded $ */
! 3989: if ( (prelen = (int)(dollar-expression)) /*#chars in expression preceding $*/
! 3990: > 0 ) { /* must have preamble preceding $ */
! 3991: if ( prelen < 65 ) { /* too long for a prefix */
! 3992: memcpy(pretext,expression,prelen); /* local copy of preamble */
! 3993: pretext[prelen] = '\000'; /* null-terminated */
! 3994: if ( strchr(pretext,*(ESCAPE))==NULL /*shouldn't be an escape in preamble*/
! 3995: && strchr(pretext,'{') == NULL ) { /*shouldn't be a left{ in preamble*/
! 3996: /* --- skip any leading whitespace --- */
! 3997: prep = pretext; /* start at beginning of preamble */
! 3998: skipwhite(prep); /* skip any leading white space */
! 3999: /* --- check for embedded , or leading +/- (either signalling size) --- */
! 4000: if ( isthischar(*prep,"+-") ) /* have leading + or - */
! 4001: isdelta = 1; /* so use size value as increment */
! 4002: comma = strchr(pretext,','); /* , signals leading size param */
! 4003: /* --- process leading size parameter if present --- */
! 4004: if ( comma != NULL /* size param explicitly signalled */
! 4005: || isdelta || isdigit(*prep) ) { /* or inferred implicitly */
! 4006: /* --- parse size parameter and reset size accordingly --- */
! 4007: if( comma != NULL ) *comma = '\000';/*, becomes null, terminating size*/
! 4008: sizevalue = atoi(prep); /* convert size string to integer */
! 4009: if ( size != NULL ) /* caller passed address for size */
! 4010: *size = (isdelta? *size+sizevalue : sizevalue); /* so reset size */
! 4011: /* --- finally, set flag and shift size parameter out of preamble --- */
! 4012: isfontsize = 1; /*set flag showing font size present*/
! 4013: if ( comma != NULL ) strcpy(pretext,comma+1);/*leading size param gone*/
! 4014: } /* --- end-of-if(comma!=NULL||etc) --- */
! 4015: /* --- copy any preamble params following size to caller's subexpr --- */
! 4016: if ( comma != NULL || !isfontsize ) /*preamb contains params past size*/
! 4017: if ( subexpr != NULL ) /* caller passed us an address */
! 4018: strcpy(subexpr,pretext); /*so return extra params to caller*/
! 4019: /* --- finally, set prep to shift preamble out of expression --- */
! 4020: prep = expression + prelen+1; /* set prep past $ in expression */
! 4021: } /* --- end-of-if(strchr(pretext,*ESCAPE)==NULL) --- */
! 4022: } /* --- end-of-if(prelen<65) --- */
! 4023: } /* --- end-of-if(prelen>0) --- */
! 4024: else { /* $ is first char of expression */
! 4025: int ndollars = 0; /* number of $...$ pairs removed */
! 4026: prep = expression; /* start at beginning of expression*/
! 4027: while ( *prep == '$' ) { /* remove all matching $...$'s */
! 4028: int explen = strlen(prep)-1; /* index of last char in expression*/
! 4029: if ( explen < 2 ) break; /* no $...$'s left to remove */
! 4030: if ( prep[explen] != '$' ) break; /* unmatched $ */
! 4031: prep[explen] = '\000'; /* remove trailing $ */
! 4032: prep++; /* and remove matching leading $ */
! 4033: ndollars++; /* count another pair removed */
! 4034: } /* --- end-of-while(*prep=='$') --- */
! 4035: ispreambledollars = ndollars; /* set flag to fix \displaystyle */
! 4036: if ( ndollars == 1 ) /* user submitted $...$ expression */
! 4037: isdisplaystyle = 0; /* so set \textstyle */
! 4038: if ( ndollars > 1 ) /* user submitted $$...$$ */
! 4039: isdisplaystyle = 2; /* so set \displaystyle */
! 4040: /*goto process_preamble;*/ /*check for preamble after leading $*/
! 4041: } /* --- end-of-if/else(prelen>0) --- */
! 4042: /* -------------------------------------------------------------------------
! 4043: back to caller
! 4044: -------------------------------------------------------------------------- */
! 4045: end_of_job:
! 4046: return ( prep ); /*expression, or ptr past preamble*/
! 4047: } /* --- end-of-function preamble() --- */
! 4048:
! 4049:
! 4050: /* ==========================================================================
! 4051: * Function: mimeprep ( expression )
! 4052: * Purpose: preprocessor for mimeTeX input, e.g.,
! 4053: * (a) removes comments,
! 4054: * (b) converts \left( to \( and \right) to \),
! 4055: * (c) xlates &html; special chars to equivalent latex
! 4056: * Should only be called once (after unescape_url())
! 4057: * --------------------------------------------------------------------------
! 4058: * Arguments: expression (I/O) char * to first char of null-terminated
! 4059: * string containing mimeTeX/LaTeX expression,
! 4060: * and returning preprocessed string
! 4061: * --------------------------------------------------------------------------
! 4062: * Returns: ( char * ) ptr to input expression,
! 4063: * or NULL for any parsing error.
! 4064: * --------------------------------------------------------------------------
! 4065: * Notes: o
! 4066: * ======================================================================= */
! 4067: /* --- entry point --- */
! 4068: char *mimeprep ( char *expression )
! 4069: {
! 4070: /* -------------------------------------------------------------------------
! 4071: Allocations and Declarations
! 4072: -------------------------------------------------------------------------- */
! 4073: char *expptr=expression, /* ptr within expression */
! 4074: *tokptr=NULL, /*ptr to token found in expression*/
! 4075: *texsubexpr(), argval[8192]; /*parse for macro args after token*/
! 4076: char *strchange(); /* change leading chars of string */
! 4077: char *findbraces(); /*find left { and right } for \atop*/
! 4078: int idelim=0, /* left- or right-index */
! 4079: isymbol=0; /*symbols[],rightcomment[],etc index*/
! 4080: int xlateleft = 0; /* true to xlate \left and \right */
! 4081: /* ---
! 4082: * comments
! 4083: * -------- */
! 4084: char *leftptr=NULL; /* find leftcomment in expression */
! 4085: static char *leftcomment = "%%", /* open comment */
! 4086: *rightcomment[] = {"\n", "%%", NULL}; /* close comments */
! 4087: /* ---
! 4088: * special long (more than 1-char) \left and \right delimiters
! 4089: * ----------------------------------------------------------- */
! 4090: static char *leftfrom[] = /* xlate any \left suffix... */
! 4091: { "\\|", /* \left\| */
! 4092: "\\{", /* \left\{ */
! 4093: "\\langle", /* \left\langle */
! 4094: NULL } ; /* --- end-of-leftfrom[] --- */
! 4095: static char *leftto[] = /* ...to this instead */
! 4096: { "=", /* = */
! 4097: "{", /* { */
! 4098: "<", /* < */
! 4099: NULL } ; /* --- end-of-leftto[] --- */
! 4100: static char *rightfrom[] = /* xlate any \right suffix... */
! 4101: { "\\|", /* \right\| */
! 4102: "\\}", /* \right\} */
! 4103: "\\rangle", /* \right\rangle */
! 4104: NULL } ; /* --- end-of-rightfrom[] --- */
! 4105: static char *rightto[] = /* ...to this instead */
! 4106: { "=", /* = */
! 4107: "}", /* } */
! 4108: ">", /* > */
! 4109: NULL } ; /* --- end-of-rightto[] --- */
! 4110: /* ---
! 4111: * { \atop }-like commands
! 4112: * ----------------------- */
! 4113: char *atopsym=NULL; /* atopcommands[isymbol] */
! 4114: static char *atopcommands[] = /* list of {a+b\command c+d}'s */
! 4115: { "\\over", /* plain tex for \frac */
! 4116: "\\choose", /* binomial coefficient */
! 4117: #ifndef NOATOP /*noatop preserves old mimeTeX rule*/
! 4118: "\\atop",
! 4119: #endif
! 4120: NULL } ; /* --- end-of-atopcommands[] --- */
! 4121: static char *atopdelims[] = /* delims for atopcommands[] */
! 4122: { NULL, NULL, /* \\over has no delims */
! 4123: "\\left(", "\\right)", /* \\choose has ( ) delims*/
! 4124: #ifndef NOATOP /*noatop preserves old mimeTeX rule*/
! 4125: NULL, NULL, /* \\atop has no delims */
! 4126: #endif
! 4127: NULL, NULL } ; /* --- end-of-atopdelims[] --- */
! 4128: /* ---
! 4129: * html special/escape chars converted to latex equivalents
! 4130: * -------------------------------------------------------- */
! 4131: char *htmlsym=NULL; /* symbols[isymbol].html */
! 4132: static struct { char *html; char *args; char *latex; } symbols[] =
! 4133: { /* ---------------------------------------
! 4134: user-supplied newcommands
! 4135: --------------------------------------- */
! 4136: #ifdef NEWCOMMANDS /* -DNEWCOMMANDS=\"filename.h\" */
! 4137: #include NEWCOMMANDS
! 4138: #endif
! 4139: /* ------------------------------------------
! 4140: LaTeX Macro #args,default template...
! 4141: ------------------------------------------ */
! 4142: { "\\lvec", "2n", "{#2_1,\\cdots,#2_{#1}}" },
! 4143: { "\\overset", NULL, "\\stackrel" }, /* just an alias */
! 4144: { "\\underset", "2", "\\relstack{#2}{#1}" }, /* reverse args */
! 4145: /* ---------------------------------------
! 4146: html termchar LaTeX equivalent...
! 4147: --------------------------------------- */
! 4148: { """, ";", "\"" }, /* " is first, " */
! 4149: { "&", ";", "&" },
! 4150: { "<", ";", "<" },
! 4151: { ">", ";", ">" },
! 4152: { " ", ";", "~" },
! 4153: { "¡", ";", "{\\raisebox{-2}{\\rotatebox{180}{!}}}" },
! 4154: { "¦", ";", "|" },
! 4155: { "±", ";", "\\pm" },
! 4156: { "²", ";", "{{}^2}" },
! 4157: { "³", ";", "{{}^3}" },
! 4158: { "µ", ";", "\\mu" },
! 4159: { "¹", ";", "{{}^1}" },
! 4160: { "¼", ";", "{\\frac14}" },
! 4161: { "½", ";", "{\\frac12}" },
! 4162: { "¾", ";", "{\\frac34}" },
! 4163: { "¿", ";", "{\\raisebox{-2}{\\rotatebox{180}{?}}}" },
! 4164: { "Â", ";", "{\\rm~\\hat~A}" },
! 4165: { "Ã", ";", "{\\rm~\\tilde~A}" },
! 4166: { "Ä", ";", "{\\rm~\\ddot~A}" },
! 4167: { "Å", ";", "{\\rm~A\\limits^{-1$o}}" },
! 4168: { "ã", ";", "{\\rm~\\tilde~a}" },
! 4169: { "ÿ", ";", "{\\rm~\\ddot~y}" }, /* ÿ is last, ÿ */
! 4170: /* ---------------------------------------
! 4171: LaTeX termchar mimeTeX equivalent...
! 4172: --------------------------------------- */
! 4173: { "\\AA", NULL, "{\\rm~A\\limits^{-1$o}}" },
! 4174: { "\\aa", NULL, "{\\rm~a\\limits^{-1$o}}" },
! 4175: { "\\bmod", NULL, "{\\hspace2{\\rm~mod}\\hspace2}" },
! 4176: { "\\vdots", NULL, "{\\raisebox3{\\rotatebox{90}{\\ldots}}}" },
! 4177: { "\\cdots", NULL, "{\\raisebox3{\\ldots}}" },
! 4178: { "\\ldots", NULL, "{\\fs4.\\hspace1.\\hspace1.}" },
! 4179: { "\\ddots", NULL, "{\\fs4\\raisebox8.\\hspace1\\raisebox4.\\hspace1.}"},
! 4180: { "\\notin", NULL, "{\\not\\in}" },
! 4181: { "\\neq", NULL, "{\\not=}" },
! 4182: { "\\hbar", NULL, "{\\compose~h{{\\fs{-1}-\\atop\\vspace3}}}" },
! 4183: { "\\angle", NULL, "{\\compose{\\hspace{3}\\lt}{\\circle(10,15;-80,80)}}"},
! 4184: { "\\cr", NULL, "\\\\" },
! 4185: { "\\iint", NULL, "{\\int\\int}\\limits" },
! 4186: { "\\Bigiint", NULL, "{\\Bigint\\Bigint}\\limits" },
! 4187: { "!`", NULL, "{\\raisebox{-2}{\\rotatebox{180}{!}}}" },
! 4188: { "?`", NULL, "{\\raisebox{-2}{\\rotatebox{180}{?}}}" },
! 4189: { "\\rightleftharpoons",NULL,"{\\rightharpoonup\\atop\\leftharpoondown}" },
! 4190: { "\\LaTeX", NULL, "{\\rm~L\\raisebox{3}{\\fs{-1}A}\\TeX}" },
! 4191: { "\\TeX", NULL, "{\\rm~T\\raisebox{-3}{E}X}" },
! 4192: { "\\cyan", NULL, "{\\reverse\\red\\reversebg}" },
! 4193: { "\\magenta",NULL, "{\\reverse\\green\\reversebg}" },
! 4194: { "\\yellow",NULL, "{\\reverse\\blue\\reversebg}" },
! 4195: { "\\hhline",NULL, "\\Hline" },
! 4196: { "\\Hline", NULL, "\\hline\\,\\\\\\hline" },
! 4197: /* ---------------------------------------------------------
! 4198: "Algebra Syntax" termchar mimeTeX/LaTeX equivalent...
! 4199: ------------------------------------------------------------ */
! 4200: { "sqrt", "1", "{\\sqrt{#1}}" },
! 4201: { "sin", "1", "{\\sin{#1}}" },
! 4202: { "cos", "1", "{\\cos{#1}}" },
! 4203: { "asin", "1", "{\\sin^{-1}{#1}}" },
! 4204: { "acos", "1", "{\\cos^{-1}{#1}}" },
! 4205: { "exp", "1", "{e^{#1}}" },
! 4206: { "det", "1", "{\\left|{#1}\\right|}" },
! 4207: /* ---------------------------------------
! 4208: LaTeX Constant termchar value...
! 4209: --------------------------------------- */
! 4210: { "\\thinspace", NULL, "2" },
! 4211: { "\\thinmathspace", NULL, "2" },
! 4212: { "\\textwidth", NULL, "400" },
! 4213: { NULL, NULL, NULL }
! 4214: } ; /* --- end-of-symbols[] --- */
! 4215: /* -------------------------------------------------------------------------
! 4216: first remove comments
! 4217: -------------------------------------------------------------------------- */
! 4218: expptr = expression; /* start search at beginning */
! 4219: while ( (leftptr=strstr(expptr,leftcomment)) != NULL ) /*found leftcomment*/
! 4220: {
! 4221: char *rightsym=NULL; /* rightcomment[isymbol] */
! 4222: expptr = leftptr+strlen(leftcomment); /* start rightcomment search here */
! 4223: /* --- check for any closing rightcomment, in given precedent order --- */
! 4224: if ( *expptr != '\000' ) /*have chars after this leftcomment*/
! 4225: for(isymbol=0; (rightsym=rightcomment[isymbol]) != NULL; isymbol++)
! 4226: if ( (tokptr=strstr(expptr,rightsym)) != NULL ) /*found rightcomment*/
! 4227: { tokptr += strlen(rightsym); /* first char after rightcomment */
! 4228: if ( *tokptr == '\000' ) /*nothing after this rightcomment*/
! 4229: { *leftptr = '\000'; /*so terminate expr at leftcomment*/
! 4230: break; } /* and stop looking for comments */
! 4231: *leftptr = '~'; /* replace entire comment by ~ */
! 4232: strcpy(leftptr+1,tokptr); /* and squeeze out comment */
! 4233: goto next_comment; } /* stop looking for rightcomment */
! 4234: /* --- no rightcomment after opening leftcomment --- */
! 4235: *leftptr = '\000'; /* so terminate expression */
! 4236: /* --- resume search past squeezed-out comment --- */
! 4237: next_comment:
! 4238: if ( *leftptr == '\000' ) break; /* reached end of expression */
! 4239: expptr = leftptr+1; /*resume search after this comment*/
! 4240: } /* --- end-of-while(leftptr!=NULL) --- */
! 4241: /* -------------------------------------------------------------------------
! 4242: convert \left( to \( and \right) to \), etc.
! 4243: -------------------------------------------------------------------------- */
! 4244: if ( xlateleft ) /* \left...\right xlation wanted */
! 4245: for ( idelim=0; idelim<2; idelim++ ) /* 0 for \left and 1 for \right */
! 4246: {
! 4247: char *lrstr = (idelim==0?"\\left":"\\right"); /* \left on 1st pass */
! 4248: int lrlen = (idelim==0?5:6); /* strlen() of \left or \right */
! 4249: char *braces = (idelim==0?LEFTBRACES ".":RIGHTBRACES "."), /*([{<or)]}>*/
! 4250: **lrfrom= (idelim==0?leftfrom:rightfrom), /* long braces like \| */
! 4251: **lrto = (idelim==0?leftto:rightto), /* xlated to 1-char like = */
! 4252: *lrsym = NULL; /* lrfrom[isymbol] */
! 4253: expptr = expression; /* start search at beginning */
! 4254: while ( (tokptr=strstr(expptr,lrstr)) != NULL ) /* found \left or \right */
! 4255: {
! 4256: if ( isthischar(*(tokptr+lrlen),braces) ) /* followed by a 1-char brace*/
! 4257: { strcpy(tokptr+1,tokptr+lrlen); /* so squeeze out "left" or "right"*/
! 4258: expptr = tokptr+2; } /* and resume search past brace */
! 4259: else /* may be a "long" brace like \| */
! 4260: {
! 4261: expptr = tokptr+lrlen; /*init to resume search past\left\rt*/
! 4262: for(isymbol=0; (lrsym=lrfrom[isymbol]) != NULL; isymbol++)
! 4263: { int symlen = strlen(lrsym); /* #chars in delim, e.g., 2 for \| */
! 4264: if ( memcmp(tokptr+lrlen,lrsym,symlen) == 0 ) /* found long delim*/
! 4265: { strcpy(tokptr+1,tokptr+lrlen+symlen-1); /* squeeze out delim */
! 4266: *(tokptr+1) = *(lrto[isymbol]); /* last char now 1-char delim*/
! 4267: expptr = tokptr+2 - lrlen; /* resume search past 1-char delim*/
! 4268: break; } /* no need to check more lrsym's */
! 4269: } /* --- end-of-for(isymbol) --- */
! 4270: } /* --- end-of-if/else(isthischar()) --- */
! 4271: } /* --- end-of-while(tokptr!=NULL) --- */
! 4272: } /* --- end-of-for(idelim) --- */
! 4273: /* -------------------------------------------------------------------------
! 4274: run thru table, converting all occurrences of each macro to its expansion
! 4275: -------------------------------------------------------------------------- */
! 4276: for(isymbol=0; (htmlsym=symbols[isymbol].html) != NULL; isymbol++)
! 4277: {
! 4278: int htmllen = strlen(htmlsym); /* length of escape, _without_ ; */
! 4279: int isalgebra = isalpha((int)(*htmlsym)); /* leading char alphabetic */
! 4280: char *aleft="{([<|", *aright="})]>|"; /*left,right delims for alg syntax*/
! 4281: char *args = symbols[isymbol].args, /* number {}-args, optional []-arg */
! 4282: *htmlterm = args, /*if *args nonumeric, then html term*/
! 4283: *latexsym = symbols[isymbol].latex; /*latex replacement for htmlsym*/
! 4284: char abuff[8192]; int iarg,nargs=0; /* macro expansion params */
! 4285: if ( args != NULL ) /*we have args (or htmlterm) param*/
! 4286: if ( *args != '\000' ) /* and it's not an empty string */
! 4287: if ( strchr("0123456789",*args) != NULL ) /* is 1st char #args=0-9 ? */
! 4288: { htmlterm = NULL; /* if so, then we have no htmlterm */
! 4289: *abuff = *args; abuff[1] = '\000'; /* #args char in ascii buffer */
! 4290: nargs = atoi(abuff); } /* interpret #args to numeric */
! 4291: expptr = expression; /* re-start search at beginning */
! 4292: while ( (tokptr=strstr(expptr,htmlsym)) != NULL ) /* found another sym */
! 4293: { char termchar = *(tokptr+htmllen); /* char terminating html sequence */
! 4294: int escapelen = htmllen; /* total length of escape sequence */
! 4295: *abuff = '\000'; /* default to empty string */
! 4296: if ( latexsym != NULL ) /* table has .latex xlation */
! 4297: if ( *latexsym != '\000' ) /* and it's not an empty string */
! 4298: strcpy(abuff,latexsym); /* so get local copy */
! 4299: if ( htmlterm != NULL ) /* sequence may have terminator */
! 4300: escapelen += (isthischar(termchar,htmlterm)?1:0); /*add terminator*/
! 4301: if ( isalpha((int)termchar) ) /*we just have prefix of longer sym*/
! 4302: { expptr = tokptr+htmllen; /* just resume search after prefix */
! 4303: continue; } /* but don't replace it */
! 4304: if ( !isthischar(*htmlsym,ESCAPE) /* our symbol isn't escaped */
! 4305: && !isthischar(*htmlsym,"&") ) /* and not an &html; special char */
! 4306: if ( tokptr != expression ) /* then if we're past beginning */
! 4307: if ( isthischar(*(tokptr-1),ESCAPE) /*and if inline symbol escaped*/
! 4308: || (isalpha(*(tokptr-1))) ) /* or if suffix of longer string */
! 4309: { expptr = tokptr+escapelen; /*just resume search after literal*/
! 4310: continue; } /* but don't replace it */
! 4311: if ( nargs > 0 ) /*substitute #1,#2,... in latexsym*/
! 4312: {
! 4313: char *arg1ptr = tokptr+escapelen;/* nargs begin after macro literal */
! 4314: char *optarg = args+1; /* ptr 1 char past #args digit 0-9 */
! 4315: expptr = arg1ptr; /* ptr to beginning of next arg */
! 4316: for ( iarg=1; iarg<=nargs; iarg++ ) /* one #`iarg` arg at a time */
! 4317: {
! 4318: char argsignal[32] = "#1", /* #1...#9 signals arg replacement */
! 4319: *argsigptr = NULL; /* ptr to argsignal in abuff[] */
! 4320: /* --- get argument value --- */
! 4321: *argval = '\000'; /* init arg as empty string */
! 4322: skipwhite(expptr); /* and skip leading white space */
! 4323: if ( iarg==1 && *optarg!='\000' /* check for optional [arg] */
! 4324: && !isalgebra ) /* but not in "algebra syntax" */
! 4325: { strcpy(argval,optarg); /* init with default value */
! 4326: if ( *expptr == '[' ) /* but user gave us [argval] */
! 4327: expptr = texsubexpr(expptr,argval,0,"[","]",0,0); } /*so get it*/
! 4328: else /* not optional, so get {argval} */
! 4329: if ( *expptr != '\000' ) /* check that some argval provided */
! 4330: if ( !isalgebra ) /* only { } delims for latex macro */
! 4331: expptr = texsubexpr(expptr,argval,0,"{","}",0,0); /*get {argval}*/
! 4332: else /*any delim for algebra syntax macro*/
! 4333: { expptr = texsubexpr(expptr,argval,0,aleft,aright,0,1);
! 4334: if ( isthischar(*argval,aleft) ) /* have delim-enclosed arg */
! 4335: if ( *argval != '{' ) /* and it's not { }-enclosed */
! 4336: { strchange(0,argval,"\\left"); /* insert opening \left, */
! 4337: strchange(0,argval+strlen(argval)-1,"\\right"); } /*\right*/
! 4338: } /* --- end-of-if/else(!isalgebra) --- */
! 4339: /* --- replace #`iarg` in macro with argval --- */
! 4340: sprintf(argsignal,"#%d",iarg); /* #1...#9 signals argument */
! 4341: while ( (argsigptr=strstr(argval,argsignal)) != NULL ) /* #1...#9 */
! 4342: strcpy(argsigptr,argsigptr+strlen(argsignal)); /*can't be in argval*/
! 4343: while ( (argsigptr=strstr(abuff,argsignal)) != NULL ) /* #1...#9 */
! 4344: strchange(strlen(argsignal),argsigptr,argval); /*replaced by argval*/
! 4345: } /* --- end-of-for(iarg) --- */
! 4346: escapelen += ((int)(expptr-arg1ptr)); /* add in length of all args */
! 4347: } /* --- end-of-if(nargs>0) --- */
! 4348: strchange(escapelen,tokptr,abuff); /*replace macro or html symbol*/
! 4349: expptr = tokptr + strlen(abuff); /*resume search after macro / html*/
! 4350: } /* --- end-of-while(tokptr!=NULL) --- */
! 4351: } /* --- end-of-for(isymbol) --- */
! 4352: /* -------------------------------------------------------------------------
! 4353: run thru table, converting all {a+b\atop c+d} to \atop{a+b}{c+d}
! 4354: -------------------------------------------------------------------------- */
! 4355: for(isymbol=0; (atopsym=atopcommands[isymbol]) != NULL; isymbol++)
! 4356: {
! 4357: int atoplen = strlen(atopsym); /* #chars in \atop */
! 4358: expptr = expression; /* re-start search at beginning */
! 4359: while ( (tokptr=strstr(expptr,atopsym)) != NULL ) /* found another atop */
! 4360: { char *leftbrace=NULL, *rightbrace=NULL; /*ptr to opening {, closing }*/
! 4361: char termchar = *(tokptr+atoplen); /* \atop followed by terminator */
! 4362: if ( msgfp!=NULL && msglevel>=999 )
! 4363: { fprintf(msgfp,"mimeprep> offset=%d rhs=\"%s\"\n",
! 4364: (int)(tokptr-expression),tokptr);
! 4365: fflush(msgfp); }
! 4366: if ( isalpha((int)termchar) ) /*we just have prefix of longer sym*/
! 4367: { expptr = tokptr+atoplen; /* just resume search after prefix */
! 4368: continue; } /* but don't process it */
! 4369: leftbrace = findbraces(expression,tokptr); /* find left { */
! 4370: rightbrace = findbraces(NULL,tokptr+atoplen-1); /* find right } */
! 4371: if ( leftbrace==NULL || rightbrace==NULL )
! 4372: { expptr += atoplen; continue; } /* skip command if didn't find */
! 4373: else /* we have bracketed { \atop } */
! 4374: {
! 4375: int leftlen = (int)(tokptr-leftbrace) - 1, /* #chars in left arg */
! 4376: rightlen = (int)(rightbrace-tokptr) - atoplen, /* and in right*/
! 4377: totlen = (int)(rightbrace-leftbrace) + 1; /*tot in { \atop }*/
! 4378: char *open=atopdelims[2*isymbol], *close=atopdelims[2*isymbol+1];
! 4379: char arg[8192], command[8192]; /* left/right args, new \atop{}{} */
! 4380: *command = '\000'; /* start with null string */
! 4381: if (open!=NULL) strcat(command,open); /* add open delim if needed */
! 4382: strcat(command,atopsym); /* add command with \atop */
! 4383: arg[0] = '{'; /* arg starts with { */
! 4384: memcpy(arg+1,leftbrace+1,leftlen); /* extract left-hand arg */
! 4385: arg[leftlen+1] = '\000'; /* and null terminate it */
! 4386: strcat(command,arg); /* concatanate {left-arg to \atop */
! 4387: strcat(command,"}{"); /* close left-arg, open right-arg */
! 4388: memcpy(arg,tokptr+atoplen,rightlen); /* right-hand arg */
! 4389: arg[rightlen] = '}'; /* add closing } */
! 4390: arg[rightlen+1] = '\000'; /* and null terminate it */
! 4391: if ( isthischar(*arg,WHITEMATH) ) /* 1st char was mandatory space */
! 4392: strcpy(arg,arg+1); /* so squeeze it out */
! 4393: strcat(command,arg); /* concatanate right-arg} */
! 4394: if (close!=NULL) strcat(command,close); /* add close delim if needed*/
! 4395: strchange(totlen-2,leftbrace+1,command); /* {\atop} --> {\atop{}{}} */
! 4396: expptr = leftbrace+strlen(command); /*resume search past \atop{}{}*/
! 4397: }
! 4398: } /* --- end-of-while(tokptr!=NULL) --- */
! 4399: } /* --- end-of-for(isymbol) --- */
! 4400: /* -------------------------------------------------------------------------
! 4401: back to caller with preprocessed expression
! 4402: -------------------------------------------------------------------------- */
! 4403: if ( msgfp!=NULL && msglevel>=99 ) /* display preprocessed expression */
! 4404: { fprintf(msgfp,"mimeprep> expression=\"\"%s\"\"\n",expression);
! 4405: fflush(msgfp); }
! 4406: return ( expression );
! 4407: } /* --- end-of-function mimeprep() --- */
! 4408:
! 4409:
! 4410: /* ==========================================================================
! 4411: * Function: strchange ( int nfirst, char *from, char *to )
! 4412: * Purpose: Changes the nfirst leading chars of `from` to `to`.
! 4413: * For example, to change char x[99]="12345678" to "123ABC5678"
! 4414: * call strchange(1,x+3,"ABC")
! 4415: * --------------------------------------------------------------------------
! 4416: * Arguments: nfirst (I) int containing #leading chars of `from`
! 4417: * that will be replace by `to`
! 4418: * from (I/O) char * to null-terminated string whose nfirst
! 4419: * leading chars will be replaced by `to`
! 4420: * to (I) char * to null-terminated string that will
! 4421: * replace the nfirst leading chars of `from`
! 4422: * --------------------------------------------------------------------------
! 4423: * Returns: ( char * ) ptr to first char of input `from`
! 4424: * or NULL for any error.
! 4425: * --------------------------------------------------------------------------
! 4426: * Notes: o If strlen(to)>nfirst, from must have memory past its null
! 4427: * (i.e., we don't do a realloc)
! 4428: * ======================================================================= */
! 4429: /* --- entry point --- */
! 4430: char *strchange ( int nfirst, char *from, char *to )
! 4431: {
! 4432: /* -------------------------------------------------------------------------
! 4433: Allocations and Declarations
! 4434: -------------------------------------------------------------------------- */
! 4435: int tolen = (to==NULL?0:strlen(to)), /* #chars in replacement string */
! 4436: nshift = abs(tolen-nfirst); /*need to shift from left or right*/
! 4437: /* -------------------------------------------------------------------------
! 4438: shift from left or right to accommodate replacement of its nfirst chars by to
! 4439: -------------------------------------------------------------------------- */
! 4440: if ( tolen < nfirst ) /* shift left is easy */
! 4441: strcpy(from,from+nshift); /* because memory doesn't overlap */
! 4442: if ( tolen > nfirst ) /* need more room at start of from */
! 4443: { char *pfrom = from+strlen(from); /* ptr to null terminating from */
! 4444: for ( ; pfrom>=from; pfrom-- ) /* shift all chars including null */
! 4445: *(pfrom+nshift) = *pfrom; } /* shift chars nshift places right */
! 4446: /* -------------------------------------------------------------------------
! 4447: from has exactly the right number of free leading chars, so just put to there
! 4448: -------------------------------------------------------------------------- */
! 4449: if ( tolen != 0 ) /* make sure to not empty or null */
! 4450: memcpy(from,to,tolen); /* chars moved into place */
! 4451: return ( from ); /* changed string back to caller */
! 4452: } /* --- end-of-function strchange() --- */
! 4453:
! 4454:
! 4455: /* ==========================================================================
! 4456: * Function: strreplace (char *string, char *from, char *to, int nreplace)
! 4457: * Purpose: Changes the first nreplace occurrences of 'from' to 'to'
! 4458: * in string, or all occurrences if nreplace=0.
! 4459: * --------------------------------------------------------------------------
! 4460: * Arguments: string (I/0) char * to null-terminated string in which
! 4461: * occurrence of 'from' will be replaced by 'to'
! 4462: * from (I) char * to null-terminated string
! 4463: * to be replaced by 'to'
! 4464: * to (I) char * to null-terminated string that will
! 4465: * replace 'from'
! 4466: * nreplace (I) int containing (maximum) number of
! 4467: * replacements, or 0 to replace all.
! 4468: * --------------------------------------------------------------------------
! 4469: * Returns: ( int ) number of replacements performed,
! 4470: * or 0 for no replacements or -1 for any error.
! 4471: * --------------------------------------------------------------------------
! 4472: * Notes: o
! 4473: * ======================================================================= */
! 4474: /* --- entry point --- */
! 4475: int strreplace ( char *string, char *from, char *to, int nreplace )
! 4476: {
! 4477: /* -------------------------------------------------------------------------
! 4478: Allocations and Declarations
! 4479: -------------------------------------------------------------------------- */
! 4480: int fromlen = (from==NULL?0:strlen(from)), /* #chars to be replaced */
! 4481: tolen = (to==NULL?0:strlen(to)); /* #chars in replacement string */
! 4482: char *pfrom = (char *)NULL, /*ptr to 1st char of from in string*/
! 4483: *pstring = string, /*ptr past previously replaced from*/
! 4484: *strchange(); /* change 'from' to 'to' */
! 4485: int nreps = 0; /* #replacements returned to caller*/
! 4486: /* -------------------------------------------------------------------------
! 4487: repace occurrences of 'from' in string to 'to'
! 4488: -------------------------------------------------------------------------- */
! 4489: if ( string == (char *)NULL /* no input string */
! 4490: || (fromlen<1 && nreplace<=0) ) /* replacing empty string forever */
! 4491: nreps = (-1); /* so signal error */
! 4492: else /* args okay */
! 4493: while (nreplace<1 || nreps<nreplace) /* up to #replacements requested */
! 4494: {
! 4495: if ( fromlen > 0 ) /* have 'from' string */
! 4496: pfrom = strstr(pstring,from); /*ptr to 1st char of from in string*/
! 4497: else pfrom = pstring; /*or empty from at start of string*/
! 4498: if ( pfrom == (char *)NULL ) break; /*no more from's, so back to caller*/
! 4499: if ( strchange(fromlen,pfrom,to) /* leading 'from' changed to 'to' */
! 4500: == (char *)NULL ) { nreps=(-1); break; } /* signal error to caller */
! 4501: nreps++; /* count another replacement */
! 4502: pstring = pfrom+tolen; /* pick up search after 'to' */
! 4503: if ( *pstring == '\000' ) break; /* but quit at end of string */
! 4504: } /* --- end-of-while() --- */
! 4505: return ( nreps ); /* #replacements back to caller */
! 4506: } /* --- end-of-function strreplace() --- */
! 4507:
! 4508:
! 4509: /* ==========================================================================
! 4510: * Function: strtexchr (char *string, char *texchr )
! 4511: * Purpose: Find first texchr in string, but texchr must be followed
! 4512: * by non-alpha
! 4513: * --------------------------------------------------------------------------
! 4514: * Arguments: string (I) char * to null-terminated string in which
! 4515: * firstoccurrence of delim will be found
! 4516: * texchr (I) char * to null-terminated string that
! 4517: * will be searched for
! 4518: * --------------------------------------------------------------------------
! 4519: * Returns: ( char * ) ptr to first char of texchr in string
! 4520: * or NULL if not found or for any error.
! 4521: * --------------------------------------------------------------------------
! 4522: * Notes: o texchr should contain its leading \, e.g., "\\left"
! 4523: * ======================================================================= */
! 4524: /* --- entry point --- */
! 4525: char *strtexchr ( char *string, char *texchr )
! 4526: {
! 4527: /* -------------------------------------------------------------------------
! 4528: Allocations and Declarations
! 4529: -------------------------------------------------------------------------- */
! 4530: char *strstr(), delim, *ptexchr=(char *)NULL; /* ptr returned to caller*/
! 4531: char *pstring = string; /* start or continue up search here*/
! 4532: int texchrlen = (texchr==NULL?0:strlen(texchr)); /* #chars in texchr */
! 4533: /* -------------------------------------------------------------------------
! 4534: locate texchr in string
! 4535: -------------------------------------------------------------------------- */
! 4536: if ( string != (char *)NULL /* check that we got input string */
! 4537: && texchrlen > 0 ) /* and a texchr to search for */
! 4538: while ( (ptexchr=strstr(pstring,texchr)) /* look for texchr in string */
! 4539: != (char *)NULL ) /* found it */
! 4540: if ( (delim = ptexchr[texchrlen]) /* char immediately after texchr */
! 4541: == '\000' ) break; /* texchr at very end of string */
! 4542: else /* if there are chars after texchr */
! 4543: if ( isalpha(delim) /*texchr is prefix of longer symbol*/
! 4544: || 0 ) /* other tests to be determined */
! 4545: pstring = ptexchr + texchrlen; /* continue search after texchr */
! 4546: else /* passed all tests */
! 4547: break; /*so return ptr to texchr to caller*/
! 4548: return ( ptexchr ); /* ptr to texchar back to caller */
! 4549: } /* --- end-of-function strtexchr() --- */
! 4550:
! 4551:
! 4552: /* ==========================================================================
! 4553: * Function: findbraces ( char *expression, char *command )
! 4554: * Purpose: If expression!=NULL, finds opening left { preceding command;
! 4555: * if expression==NULL, finds closing right } after command.
! 4556: * For example, to parse out {a+b\over c+d} call findbraces()
! 4557: * twice.
! 4558: * --------------------------------------------------------------------------
! 4559: * Arguments: expression (I) NULL to find closing right } after command,
! 4560: * or char * to null-terminated string to find
! 4561: * left opening { preceding command.
! 4562: * command (I) char * to null-terminated string whose
! 4563: * first character is usually the \ of \command
! 4564: * --------------------------------------------------------------------------
! 4565: * Returns: ( char * ) ptr to either opening { or closing },
! 4566: * or NULL for any error.
! 4567: * --------------------------------------------------------------------------
! 4568: * Notes: o
! 4569: * ======================================================================= */
! 4570: /* --- entry point --- */
! 4571: char *findbraces ( char *expression, char *command )
! 4572: {
! 4573: /* -------------------------------------------------------------------------
! 4574: Allocations and Declarations
! 4575: -------------------------------------------------------------------------- */
! 4576: int isopen = (expression==NULL?0:1); /* true to find left opening { */
! 4577: char *left="{", *right="}", /* delims bracketing {x\command y} */
! 4578: *delim = (isopen?left:right), /* delim we want, { if isopen */
! 4579: *match = (isopen?right:left), /* matching delim, } if isopen */
! 4580: *brace = NULL; /* ptr to delim returned to caller */
! 4581: int inc = (isopen?-1:+1); /* pointer increment */
! 4582: int level = 1; /* nesting level, for {{}\command} */
! 4583: char *ptr = command; /* start search here */
! 4584: int setbrace = 1; /* true to set {}'s if none found */
! 4585: /* -------------------------------------------------------------------------
! 4586: search for left opening { before command, or right closing } after command
! 4587: -------------------------------------------------------------------------- */
! 4588: while ( 1 ) /* search for brace, or until end */
! 4589: {
! 4590: /* --- next char to check for delim --- */
! 4591: ptr += inc; /* bump ptr left or right */
! 4592: /* --- check for beginning or end of expression --- */
! 4593: if ( isopen ) /* going left, check for beginning */
! 4594: { if ( ptr < expression ) break; } /* went before start of string */
! 4595: else { if ( *ptr == '\000' ) break; } /* went past end of string */
! 4596: /* --- don't check this char if it's escaped --- */
! 4597: if ( !isopen || ptr>expression ) /* very first char can't be escaped*/
! 4598: if ( isthischar(*(ptr-1),ESCAPE) ) /* escape char precedes current */
! 4599: continue; /* so don't check this char */
! 4600: /* --- check for delim --- */
! 4601: if ( isthischar(*ptr,delim) ) /* found delim */
! 4602: if ( --level == 0 ) /* and it's not "internally" nested*/
! 4603: { brace = ptr; /* set ptr to brace */
! 4604: goto end_of_job; } /* and return it to caller */
! 4605: /* --- check for matching delim --- */
! 4606: if ( isthischar(*ptr,match) ) /* found matching delim */
! 4607: level++; /* so bump nesting level */
! 4608: } /* --- end-of-while(1) --- */
! 4609: end_of_job:
! 4610: if ( brace == (char *)NULL ) /* open{ or close} not found */
! 4611: if ( setbrace ) /* want to force one at start/end? */
! 4612: brace = ptr; /* { before expressn, } after cmmnd*/
! 4613: return ( brace ); /*back to caller with delim or NULL*/
! 4614: } /* --- end-of-function findbraces() --- */
! 4615: #endif /* PART2 */
! 4616:
! 4617: /* ---
! 4618: * PART3
! 4619: * ------ */
! 4620: #if !defined(PARTS) || defined(PART3)
! 4621: /* ==========================================================================
! 4622: * Function: rasterize ( expression, size )
! 4623: * Purpose: returns subraster corresponding to (a valid LaTeX) expression
! 4624: * at font size
! 4625: * --------------------------------------------------------------------------
! 4626: * Arguments: expression (I) char * to first char of null-terminated
! 4627: * string containing valid LaTeX expression
! 4628: * to be rasterized
! 4629: * size (I) int containing 0-4 default font size
! 4630: * --------------------------------------------------------------------------
! 4631: * Returns: ( subraster * ) ptr to subraster corresponding to expression,
! 4632: * or NULL for any parsing error.
! 4633: * --------------------------------------------------------------------------
! 4634: * Notes: o This is mimeTeX's "main" reusable entry point. Easy to use:
! 4635: * just call it with a LaTeX expression, and get back a bitmap
! 4636: * of that expression. Then do what you want with the bitmap.
! 4637: * ======================================================================= */
! 4638: /* --- entry point --- */
! 4639: subraster *rasterize ( char *expression, int size )
! 4640: {
! 4641: /* -------------------------------------------------------------------------
! 4642: Allocations and Declarations
! 4643: -------------------------------------------------------------------------- */
! 4644: char *preamble(), pretext[256]; /* process preamble, if present */
! 4645: char chartoken[8192], *texsubexpr(), /*get subexpression from expression*/
! 4646: *subexpr = chartoken; /* token may be parenthesized expr */
! 4647: int isbrace(); /* check subexpr for braces */
! 4648: mathchardef *symdef, *get_symdef(); /*get mathchardef struct for symbol*/
! 4649: int natoms=0; /* #atoms/tokens processed so far */
! 4650: int type_raster(); /* display debugging output */
! 4651: subraster *rasterize(), /* recurse */
! 4652: *rastparen(), /* handle parenthesized subexpr's */
! 4653: *rastlimits(); /* handle sub/superscripted expr's */
! 4654: subraster *rastcat(), /* concatanate atom subrasters */
! 4655: *subrastcpy(), /* copy final result if a charaster*/
! 4656: *new_subraster(); /* new subraster for isstring mode */
! 4657: subraster *get_charsubraster(), /* character subraster */
! 4658: *sp=NULL, *prevsp=NULL, /* raster for current, prev char */
! 4659: *expraster = (subraster *)NULL; /* raster returned to caller */
! 4660: int delete_subraster(); /* free everything before returning*/
! 4661: /*int pixsz = 1;*/ /*default #bits per pixel, 1=bitmap*/
! 4662: /* --- global values saved/restored at each recursive iteration --- */
! 4663: int wastext = istext, /* initial istext mode flag */
! 4664: wasstring = isstring, /* initial isstring mode flag */
! 4665: wasdisplaystyle = isdisplaystyle, /*initial displaystyle mode flag*/
! 4666: oldfontsize = fontsize, /* initial fontsize */
! 4667: olddisplaysize = displaysize, /* initial \displaystyle size */
! 4668: oldshrinkfactor = shrinkfactor, /* initial shrinkfactor */
! 4669: oldsquashmargin = squashmargin, /* initial squashmargin */
! 4670: oldissquashdelta = issquashdelta, /* initial issquashdelta */
! 4671: *oldworkingparam = workingparam; /* initial working parameter */
! 4672: subraster *oldworkingbox = workingbox, /* initial working box */
! 4673: *oldleftexpression = leftexpression; /*left half rasterized so far*/
! 4674: double oldunitlength = unitlength; /* initial unitlength */
! 4675: mathchardef *oldleftsymdef = leftsymdef; /* init oldleftsymdef */
! 4676: /* -------------------------------------------------------------------------
! 4677: initialization
! 4678: -------------------------------------------------------------------------- */
! 4679: recurlevel++; /* wind up one more recursion level*/
! 4680: leftexpression = NULL; /* no leading left half yet */
! 4681: isreplaceleft = 0; /* reset replaceleft flag */
! 4682: /* shrinkfactor = shrinkfactors[max2(0,min2(size,LARGESTSIZE))];*/ /*set sf*/
! 4683: shrinkfactor = shrinkfactors[max2(0,min2(size,16))]; /* have 17 sf's */
! 4684: if ( msgfp!=NULL && msglevel >= 29 ) /*display expression for debugging*/
! 4685: { fprintf(msgfp,
! 4686: "rasterize> recursion level=%d, size=%d,\n\texpression=\"%s\"\n",
! 4687: recurlevel,size,(expression==NULL?"null":expression)); fflush(msgfp); }
! 4688: if ( expression == NULL ) goto end_of_job; /* nothing given to do */
! 4689: /* -------------------------------------------------------------------------
! 4690: preocess optional $-terminated preamble preceding expression
! 4691: -------------------------------------------------------------------------- */
! 4692: expression = preamble(expression,&size,pretext); /* size may be modified */
! 4693: if ( *expression == '\000' ) goto end_of_job; /* nothing left to do */
! 4694: fontsize = size; /* start at requested size */
! 4695: if ( isdisplaystyle == 1 ) /* displaystyle enabled but not set*/
! 4696: if ( !ispreambledollars ) /* style fixed by $$...$$'s */
! 4697: isdisplaystyle = (fontsize>=displaysize? 2:1); /*force at large fontsize*/
! 4698: /* -------------------------------------------------------------------------
! 4699: build up raster one character (or subexpression) at a time
! 4700: -------------------------------------------------------------------------- */
! 4701: while ( 1 )
! 4702: {
! 4703: /* --- get next character/token or subexpression --- */
! 4704: expression = texsubexpr(expression,chartoken,0,LEFTBRACES,RIGHTBRACES,1,1);
! 4705: subexpr = chartoken; /* "local" copy of chartoken ptr */
! 4706: leftsymdef = NULL; /* no character identified yet */
! 4707: sp = NULL; /* no subraster yet */
! 4708: size = fontsize; /* in case reset by \tiny, etc */
! 4709: /* --- debugging output --- */
! 4710: if ( msgfp!=NULL && msglevel >= 999 ) /* display chartoken for debugging */
! 4711: { fprintf(msgfp,"rasterize> recursion level=%d, atom#%d = \"%s\"\n",
! 4712: recurlevel,natoms+1,chartoken); fflush(msgfp); }
! 4713: if ( expression == NULL /* no more tokens */
! 4714: && *subexpr == '\000' ) break; /* and this token empty */
! 4715: if ( *subexpr == '\000' ) break; /* enough if just this token empty */
! 4716: /* --- check for parenthesized subexpression --- */
! 4717: if ( isbrace(subexpr,LEFTBRACES,1) ) /* got parenthesized subexpression */
! 4718: { if ( (sp=rastparen(&subexpr,size,prevsp)) /* rasterize subexpression */
! 4719: == NULL ) continue; } /* flush it if failed to rasterize */
! 4720: else /* --- single-character atomic token --- */
! 4721: if ( !isthischar(*subexpr,SCRIPTS) ) /* scripts handled below */
! 4722: {
! 4723: /* --- first look up mathchardef for atomic token in table --- */
! 4724: if ( (leftsymdef=symdef=get_symdef(chartoken)) /*mathchardef for token*/
! 4725: == NULL ) /* lookup failed */
! 4726: { char literal[512] = "[?]"; /*display for unrecognized literal*/
! 4727: int wastext = istext; /* error display in default mode */
! 4728: if ( msgfp!=NULL && msglevel >= 29 ) /* display unrecognized symbol */
! 4729: { fprintf(msgfp,"rasterize> get_symdef() failed for \"%s\"\n",
! 4730: chartoken); fflush(msgfp); }
! 4731: sp = (subraster *)NULL; /* init to signal failure */
! 4732: if ( warninglevel < 1 ) continue; /* warnings not wanted */
! 4733: istext = 0; /* reset from \mathbb, etc */
! 4734: if ( isthischar(*chartoken,ESCAPE) ) /* we got unrecognized \escape */
! 4735: { /* --- so display literal {\rm~[\backslash~chartoken?]} --- */
! 4736: strcpy(literal,"{\\rm~[\\backslash~"); /* init token */
! 4737: strcat(literal,chartoken+1); /* add chars following leading \ */
! 4738: strcat(literal,"?]}"); } /* add closing brace */
! 4739: sp = rasterize(literal,size-1); /* rasterize literal token */
! 4740: istext = wastext; /* reset text mode */
! 4741: if ( sp == (subraster *)NULL ) continue; } /*flush if rasterize fails*/
! 4742: else /* --- check if we have special handler to process this token --- */
! 4743: if ( symdef->handler != NULL ) /* have a handler for this token */
! 4744: { int arg1=symdef->charnum, arg2=symdef->family, arg3=symdef->class;
! 4745: if ( (sp = (subraster *) /* returned void* is subraster* */
! 4746: (*(symdef->handler))(&expression,size,prevsp,arg1,arg2,arg3))== NULL )
! 4747: continue; } /* flush token if handler failed */
! 4748: else /* --- no handler, so just get subraster for this character --- */
! 4749: if ( !isstring ) /* rasterizing */
! 4750: { if ( (sp=get_charsubraster(symdef,size)) /* get subraster */
! 4751: == NULL ) continue; } /* flush token if failed */
! 4752: else /* constructing ascii string */
! 4753: { char *symbol = symdef->symbol; /* symbol for ascii string */
! 4754: int symlen = (symbol!=NULL?strlen(symbol):0); /*#chars in symbol*/
! 4755: if ( symlen < 1 ) continue; /* no symbol for ascii string */
! 4756: if ( (sp=new_subraster(symlen+1,1,8)) /* subraster for symbol */
! 4757: == NULL ) continue; /* flush token if malloc failed */
! 4758: sp->type = ASCIISTRING; /* set subraster type */
! 4759: sp->symdef = symdef; /* and set symbol definition */
! 4760: sp->baseline = 1; /* default (should be unused) */
! 4761: strcpy((char *)((sp->image)->pixmap),symbol); /* copy symbol */
! 4762: /*((char *)((sp->image)->pixmap))[symlen] = '\000';*/ } /*null*/
! 4763: } /* --- end-of-if/else ... if/else --- */
! 4764: /* --- handle any super/subscripts following symbol or subexpression --- */
! 4765: sp = rastlimits(&expression,size,sp);
! 4766: /* --- debugging output --- */
! 4767: if ( msgfp!=NULL && msglevel >= 999 ) /* display raster for debugging */
! 4768: { fprintf(msgfp,"rasterize> recursion level=%d, atom#%d%s\n",
! 4769: recurlevel,natoms+1,(sp==NULL?" = null":"..."));
! 4770: if(sp!=NULL) type_raster(sp->image,msgfp); /* display raster */
! 4771: fflush(msgfp); } /* flush msgfp buffer */
! 4772: /* --- accumulate atom or parenthesized subexpression --- */
! 4773: if ( natoms < 1 /* nothing previous to concat */
! 4774: || expraster == NULL /* or previous was complete error */
! 4775: || isreplaceleft ) /* or we're replacing previous */
! 4776: { expraster = subrastcpy(sp); /* so just copy static CHARASTER */
! 4777: isreplaceleft = 0; } /* reset replacement flag */
! 4778: else /*we've already built up atoms so...*/
! 4779: if ( sp != NULL ) /* ...if we have a new component */
! 4780: expraster = rastcat(expraster,sp,1); /* concat new one, free previous */
! 4781: delete_subraster(prevsp); /* free prev (if not a CHARASTER) */
! 4782: prevsp = sp; /* current becomes previous */
! 4783: leftexpression = expraster; /* left half rasterized so far */
! 4784: /* --- bump count --- */
! 4785: natoms++; /* bump #atoms count */
! 4786: } /* --- end-of-while(expression!=NULL) --- */
! 4787: /* -------------------------------------------------------------------------
! 4788: back to caller with rasterized expression
! 4789: -------------------------------------------------------------------------- */
! 4790: end_of_job:
! 4791: delete_subraster(prevsp); /* free last (if not a CHARASTER) */
! 4792: /* --- debugging output --- */
! 4793: if ( msgfp!=NULL && msglevel >= 999 ) /* display raster for debugging */
! 4794: { fprintf(msgfp,"rasterize> Final recursion level=%d, atom#%d...\n",
! 4795: recurlevel,natoms);
! 4796: if ( expraster != (subraster *)NULL ) /* i.e., if natoms>0 */
! 4797: type_raster(expraster->image,msgfp); /* display completed raster */
! 4798: fflush(msgfp); } /* flush msgfp buffer */
! 4799: /* --- restore flags/values to original saved values --- */
! 4800: istext = wastext; /* text mode reset */
! 4801: isstring = wasstring; /* string mode reset */
! 4802: isdisplaystyle = wasdisplaystyle; /* displaystyle mode reset */
! 4803: fontsize = oldfontsize; /* fontsize reset */
! 4804: displaysize = olddisplaysize; /* \displaystyle size reset */
! 4805: shrinkfactor = oldshrinkfactor; /* shrinkfactor reset */
! 4806: squashmargin = oldsquashmargin; /* squashmargin reset */
! 4807: issquashdelta = oldissquashdelta; /* issquashdelta reset */
! 4808: workingparam = oldworkingparam; /* working parameter reset */
! 4809: workingbox = oldworkingbox; /* working box reset */
! 4810: leftexpression = oldleftexpression; /* leftexpression reset */
! 4811: leftsymdef = oldleftsymdef; /* leftsymdef reset */
! 4812: unitlength = oldunitlength; /* unitlength reset */
! 4813: recurlevel--; /* unwind one recursion level */
! 4814: /* --- return final subraster to caller --- */
! 4815: if ( 1 && expraster != (subraster *)NULL ) /* have an expression */
! 4816: { expraster->type = IMAGERASTER; /* set type to constructed image */
! 4817: expraster->size = fontsize; } /* set original input font size */
! 4818: return ( expraster );
! 4819: } /* --- end-of-function rasterize() --- */
! 4820:
! 4821:
! 4822: /* ==========================================================================
! 4823: * Function: rastparen ( subexpr, size, basesp )
! 4824: * Purpose: parentheses handler, returns a subraster corresponding to
! 4825: * parenthesized subexpression at font size
! 4826: * --------------------------------------------------------------------------
! 4827: * Arguments: subexpr (I) char ** to first char of null-terminated
! 4828: * string beginning with a LEFTBRACES
! 4829: * to be rasterized
! 4830: * size (I) int containing 0-5 default font size
! 4831: * basesp (I) subraster * to character (or subexpression)
! 4832: * immediately preceding leading left{
! 4833: * (unused, but passed for consistency)
! 4834: * --------------------------------------------------------------------------
! 4835: * Returns: ( subraster * ) ptr to subraster corresponding to subexpr,
! 4836: * or NULL for any parsing error
! 4837: * --------------------------------------------------------------------------
! 4838: * Notes: o This "handler" isn't in the mathchardef symbol table,
! 4839: * but is called directly from rasterize(), as necessary.
! 4840: * o Though subexpr is returned unchanged, it's passed as char **
! 4841: * for consistency with other handlers. Ditto, basesp is unused
! 4842: * but passed for consistency
! 4843: * ======================================================================= */
! 4844: /* --- entry point --- */
! 4845: subraster *rastparen ( char **subexpr, int size, subraster *basesp )
! 4846: {
! 4847: /* -------------------------------------------------------------------------
! 4848: Allocations and Declarations
! 4849: -------------------------------------------------------------------------- */
! 4850: char *expression = *subexpr; /* dereference subexpr to get char* */
! 4851: int explen = strlen(expression); /* total #chars, including parens */
! 4852: int isescape = 0, /* true if parens \escaped */
! 4853: isrightdot = 0, /* true if right paren is \right. */
! 4854: isleftdot = 0; /* true if left paren is \left. */
! 4855: char left[16], right[16]; /* parens enclosing expresion */
! 4856: char noparens[8192]; /* get subexpr without parens */
! 4857: subraster *rasterize(), *sp=NULL; /* rasterize what's between ()'s */
! 4858: int isheight = 1; /*true=full height, false=baseline*/
! 4859: int height, /* height of rasterized noparens[] */
! 4860: baseline; /* and its baseline */
! 4861: int family = CMEX10; /* family for paren chars */
! 4862: subraster *get_delim(), *lp=NULL, *rp=NULL; /* left and right paren chars */
! 4863: subraster *rastcat(); /* concatanate subrasters */
! 4864: int delete_subraster(); /*in case of error after allocation*/
! 4865: /* -------------------------------------------------------------------------
! 4866: rasterize "interior" of expression, i.e., without enclosing parens
! 4867: -------------------------------------------------------------------------- */
! 4868: /* --- first see if enclosing parens are \escaped --- */
! 4869: if ( isthischar(*expression,ESCAPE) ) /* expression begins with \escape */
! 4870: isescape = 1; /* so set flag accordingly */
! 4871: /* --- get expression *without* enclosing parens --- */
! 4872: strcpy(noparens,expression); /* get local copy of expression */
! 4873: noparens[explen-(1+isescape)] = '\000'; /* null-terminate before right} */
! 4874: strcpy(noparens,noparens+(1+isescape)); /* and then squeeze out left{ */
! 4875: /* --- rasterize it --- */
! 4876: if ( (sp = rasterize(noparens,size)) /*rasterize "interior" of expression*/
! 4877: == NULL ) goto end_of_job; /* quit if failed */
! 4878: /* --- no need to add parentheses for unescaped { --- */
! 4879: if ( !isescape && isthischar(*expression,"{") ) /* don't add parentheses */
! 4880: goto end_of_job; /* just return sp to caller */
! 4881: /* -------------------------------------------------------------------------
! 4882: obtain paren characters to enclose noparens[] raster with
! 4883: -------------------------------------------------------------------------- */
! 4884: /* --- first get left and right parens from expression --- */
! 4885: memset(left,0,16); memset(right,0,16); /* init parens with nulls */
! 4886: left[0] = *(expression+isescape); /* left{ is 1st or 2nd char */
! 4887: right[0] = *(expression+explen-1); /* right} is always last char */
! 4888: isleftdot = (isescape && isthischar(*left,".")); /* true if \left. */
! 4889: isrightdot = (isescape && isthischar(*right,".")); /* true if \right. */
! 4890: /* --- need height of noparens[] raster as minimum parens height --- */
! 4891: height = (sp->image)->height; /* height of noparens[] raster */
! 4892: baseline = sp->baseline; /* baseline of noparens[] raster */
! 4893: if ( !isheight ) height = baseline+1; /* parens only enclose baseline up */
! 4894: /* --- get best-fit parentheses characters --- */
! 4895: if ( !isleftdot ) /* if not \left. */
! 4896: lp = get_delim(left,height+1,family); /* get left paren char */
! 4897: if ( !isrightdot ) /* and if not \right. */
! 4898: rp = get_delim(right,height+1,family); /* get right paren char */
! 4899: if ( (lp==NULL && !isleftdot) /* check that we got left( */
! 4900: || (rp==NULL && !isrightdot) ) /* and right) if needed */
! 4901: { delete_subraster(sp); /* if failed, free subraster */
! 4902: if ( lp != NULL ) free ((void *)lp);/*free left-paren subraster envelope*/
! 4903: if ( rp != NULL ) free ((void *)rp);/*and right-paren subraster envelope*/
! 4904: sp = (subraster *)NULL; /* signal error to caller */
! 4905: goto end_of_job; } /* and quit */
! 4906: /* -------------------------------------------------------------------------
! 4907: set paren baselines to center on noparens[] raster, and concat components
! 4908: -------------------------------------------------------------------------- */
! 4909: /* --- set baselines to center paren chars on raster --- */
! 4910: if ( lp != NULL ) /* ignore for \left. */
! 4911: lp->baseline = baseline + ((lp->image)->height - height)/2;
! 4912: if ( rp != NULL ) /* ignore for \right. */
! 4913: rp->baseline = baseline + ((rp->image)->height - height)/2;
! 4914: /* --- concat lp||sp||rp to obtain final result --- */
! 4915: if ( lp != NULL ) /* ignore \left. */
! 4916: sp = rastcat(lp,sp,3); /* concat lp||sp and free sp,lp */
! 4917: if ( sp != NULL ) /* succeeded or ignored \left. */
! 4918: if ( rp != NULL ) /* ignore \right. */
! 4919: sp = rastcat(sp,rp,3); /* concat sp||rp and free sp,rp */
! 4920: /* --- back to caller --- */
! 4921: end_of_job:
! 4922: return ( sp );
! 4923: } /* --- end-of-function rastparen() --- */
! 4924:
! 4925:
! 4926: /* ==========================================================================
! 4927: * Function: rastlimits ( expression, size, basesp )
! 4928: * Purpose: \limits, \nolimts, _ and ^ handler,
! 4929: * dispatches call to rastscripts() or to rastdispmath()
! 4930: * as necessary, to handle sub/superscripts following symbol
! 4931: * --------------------------------------------------------------------------
! 4932: * Arguments: expression (I) char ** to first char of null-terminated
! 4933: * LaTeX expression (unused/unchanged)
! 4934: * size (I) int containing base font size (not used,
! 4935: * just stored in subraster)
! 4936: * basesp (I) subraster * to current character (or
! 4937: * subexpression) immediately preceding script
! 4938: * indicator
! 4939: * --------------------------------------------------------------------------
! 4940: * Returns: ( subraster * ) ptr to subraster returned by rastscripts()
! 4941: * or rastdispmath(), or NULL for any error
! 4942: * --------------------------------------------------------------------------
! 4943: * Notes: o
! 4944: * ======================================================================= */
! 4945: /* --- entry point --- */
! 4946: subraster *rastlimits ( char **expression, int size, subraster *basesp )
! 4947: {
! 4948: /* -------------------------------------------------------------------------
! 4949: Allocations and Declarations
! 4950: -------------------------------------------------------------------------- */
! 4951: subraster *rastscripts(), *rastdispmath(), /*one of these will do the work*/
! 4952: *rastcat(), /* may need to concat scripts */
! 4953: *scriptsp = basesp; /* and this will become the result */
! 4954: int isdisplay = (-1); /* set 1 for displaystyle, else 0 */
! 4955: int oldsquashmargin = squashmargin; /* save original squashmargin */
! 4956: int type_raster(); /* display debugging output */
! 4957: /* --- to check for \limits or \nolimits preceding scripts --- */
! 4958: char *texchar(), *exprptr=*expression, limtoken[255]; /*check for \limits*/
! 4959: int toklen=0; /* strlen(limtoken) */
! 4960: mathchardef *tokdef, *get_symdef(); /* mathchardef struct for limtoken */
! 4961: int class=(leftsymdef==NULL?NOVALUE:leftsymdef->class); /*base sym class*/
! 4962: /* -------------------------------------------------------------------------
! 4963: determine whether or not to use displaymath
! 4964: -------------------------------------------------------------------------- */
! 4965: scriptlevel++; /* first, increment subscript level*/
! 4966: *limtoken = '\000'; /* no token yet */
! 4967: if ( msgfp!=NULL && msglevel>=999 )
! 4968: { fprintf(msgfp,"rastlimits> scriptlevel#%d exprptr=%.48s\n",
! 4969: scriptlevel,(exprptr==NULL?"null":exprptr)); fflush(msgfp); }
! 4970: if ( isstring ) goto end_of_job; /* no scripts for ascii string */
! 4971: /* --- check for \limits or \nolimits --- */
! 4972: skipwhite(exprptr); /* skip white space before \limits */
! 4973: if ( exprptr != NULL ) /* expression ptr supplied */
! 4974: if ( *exprptr != '\000' ) /* something in expression */
! 4975: exprptr = texchar(exprptr,limtoken); /* retrieve next token */
! 4976: if ( *limtoken != '\000' ) /* have token */
! 4977: if ( (toklen=strlen(limtoken)) >= 3 ) /* which may be \[no]limits */
! 4978: if ( memcmp("\\limits",limtoken,toklen) == 0 /* may be \limits */
! 4979: || memcmp("\\nolimits",limtoken,toklen) == 0 ) /* or may be \nolimits */
! 4980: if ( (tokdef= get_symdef(limtoken)) /* look up token to be sure */
! 4981: != NULL ) /* found token in table */
! 4982: if ( strcmp("\\limits",tokdef->symbol) == 0 ) /* found \limits */
! 4983: isdisplay = 1; /* so explicitly set displaymath */
! 4984: else /* wasn't \limits */
! 4985: if ( strcmp("\\nolimits",tokdef->symbol) == 0 ) /* found \nolimits */
! 4986: isdisplay = 0; /* so explicitly reset displaymath */
! 4987: /* --- see if we found \[no]limits --- */
! 4988: if ( isdisplay != (-1) ) /* explicit directive found */
! 4989: *expression = exprptr; /* so bump expression past it */
! 4990: else /* noexplicit directive */
! 4991: { isdisplay = 0; /* init displaymath flag off */
! 4992: if ( isdisplaystyle ) /* we're in displaystyle math mode */
! 4993: if ( isdisplaystyle >= 5 ) /* and mode irrevocably forced true */
! 4994: { if ( class!=OPENING && class!=CLOSING ) /*don't force ('s and )'s*/
! 4995: isdisplay = 1; } /* set flag if mode forced true */
! 4996: else
! 4997: if ( isdisplaystyle >= 2 ) /*or mode forced conditionally true*/
! 4998: { if ( class!=VARIABLE && class!=ORDINARY /*don't force characters*/
! 4999: && class!=OPENING && class!=CLOSING /*don't force ('s and )'s*/
! 5000: && class!=BINARYOP /* don't force binary operators */
! 5001: && class!=NOVALUE ) /* finally, don't force "images" */
! 5002: isdisplay = 1; } /* set flag if mode forced true */
! 5003: else /* determine mode from base symbol */
! 5004: if ( class == DISPOPER ) /* it's a displaystyle operator */
! 5005: isdisplay = 1; } /* so set flag */
! 5006: /* -------------------------------------------------------------------------
! 5007: dispatch call to create sub/superscripts
! 5008: -------------------------------------------------------------------------- */
! 5009: if ( isdisplay ) /* scripts above/below base symbol */
! 5010: scriptsp = rastdispmath(expression,size,basesp); /* everything all done */
! 5011: else /* scripts alongside base symbol */
! 5012: if ( (scriptsp=rastscripts(expression,size,basesp)) == NULL ) /*no scripts*/
! 5013: scriptsp = basesp; /* so just return unscripted symbol*/
! 5014: else /* symbols followed by scripts */
! 5015: if ( basesp != NULL ) /* have base symbol */
! 5016: { squashmargin = 0; /* don't squash script */
! 5017: scriptsp = rastcat(basesp,scriptsp,2); /*concat scripts to base sym*/
! 5018: scriptsp->type = IMAGERASTER; /* flip type of composite object */
! 5019: scriptsp->size = size; } /* and set font size */
! 5020: end_of_job:
! 5021: squashmargin = oldsquashmargin; /* reset original squashmargin */
! 5022: if ( msgfp!=NULL && msglevel>=99 )
! 5023: { fprintf(msgfp,"rastlimits> scriptlevel#%d returning %s\n",
! 5024: scriptlevel,(scriptsp==NULL?"null":"..."));
! 5025: if ( scriptsp != NULL ) /* have a constructed raster */
! 5026: type_raster(scriptsp->image,msgfp); /*display constructed raster*/
! 5027: fflush(msgfp); }
! 5028: scriptlevel--; /*lastly, decrement subscript level*/
! 5029: return ( scriptsp );
! 5030: } /* --- end-of-function rastlimits() --- */
! 5031:
! 5032:
! 5033: /* ==========================================================================
! 5034: * Function: rastscripts ( expression, size, basesp )
! 5035: * Purpose: super/subscript handler, returns subraster for the leading
! 5036: * scripts in expression, whose base symbol is at font size
! 5037: * --------------------------------------------------------------------------
! 5038: * Arguments: expression (I/O) char ** to first char of null-terminated
! 5039: * string beginning with a super/subscript,
! 5040: * and returning ptr immediately following
! 5041: * last script character processed.
! 5042: * size (I) int containing 0-4 default font size
! 5043: * basesp (I) subraster * to character (or subexpression)
! 5044: * immediately preceding leading script
! 5045: * (scripts will be placed relative to base)
! 5046: * --------------------------------------------------------------------------
! 5047: * Returns: ( subraster * ) ptr to subraster corresponding to scripts,
! 5048: * or NULL for any parsing error
! 5049: * --------------------------------------------------------------------------
! 5050: * Notes: o This "handler" isn't in the mathchardef symbol table,
! 5051: * but is called directly from rasterize(), as necessary.
! 5052: * ======================================================================= */
! 5053: /* --- entry point --- */
! 5054: subraster *rastscripts ( char **expression, int size, subraster *basesp )
! 5055: {
! 5056: /* -------------------------------------------------------------------------
! 5057: Allocations and Declarations
! 5058: -------------------------------------------------------------------------- */
! 5059: char *texscripts(), /* parse expression for scripts */
! 5060: subscript[512], supscript[512]; /* scripts parsed from expression */
! 5061: subraster *rasterize(), *subsp=NULL, *supsp=NULL; /* rasterize scripts */
! 5062: subraster *new_subraster(), *sp=NULL, /* super- over subscript subraster */
! 5063: *rastack(); /*sets scripts in displaymath mode*/
! 5064: raster *rp=NULL; /* image raster embedded in sp */
! 5065: int height=0, width=0, baseline=0, /* height,width,baseline of sp */
! 5066: subht=0, subwidth=0, subln=0, /* height,width,baseline of sub */
! 5067: supht=0, supwidth=0, supln=0, /* height,width,baseline of sup */
! 5068: baseht=0, baseln=0; /* height,baseline of base */
! 5069: int bdescend=0, sdescend=0; /* descender of base, subscript */
! 5070: int issub=0, issup=0, isboth=0, /* true if we have sub,sup,both */
! 5071: isbase=0; /* true if we have base symbol */
! 5072: int szval = min2(max2(size,0),LARGESTSIZE), /* 0...LARGESTSIZE */
! 5073: vbetween = 2, /* vertical space between scripts */
! 5074: vabove = szval+1, /*sup's top/bot above base's top/bot*/
! 5075: vbelow = szval+1, /*sub's top/bot below base's top/bot*/
! 5076: vbottom = szval+1; /*sup's bot above (sub's below) bsln*/
! 5077: /*int istweak = 1;*/ /* true to tweak script positioning */
! 5078: int rastput(); /*put scripts in constructed raster*/
! 5079: int delete_subraster(); /* free work areas */
! 5080: int pixsz = 1; /*default #bits per pixel, 1=bitmap*/
! 5081: /* -------------------------------------------------------------------------
! 5082: Obtain subscript and/or superscript expressions, and rasterize them/it
! 5083: -------------------------------------------------------------------------- */
! 5084: /* --- parse for sub,superscript(s), and bump expression past it(them) --- */
! 5085: if ( expression == NULL ) goto end_of_job; /* no *ptr given */
! 5086: if ( *expression == NULL ) goto end_of_job; /* no expression given */
! 5087: if ( *(*expression) == '\000' ) goto end_of_job; /* nothing in expression */
! 5088: *expression = texscripts(*expression,subscript,supscript,3);
! 5089: /* --- rasterize scripts --- */
! 5090: if ( *subscript != '\000' ) /* have a subscript */
! 5091: subsp = rasterize(subscript,size-1); /* so rasterize it at size-1 */
! 5092: if ( *supscript != '\000' ) /* have a superscript */
! 5093: supsp = rasterize(supscript,size-1); /* so rasterize it at size-1 */
! 5094: /* --- set flags for convenience --- */
! 5095: issub = (subsp != (subraster *)NULL); /* true if we have subscript */
! 5096: issup = (supsp != (subraster *)NULL); /* true if we have superscript */
! 5097: isboth = (issub && issup); /* true if we have both */
! 5098: if (!issub && !issup) goto end_of_job; /* quit if we have neither */
! 5099: /* -------------------------------------------------------------------------
! 5100: get height, width, baseline of scripts, and height, baseline of base symbol
! 5101: -------------------------------------------------------------------------- */
! 5102: /* --- get height and width of components --- */
! 5103: if ( issub ) /* we have a subscript */
! 5104: { subht = (subsp->image)->height; /* so get its height */
! 5105: subwidth = (subsp->image)->width; /* and width */
! 5106: subln = subsp->baseline; } /* and baseline */
! 5107: if ( issup ) /* we have a superscript */
! 5108: { supht = (supsp->image)->height; /* so get its height */
! 5109: supwidth = (supsp->image)->width; /* and width */
! 5110: supln = supsp->baseline; } /* and baseline */
! 5111: /* --- get height and baseline of base, and descender of base and sub --- */
! 5112: if ( basesp == (subraster *)NULL ) /* no base symbol for scripts */
! 5113: basesp = leftexpression; /* try using left side thus far */
! 5114: if ( basesp != (subraster *)NULL ) /* we have base symbol for scripts */
! 5115: { baseht = (basesp->image)->height; /* height of base symbol */
! 5116: baseln = basesp->baseline; /* and its baseline */
! 5117: bdescend = baseht-(baseln+1); /* and base symbol descender */
! 5118: sdescend = bdescend + vbelow; /*sub must descend by at least this*/
! 5119: if ( baseht > 0 ) isbase = 1; } /* set flag */
! 5120: /* -------------------------------------------------------------------------
! 5121: determine width of constructed raster
! 5122: -------------------------------------------------------------------------- */
! 5123: width = max2(subwidth,supwidth); /*widest component is overall width*/
! 5124: /* -------------------------------------------------------------------------
! 5125: determine height and baseline of constructed raster
! 5126: -------------------------------------------------------------------------- */
! 5127: /* --- both super/subscript --- */
! 5128: if ( isboth ) /*we have subscript and superscript*/
! 5129: { height = max2(subht+vbetween+supht, /* script heights + space bewteen */
! 5130: vbelow+baseht+vabove); /*sub below base bot, sup above top*/
! 5131: baseline = baseln + (height-baseht)/2; } /*center scripts on base symbol*/
! 5132: /* --- superscript only --- */
! 5133: if ( !issub ) /* we only have a superscript */
! 5134: { height = max3(baseln+1+vabove, /* sup's top above base symbol top */
! 5135: supht+vbottom, /* sup's bot above baseln */
! 5136: supht+vabove-bdescend); /* sup's bot above base symbol bot */
! 5137: baseline = height-1; } /*sup's baseline at bottom of raster*/
! 5138: /* --- subscript only --- */
! 5139: if ( !issup ) /* we only have a subscript */
! 5140: if ( subht > sdescend ) /*sub can descend below base bot...*/
! 5141: { height = subht; /* ...without extra space on top */
! 5142: baseline = height-(sdescend+1); /* sub's bot below base symbol bot */
! 5143: baseline = min2(baseline,max2(baseln-vbelow,0)); }/*top below base top*/
! 5144: else /* sub's top will be below baseln */
! 5145: { height = sdescend+1; /* sub's bot below base symbol bot */
! 5146: baseline = 0; } /* sub's baseline at top of raster */
! 5147: /* -------------------------------------------------------------------------
! 5148: construct raster with superscript over subscript
! 5149: -------------------------------------------------------------------------- */
! 5150: /* --- allocate subraster containing constructed raster --- */
! 5151: if ( (sp=new_subraster(width,height,pixsz)) /*allocate subraster and raster*/
! 5152: == NULL ) /* and if we fail to allocate */
! 5153: goto end_of_job; /* quit */
! 5154: /* --- initialize subraster parameters --- */
! 5155: sp->type = IMAGERASTER; /* set type as constructed image */
! 5156: sp->size = size; /* set given size */
! 5157: sp->baseline = baseline; /* composite scripts baseline */
! 5158: rp = sp->image; /* raster embedded in subraster */
! 5159: /* --- place super/subscripts in new raster --- */
! 5160: if ( issup ) /* we have a superscript */
! 5161: rastput(rp,supsp->image,0,0,1); /* it goes in upper-left corner */
! 5162: if ( issub ) /* we have a subscript */
! 5163: rastput(rp,subsp->image,height-subht,0,1); /*in lower-left corner*/
! 5164: /* -------------------------------------------------------------------------
! 5165: free unneeded component subrasters and return final result to caller
! 5166: -------------------------------------------------------------------------- */
! 5167: end_of_job:
! 5168: if ( issub ) delete_subraster(subsp); /* free unneeded subscript */
! 5169: if ( issup ) delete_subraster(supsp); /* and superscript */
! 5170: return ( sp );
! 5171: } /* --- end-of-function rastscripts() --- */
! 5172:
! 5173:
! 5174: /* ==========================================================================
! 5175: * Function: rastdispmath ( expression, size, sp )
! 5176: * Purpose: displaymath handler, returns sp along with
! 5177: * its immediately following super/subscripts
! 5178: * --------------------------------------------------------------------------
! 5179: * Arguments: expression (I/O) char ** to first char of null-terminated
! 5180: * string immediately following sp to be
! 5181: * rasterized along with its super/subscripts,
! 5182: * and returning ptr immediately following last
! 5183: * character processed.
! 5184: * size (I) int containing 0-4 default font size
! 5185: * sp (I) subraster * to display math operator
! 5186: * to which super/subscripts will be added
! 5187: * --------------------------------------------------------------------------
! 5188: * Returns: ( subraster * ) ptr to subraster corresponding to sp
! 5189: * plus its scripts, or NULL for any error
! 5190: * --------------------------------------------------------------------------
! 5191: * Notes: o sp returned unchanged if no super/subscript(s) follow it.
! 5192: * ======================================================================= */
! 5193: /* --- entry point --- */
! 5194: subraster *rastdispmath ( char **expression, int size, subraster *sp )
! 5195: {
! 5196: /* -------------------------------------------------------------------------
! 5197: Allocations and Declarations
! 5198: -------------------------------------------------------------------------- */
! 5199: char *texscripts(), /* parse expression for scripts */
! 5200: subscript[512], supscript[512]; /* scripts parsed from expression */
! 5201: int issub=0, issup=0; /* true if we have sub,sup */
! 5202: subraster *rasterize(), *subsp=NULL, *supsp=NULL, /* rasterize scripts */
! 5203: *rastack(), /* stack operator with scripts */
! 5204: *new_subraster(); /* for dummy base sp, if needed */
! 5205: int vspace = 1; /* vertical space between scripts */
! 5206: /* -------------------------------------------------------------------------
! 5207: Obtain subscript and/or superscript expressions, and rasterize them/it
! 5208: -------------------------------------------------------------------------- */
! 5209: /* --- parse for sub,superscript(s), and bump expression past it(them) --- */
! 5210: if ( expression == NULL ) goto end_of_job; /* no *ptr given */
! 5211: if ( *expression == NULL ) goto end_of_job; /* no expression given */
! 5212: if ( *(*expression) == '\000' ) goto end_of_job; /* nothing in expression */
! 5213: *expression = texscripts(*expression,subscript,supscript,3);
! 5214: /* --- rasterize scripts --- */
! 5215: if ( *subscript != '\000' ) /* have a subscript */
! 5216: subsp = rasterize(subscript,size-1); /* so rasterize it at size-1 */
! 5217: if ( *supscript != '\000' ) /* have a superscript */
! 5218: supsp = rasterize(supscript,size-1); /* so rasterize it at size-1 */
! 5219: /* --- set flags for convenience --- */
! 5220: issub = (subsp != (subraster *)NULL); /* true if we have subscript */
! 5221: issup = (supsp != (subraster *)NULL); /* true if we have superscript */
! 5222: if (!issub && !issup) goto end_of_job; /*return operator alone if neither*/
! 5223: /* -------------------------------------------------------------------------
! 5224: stack operator and its script(s)
! 5225: -------------------------------------------------------------------------- */
! 5226: /* --- stack superscript atop operator --- */
! 5227: if ( issup ) /* we have a superscript */
! 5228: if ( sp == NULL ) /* but no base expression */
! 5229: sp = supsp; /* so just use superscript */
! 5230: else /* have base and superscript */
! 5231: if ( (sp=rastack(sp,supsp,1,vspace,1,3)) /* stack supsp atop base sp */
! 5232: == NULL ) goto end_of_job; /* and quit if failed */
! 5233: /* --- stack operator+superscript atop subscript --- */
! 5234: if ( issub ) /* we have a subscript */
! 5235: if ( sp == NULL ) /* but no base expression */
! 5236: sp = subsp; /* so just use subscript */
! 5237: else /* have base and subscript */
! 5238: if ( (sp=rastack(subsp,sp,2,vspace,1,3)) /* stack sp atop base subsp */
! 5239: == NULL ) goto end_of_job; /* and quit if failed */
! 5240: sp->type = IMAGERASTER; /* flip type of composite object */
! 5241: sp->size = size; /* and set font size */
! 5242: /* -------------------------------------------------------------------------
! 5243: free unneeded component subrasters and return final result to caller
! 5244: -------------------------------------------------------------------------- */
! 5245: end_of_job:
! 5246: return ( sp );
! 5247: } /* --- end-of-function rastdispmath() --- */
! 5248:
! 5249:
! 5250: /* ==========================================================================
! 5251: * Function: rastleft ( expression, size, basesp, ildelim, arg2, arg3 )
! 5252: * Purpose: \left...\right handler, returns a subraster corresponding to
! 5253: * delimited subexpression at font size
! 5254: * --------------------------------------------------------------------------
! 5255: * Arguments: expression (I) char ** to first char of null-terminated
! 5256: * string beginning with a \left
! 5257: * to be rasterized
! 5258: * size (I) int containing 0-5 default font size
! 5259: * basesp (I) subraster * to character (or subexpression)
! 5260: * immediately preceding leading left{
! 5261: * (unused, but passed for consistency)
! 5262: * ildelim (I) int containing ldelims index of
! 5263: * left delimiter
! 5264: * arg2 (I) int unused
! 5265: * arg3 (I) int unused
! 5266: * --------------------------------------------------------------------------
! 5267: * Returns: ( subraster * ) ptr to subraster corresponding to subexpr,
! 5268: * or NULL for any parsing error
! 5269: * --------------------------------------------------------------------------
! 5270: * Notes: o
! 5271: * ======================================================================= */
! 5272: /* --- entry point --- */
! 5273: subraster *rastleft ( char **expression, int size, subraster *basesp,
! 5274: int ildelim, int arg2, int arg3 )
! 5275: {
! 5276: /* -------------------------------------------------------------------------
! 5277: Allocations and Declarations
! 5278: -------------------------------------------------------------------------- */
! 5279: subraster *rasterize(), *sp=NULL; /*rasterize between \left...\right*/
! 5280: subraster *get_delim(), *lp=NULL, *rp=NULL; /* left and right delim chars */
! 5281: subraster *rastlimits(); /*handle sub/super scripts on lp,rp*/
! 5282: subraster *rastcat(); /* concat lp||sp||rp subrasters */
! 5283: int family=CMSYEX, /* get_delim() family */
! 5284: height=0, rheight=0, /* subexpr, right delim height */
! 5285: margin=(size+1), /* delim height margin over subexpr*/
! 5286: opmargin=(5); /* extra margin for \int,\sum,\etc */
! 5287: char subexpr[8192]; /* chars between \left...\right */
! 5288: char *texchar(), /* get delims after \left,\right */
! 5289: ldelim[256]=".", rdelim[256]="."; /* delims following \left,\right */
! 5290: char *strtexchr(), *pleft, *pright; /*locate \right matching our \left*/
! 5291: int isleftdot=0, isrightdot=0; /* true if \left. or \right. */
! 5292: int sublen=0; /* strlen(subexpr) */
! 5293: int idelim=0; /* 1=left,2=right */
! 5294: int delete_subraster(); /* free subraster if rastleft fails*/
! 5295: int wasdisplaystyle = isdisplaystyle; /* save current displaystyle */
! 5296: /* --- recognized delimiters --- */
! 5297: static char left[16]="\\left", right[16]="\\right"; /* tex delimiters */
! 5298: static char *ldelims[] = {
! 5299: "unused", ".", /* 1 for \left., \right. */
! 5300: "(", ")", /* 2,3 for \left(, \right) */
! 5301: "\\{","\\}", /* 4,5 for \left\{, \right\} */
! 5302: "[", "]", /* 6,7 for \left[, \right] */
! 5303: "<", ">", /* 8,9 for \left<, \right> */
! 5304: "|", "\\|", /* 10,11 for \left,\right |,\|*/
! 5305: NULL };
! 5306: /* --- recognized operator delimiters --- */
! 5307: static char *opdelims[] = { /* operator delims from cmex10 */
! 5308: "int", "sum", "prod",
! 5309: "cup", "cap", "dot",
! 5310: "plus", "times", "wedge",
! 5311: "vee",
! 5312: NULL }; /* --- end-of-opdelims[] --- */
! 5313: /* --- delimiter xlation --- */
! 5314: static char *xfrom[] = /* xlate any delim suffix... */
! 5315: { "\\|", /* \| */
! 5316: "\\{", /* \{ */
! 5317: "\\}", /* \} */
! 5318: "\\lbrace", /* \lbrace */
! 5319: "\\rbrace", /* \rbrace */
! 5320: "\\langle", /* \langle */
! 5321: "\\rangle", /* \rangle */
! 5322: NULL } ; /* --- end-of-xfrom[] --- */
! 5323: static char *xto[] = /* ...to this instead */
! 5324: { "=", /* \| to = */
! 5325: "{", /* \{ to { */
! 5326: "}", /* \} to } */
! 5327: "{", /* \lbrace to { */
! 5328: "}", /* \rbrace to } */
! 5329: "<", /* \langle to < */
! 5330: ">", /* \rangle to > */
! 5331: NULL } ; /* --- end-of-xto[] --- */
! 5332: /* -------------------------------------------------------------------------
! 5333: initialization
! 5334: -------------------------------------------------------------------------- */
! 5335: /* --- check args --- */
! 5336: if ( *(*expression) == '\000' ) goto end_of_job; /* nothing after \left */
! 5337: /* --- determine left delimiter, and set default \right. delimiter --- */
! 5338: if ( ildelim!=NOVALUE && ildelim>=1 ) /* called with explicit left delim */
! 5339: strcpy(ldelim,ldelims[ildelim]); /* so just get a local copy */
! 5340: else /* trapped \left without delim */
! 5341: { skipwhite(*expression); /* interpret \left ( as \left( */
! 5342: *expression = texchar(*expression,ldelim); } /*pull delim from expression*/
! 5343: strcpy(rdelim,"."); /* init default \right. delim */
! 5344: /* -------------------------------------------------------------------------
! 5345: locate \right balancing our opening \left
! 5346: -------------------------------------------------------------------------- */
! 5347: /* --- first \right following \left --- */
! 5348: if ( (pright=strtexchr(*expression,right)) /* look for \right after \left */
! 5349: != NULL ) { /* found it */
! 5350: /* --- find matching \right by pushing past any nested \left's --- */
! 5351: pleft = *expression; /* start after first \left( */
! 5352: while ( 1 ) { /*break when matching \right found*/
! 5353: /* -- locate next nested \left if there is one --- */
! 5354: if ( (pleft=strtexchr(pleft,left)) /* find next \left */
! 5355: == NULL ) break; /*no more, so matching \right found*/
! 5356: pleft += strlen(left); /* push ptr past \left token */
! 5357: if ( pleft >= pright ) break; /* not nested if \left after \right*/
! 5358: /* --- have nested \left, so push forward to next \right --- */
! 5359: if ( (pright=strtexchr(pright+strlen(right),right)) /* find next \right */
! 5360: == NULL ) break; /* ran out of \right's */
! 5361: } /* --- end-of-while(1) --- */
! 5362: } /* --- end-of-if(pright!=NULL) --- */
! 5363: /* -------------------------------------------------------------------------
! 5364: push past \left(_a^b sub/superscripts, if present
! 5365: -------------------------------------------------------------------------- */
! 5366: pleft = *expression; /*reset pleft after opening \left( */
! 5367: /*lp=*/ rastlimits(expression,size,lp); /*dummy call push expression past b*/
! 5368: /* -------------------------------------------------------------------------
! 5369: get \right delimiter and subexpression between \left...\right, xlate delims
! 5370: -------------------------------------------------------------------------- */
! 5371: /* --- get delimiter following \right --- */
! 5372: if ( pright == (char *)NULL ) { /* assume \right. at end of exprssn*/
! 5373: strcpy(rdelim,"."); /* set default \right. */
! 5374: sublen = strlen(*expression); /* use entire remaining expression */
! 5375: memcpy(subexpr,*expression,sublen); /* copy all remaining chars */
! 5376: *expression += sublen; } /* and push expression to its null */
! 5377: else { /* have explicit matching \right */
! 5378: sublen = (int)(pright-(*expression)); /* #chars between \left...\right */
! 5379: memcpy(subexpr,*expression,sublen); /* copy chars preceding \right */
! 5380: *expression = pright+strlen(right); /* push expression past \right */
! 5381: skipwhite(*expression); /* interpret \right ) as \right) */
! 5382: *expression = texchar(*expression,rdelim); /*pull delim from expression*/
! 5383: if ( *rdelim == '\000' ) strcpy(rdelim,"."); } /* \right. if no rdelim */
! 5384: /* --- get subexpression between \left...\right --- */
! 5385: if ( sublen < 1 ) goto end_of_job; /* nothing between delimiters */
! 5386: subexpr[sublen] = '\000'; /* and null-terminate it */
! 5387: /* --- check for operator delimiter --- */
! 5388: for ( idelim=0; opdelims[idelim]!=NULL; idelim++ )
! 5389: if ( strstr(ldelim,opdelims[idelim]) != NULL ) /* found operator */
! 5390: { margin += opmargin; /* extra height for operator */
! 5391: if ( *ldelim == '\\' ) /* have leading escape */
! 5392: strcpy(ldelim,ldelim+1); /* squeeze it out */
! 5393: break; } /* no need to check rest of table */
! 5394: /* --- xlate delimiters --- */
! 5395: for ( idelim=1; idelim<=2; idelim++ ) { /* 1=left, 2=right */
! 5396: char *lrdelim = (idelim==1? ldelim:rdelim); /* ldelim or rdelim */
! 5397: int ix; char *xdelim; /* xfrom[] and xto[] index, delim */
! 5398: for( ix=0; (xdelim=xfrom[ix]) != NULL; ix++ )
! 5399: if ( strcmp(lrdelim,xdelim) == 0 ) /* found delim to xlate */
! 5400: { strcpy(lrdelim,xto[ix]); /* replace with corresponding xto[]*/
! 5401: break; } /* no need to check further */
! 5402: } /* --- end-of-for(idelim) --- */
! 5403: /* --- debugging --- */
! 5404: if ( msgfp!=NULL && msglevel>=99 )
! 5405: fprintf(msgfp,"rastleft> left=\"%s\" right=\"%s\" subexpr=\"%s\"\n",
! 5406: ldelim,rdelim,subexpr);
! 5407: /* -------------------------------------------------------------------------
! 5408: rasterize subexpression
! 5409: -------------------------------------------------------------------------- */
! 5410: /* --- rasterize subexpression --- */
! 5411: if ( (sp = rasterize(subexpr,size)) /* rasterize chars between delims */
! 5412: == NULL ) goto end_of_job; /* quit if failed */
! 5413: height = (sp->image)->height; /* height of subexpr raster */
! 5414: rheight = height+margin; /*default rheight as subexpr height*/
! 5415: /* -------------------------------------------------------------------------
! 5416: rasterize delimiters, reset baselines, and add sub/superscripts if present
! 5417: -------------------------------------------------------------------------- */
! 5418: /* --- check for dot delimiter --- */
! 5419: isleftdot = (strchr(ldelim,'.')!=NULL); /* true if \left. */
! 5420: isrightdot = (strchr(rdelim,'.')!=NULL); /* true if \right. */
! 5421: /* --- get rasters for best-fit delim characters, add sub/superscripts --- */
! 5422: isdisplaystyle = 9; /* force \displaystyle */
! 5423: if ( !isleftdot ) /* if not \left. */
! 5424: { /* --- first get requested \left delimiter --- */
! 5425: lp = get_delim(ldelim,rheight,family); /* get \left delim char */
! 5426: /* --- reset lp delim baseline to center delim on subexpr raster --- */
! 5427: if ( lp != NULL ) /* if get_delim() succeeded */
! 5428: { int lheight = (lp->image)->height; /* actual height of left delim */
! 5429: lp->baseline = sp->baseline + (lheight - height)/2;
! 5430: if ( lheight > rheight ) /* got bigger delim than requested */
! 5431: rheight = lheight-1; } /* make sure right delim matches */
! 5432: /* --- then add on any sub/superscripts attached to \left( --- */
! 5433: lp = rastlimits(&pleft,size,lp); } /*\left(_a^b and push pleft past b*/
! 5434: isdisplaystyle = 9; /* force \displaystyle */
! 5435: if ( !isrightdot ) /* and if not \right. */
! 5436: { /* --- first get requested \right delimiter --- */
! 5437: rp = get_delim(rdelim,rheight,family); /* get \right delim char */
! 5438: /* --- reset rp delim baseline to center delim on subexpr raster --- */
! 5439: if ( rp != NULL ) /* if get_delim() succeeded */
! 5440: rp->baseline = sp->baseline + ((rp->image)->height - height)/2;
! 5441: /* --- then add on any sub/superscripts attached to \right) --- */
! 5442: rp = rastlimits(expression,size,rp); } /*\right)_c^d, expression past d*/
! 5443: isdisplaystyle = wasdisplaystyle; /* original \displystyle default */
! 5444: /* --- check that we got delimiters --- */
! 5445: if ( 0 )
! 5446: if ( (lp==NULL && !isleftdot) /* check that we got left( */
! 5447: || (rp==NULL && !isrightdot) ) /* and right) if needed */
! 5448: { if ( lp != NULL ) free ((void *)lp); /* free \left-delim subraster */
! 5449: if ( rp != NULL ) free ((void *)rp); /* and \right-delim subraster */
! 5450: if (0) { delete_subraster(sp); /* if failed, free subraster */
! 5451: sp = (subraster *)NULL; } /* signal error to caller */
! 5452: goto end_of_job; } /* and quit */
! 5453: /* -------------------------------------------------------------------------
! 5454: concat lp || sp || rp components
! 5455: -------------------------------------------------------------------------- */
! 5456: /* --- concat lp||sp||rp to obtain final result --- */
! 5457: if ( lp != NULL ) /* ignore \left. */
! 5458: sp = rastcat(lp,sp,3); /* concat lp||sp and free sp,lp */
! 5459: if ( sp != NULL ) /* succeeded or ignored \left. */
! 5460: if ( rp != NULL ) /* ignore \right. */
! 5461: sp = rastcat(sp,rp,3); /* concat sp||rp and free sp,rp */
! 5462: /* --- back to caller --- */
! 5463: end_of_job:
! 5464: return ( sp );
! 5465: } /* --- end-of-function rastleft() --- */
! 5466:
! 5467:
! 5468: /* ==========================================================================
! 5469: * Function: rastflags ( expression, size, basesp, flag, value, arg3 )
! 5470: * Purpose: sets an internal flag, e.g., for \rm, or sets an internal
! 5471: * value, e.g., for \unitlength=<value>, and returns NULL
! 5472: * so nothing is displayed
! 5473: * --------------------------------------------------------------------------
! 5474: * Arguments: expression (I) char ** to first char of null-terminated
! 5475: * LaTeX expression (unused/unchanged)
! 5476: * size (I) int containing base font size (not used,
! 5477: * just stored in subraster)
! 5478: * basesp (I) subraster * to character (or subexpression)
! 5479: * immediately preceding space, whose baseline
! 5480: * and height params are transferred to space
! 5481: * flag (I) int containing #define'd symbol specifying
! 5482: * internal flag to be set
! 5483: * value (I) int containing new value of flag
! 5484: * arg3 (I) int unused
! 5485: * --------------------------------------------------------------------------
! 5486: * Returns: ( subraster * ) NULL so nothing is displayed
! 5487: * --------------------------------------------------------------------------
! 5488: * Notes: o
! 5489: * ======================================================================= */
! 5490: /* --- entry point --- */
! 5491: subraster *rastflags ( char **expression, int size, subraster *basesp,
! 5492: int flag, int value, int arg3 )
! 5493: {
! 5494: /* -------------------------------------------------------------------------
! 5495: Allocations and Declarations
! 5496: -------------------------------------------------------------------------- */
! 5497: char *texsubexpr(), /* parse expression for... */
! 5498: valuearg[1024]="NOVALUE"; /* value from expression, if needed */
! 5499: int argvalue=NOVALUE, /* atoi(valuearg) */
! 5500: isdelta=0, /* true if + or - precedes valuearg */
! 5501: valuelen=0; /* strlen(valuearg) */
! 5502: double strtod(); /*convert ascii {valuearg} to double*/
! 5503: static int displaystylelevel = (-99); /* \displaystyle set at recurlevel */
! 5504: /* -------------------------------------------------------------------------
! 5505: set flag or value
! 5506: -------------------------------------------------------------------------- */
! 5507: switch ( flag )
! 5508: {
! 5509: default: break; /* unrecognized flag */
! 5510: case ISTEXT:
! 5511: if ( isthischar((*(*expression)),WHITEMATH) ) /* \rm followed by white */
! 5512: (*expression)++; /* skip leading ~ after \rm */
! 5513: istext=value; /* set text mode */
! 5514: break;
! 5515: case ISSTRING: isstring=value; break; /* set string/image mode */
! 5516: case ISDISPLAYSTYLE: /* set \displaystyle mode */
! 5517: displaystylelevel = recurlevel; /* \displaystyle set at recurlevel */
! 5518: isdisplaystyle=value; break;
! 5519: case ISOPAQUE: istransparent=value; break; /* set transparent/opaque */
! 5520: case ISREVERSE: /* reverse video */
! 5521: if ( value==1 || value==NOVALUE )
! 5522: { fgred=255-fgred; fggreen=255-fggreen; fgblue=255-fgblue; }
! 5523: if ( value==2 || value==NOVALUE )
! 5524: { bgred=255-bgred; bggreen=255-bggreen; bgblue=255-bgblue; }
! 5525: if ( value==2 || value==NOVALUE )
! 5526: isblackonwhite = !isblackonwhite;
! 5527: break;
! 5528: case ISSUPER: /* set supersampling/lowpass flag */
! 5529: #ifndef SSFONTS /* don't have ss fonts loaded */
! 5530: value = 0; /* so force lowpass */
! 5531: #endif
! 5532: isss = issupersampling = value;
! 5533: fonttable = (issupersampling?ssfonttable:aafonttable); /* set fonts */
! 5534: break;
! 5535: case ISFONTSIZE: /* set fontsize */
! 5536: case ISDISPLAYSIZE: /* set displaysize */
! 5537: case ISSHRINK: /* set shrinkfactor */
! 5538: case ISAAALGORITHM: /* set anti-aliasing algorithm */
! 5539: case ISWEIGHT: /* set font weight */
! 5540: case ISCENTERWT: /* set lowpass center pixel weight */
! 5541: case ISADJACENTWT: /* set lowpass adjacent weight */
! 5542: case ISCORNERWT: /* set lowpass corner weight */
! 5543: case ISCOLOR: /* set red(1),green(2),blue(3) */
! 5544: case ISSQUASH: /* set (minimum) "squash" margin */
! 5545: if ( value != NOVALUE ) /* passed a fixed value to be set */
! 5546: argvalue = value; /* set given fixed value */
! 5547: else /* get value from expression */
! 5548: { *expression = texsubexpr(*expression,valuearg,1023,"{","}",0,0);
! 5549: if ( *valuearg != '\000' ) /* guard against empty string */
! 5550: if ( !isalpha(*valuearg) ) /* and against alpha string args */
! 5551: if ( !isthischar(*valuearg,"?") ) /*leading ? is query for value*/
! 5552: { isdelta = isthischar(*valuearg,"+-"); /* leading + or - */
! 5553: if ( memcmp(valuearg,"--",2) == 0 ) /* leading -- signals...*/
! 5554: { isdelta=0; strcpy(valuearg,valuearg+1); } /* ...not delta */
! 5555: argvalue = atoi(valuearg); } } /* convert to int */
! 5556: switch ( flag )
! 5557: {
! 5558: default: break;
! 5559: case ISCOLOR: /* set color */
! 5560: slower(valuearg); /* convert arg to lower case */
! 5561: if ( argvalue==1 || strstr(valuearg,"red") )
! 5562: { fggreen = fgblue = (isblackonwhite?0:255);
! 5563: fgred = (isblackonwhite?255:0); }
! 5564: if ( argvalue==2 || strstr(valuearg,"green") )
! 5565: { fgred = fgblue = (isblackonwhite?0:255);
! 5566: fggreen = (isblackonwhite?255:0); }
! 5567: if ( argvalue==3 || strstr(valuearg,"blue") )
! 5568: { fgred = fggreen = (isblackonwhite?0:255);
! 5569: fgblue = (isblackonwhite?255:0); }
! 5570: if ( argvalue==0 || strstr(valuearg,"black") )
! 5571: fgred = fggreen = fgblue = (isblackonwhite?0:255);
! 5572: if ( argvalue==7 || strstr(valuearg,"white") )
! 5573: fgred = fggreen = fgblue = (isblackonwhite?255:0);
! 5574: break;
! 5575: case ISFONTSIZE: /* set fontsize */
! 5576: if ( argvalue != NOVALUE ) /* got a value */
! 5577: { int largestsize = (issupersampling?16:LARGESTSIZE);
! 5578: fontsize = (isdelta? fontsize+argvalue : argvalue);
! 5579: fontsize = max2(0,min2(fontsize,largestsize));
! 5580: shrinkfactor = shrinkfactors[fontsize];
! 5581: if ( isdisplaystyle == 1 ) /* displaystyle enabled but not set*/
! 5582: if ( displaystylelevel != recurlevel ) /*respect \displaystyle*/
! 5583: if ( !ispreambledollars ) /* respect $$...$$'s */
! 5584: isdisplaystyle = (fontsize>=displaysize? 2:1); /* forced */
! 5585: /*displaystylelevel = (-99);*/ } /* reset \displaystyle level */
! 5586: else /* embed font size in expression */
! 5587: { sprintf(valuearg,"%d",fontsize); /* convert size */
! 5588: valuelen = strlen(valuearg); /* ought to be 1 */
! 5589: if ( *expression != '\000' ) /* ill-formed expression */
! 5590: { *expression = (char *)(*expression-valuelen); /*back up buff*/
! 5591: memcpy(*expression,valuearg,valuelen); } } /*and put in size*/
! 5592: break;
! 5593: case ISDISPLAYSIZE: /* set displaysize */
! 5594: if ( argvalue != NOVALUE ) /* got a value */
! 5595: displaysize = (isdelta? displaysize+argvalue : argvalue);
! 5596: break;
! 5597: case ISSQUASH: /* set (minimum) "squash" margin */
! 5598: if ( argvalue != NOVALUE ) /* got a value */
! 5599: { squashmargin = argvalue; /* set value */
! 5600: if ( arg3 != NOVALUE ) isdelta=arg3; /* hard-coded isdelta */
! 5601: issquashdelta = (isdelta?1:0); } /* and set delta flag */
! 5602: squashmargin = max2((isdelta?-5:0),min2(squashmargin,32)); /*sanity*/
! 5603: break;
! 5604: case ISSHRINK: /* set shrinkfactor */
! 5605: if ( argvalue != NOVALUE ) /* got a value */
! 5606: shrinkfactor = (isdelta? shrinkfactor+argvalue : argvalue);
! 5607: shrinkfactor = max2(1,min2(shrinkfactor,27)); /* sanity check */
! 5608: break;
! 5609: case ISAAALGORITHM: /* set anti-aliasing algorithm */
! 5610: if ( argvalue != NOVALUE ) /* got a value */
! 5611: aaalgorithm = argvalue; /* set algorithm number */
! 5612: aaalgorithm = max2(0,min2(aaalgorithm,3)); /* bounds check */
! 5613: break;
! 5614: case ISWEIGHT: /* set font weight number */
! 5615: value = (argvalue==NOVALUE? NOVALUE : /* don't have a value */
! 5616: (isdelta? weightnum+argvalue : argvalue));
! 5617: if ( value>=0 && value<maxaaparams ) /* in range */
! 5618: { weightnum = value; /* reset weightnum index */
! 5619: minadjacent = aaparams[weightnum].minadjacent;
! 5620: maxadjacent = aaparams[weightnum].maxadjacent;
! 5621: cornerwt = aaparams[weightnum].cornerwt;
! 5622: adjacentwt = aaparams[weightnum].adjacentwt;
! 5623: centerwt = aaparams[weightnum].centerwt;
! 5624: fgalias = aaparams[weightnum].fgalias;
! 5625: fgonly = aaparams[weightnum].fgonly;
! 5626: bgalias = aaparams[weightnum].bgalias;
! 5627: bgonly = aaparams[weightnum].bgonly; }
! 5628: break;
! 5629: case ISCENTERWT: /* set lowpass center pixel weight */
! 5630: if ( argvalue != NOVALUE ) /* got a value */
! 5631: centerwt = argvalue; /* set lowpass center weight */
! 5632: break;
! 5633: case ISADJACENTWT: /* set lowpass adjacent weight */
! 5634: if ( argvalue != NOVALUE ) /* got a value */
! 5635: adjacentwt = argvalue; /* set lowpass adjacent weight */
! 5636: break;
! 5637: case ISCORNERWT: /* set lowpass corner weight */
! 5638: if ( argvalue != NOVALUE ) /* got a value */
! 5639: cornerwt = argvalue; /* set lowpass corner weight */
! 5640: break;
! 5641: } /* --- end-of-switch() --- */
! 5642: break;
! 5643: case PNMPARAMS: /*set fgalias,fgonly,bgalias,bgonly*/
! 5644: *expression = texsubexpr(*expression,valuearg,1023,"{","}",0,0);
! 5645: valuelen = strlen(valuearg); /* ought to be 1-4 */
! 5646: if ( valuelen>0 && isthischar(toupper(valuearg[0]),"TY1") ) fgalias=1;
! 5647: if ( valuelen>0 && isthischar(toupper(valuearg[0]),"FN0") ) fgalias=0;
! 5648: if ( valuelen>1 && isthischar(toupper(valuearg[1]),"TY1") ) fgonly =1;
! 5649: if ( valuelen>1 && isthischar(toupper(valuearg[1]),"FN0") ) fgonly =0;
! 5650: if ( valuelen>2 && isthischar(toupper(valuearg[2]),"TY1") ) bgalias=1;
! 5651: if ( valuelen>2 && isthischar(toupper(valuearg[2]),"FN0") ) bgalias=0;
! 5652: if ( valuelen>3 && isthischar(toupper(valuearg[3]),"TY1") ) bgonly =1;
! 5653: if ( valuelen>3 && isthischar(toupper(valuearg[3]),"FN0") ) bgonly =0;
! 5654: break;
! 5655: case UNITLENGTH:
! 5656: if ( value != NOVALUE ) /* passed a fixed value to be set */
! 5657: unitlength = (double)(value); /* set given fixed value */
! 5658: else /* get value from expression */
! 5659: { *expression = texsubexpr(*expression,valuearg,1023,"{","}",0,0);
! 5660: if ( *valuearg != '\000' ) /* guard against empty string */
! 5661: unitlength = strtod(valuearg,NULL); } /* convert to double */
! 5662: break;
! 5663: } /* --- end-of-switch(flag) --- */
! 5664: return ( NULL ); /*just set value, nothing to display*/
! 5665: } /* --- end-of-function rastflags() --- */
! 5666:
! 5667:
! 5668: /* ==========================================================================
! 5669: * Function: rastspace(expression, size, basesp, width, isfill, isheight)
! 5670: * Purpose: returns a blank/space subraster width wide,
! 5671: * with baseline and height corresponding to basep
! 5672: * --------------------------------------------------------------------------
! 5673: * Arguments: expression (I) char ** to first char of null-terminated
! 5674: * LaTeX expression (unused/unchanged)
! 5675: * size (I) int containing base font size (not used,
! 5676: * just stored in subraster)
! 5677: * basesp (I) subraster * to character (or subexpression)
! 5678: * immediately preceding space, whose baseline
! 5679: * and height params are transferred to space
! 5680: * width (I) int containing #bits/pixels for space width
! 5681: * isfill (I) int containing true to \hfill complete
! 5682: * expression out to width
! 5683: * isheight (I) int containing true (but not NOVALUE)
! 5684: * to treat width arg as height
! 5685: * --------------------------------------------------------------------------
! 5686: * Returns: ( subraster * ) ptr to empty/blank subraster
! 5687: * or NULL for any error
! 5688: * --------------------------------------------------------------------------
! 5689: * Notes: o
! 5690: * ======================================================================= */
! 5691: /* --- entry point --- */
! 5692: subraster *rastspace ( char **expression, int size, subraster *basesp,
! 5693: int width, int isfill, int isheight )
! 5694: {
! 5695: /* -------------------------------------------------------------------------
! 5696: Allocations and Declarations
! 5697: -------------------------------------------------------------------------- */
! 5698: subraster *new_subraster(), *spacesp=NULL; /* subraster for space */
! 5699: int baseht=1, baseln=0; /* height,baseline of base symbol */
! 5700: int pixsz = 1; /*default #bits per pixel, 1=bitmap*/
! 5701: char *texsubexpr(), widtharg[256]; /* parse for optional {width} */
! 5702: subraster *rasterize(), *rightsp=NULL; /*rasterize right half of expression*/
! 5703: subraster *rastcat(); /* cat rightsp after \hfill */
! 5704: int blanksignal = (-991234); /*rastsquash signal right-hand blank*/
! 5705: /* -------------------------------------------------------------------------
! 5706: initialization
! 5707: -------------------------------------------------------------------------- */
! 5708: if ( isfill == NOVALUE ) isfill=0; /* novalue means false */
! 5709: if ( isheight == NOVALUE ) isheight=0; /* novalue means false */
! 5710: /* -------------------------------------------------------------------------
! 5711: determine width if not given (e.g., \hspace{width}, \hfill{width})
! 5712: -------------------------------------------------------------------------- */
! 5713: if ( width <= 0 ) /* width specified in expression */
! 5714: { int widthval; /* test {width} before using it */
! 5715: width = 1; /* set default width */
! 5716: *expression = texsubexpr(*expression,widtharg,255,"{","}",0,0);
! 5717: widthval = /* convert {width} to integer */
! 5718: (int)((unitlength*strtod(widtharg,NULL))+0.5);
! 5719: if ( widthval>=2 && widthval<=600 ) /* sanity check */
! 5720: width = widthval; } /* replace deafault width */
! 5721: /* -------------------------------------------------------------------------
! 5722: see if width is "absolute" or fill width
! 5723: -------------------------------------------------------------------------- */
! 5724: if ( isfill /* called as \hfill{} */
! 5725: && !isheight ) /* parameter conflict */
! 5726: { if ( leftexpression != NULL ) /* if we have left half */
! 5727: width -= (leftexpression->image)->width; /*reduce left width from total*/
! 5728: if ( (rightsp=rasterize(*expression,size)) /* rasterize right half */
! 5729: != NULL ) /* succeeded */
! 5730: width -= (rightsp->image)->width; } /* reduce right width from total */
! 5731: /* -------------------------------------------------------------------------
! 5732: construct blank subraster, and return it to caller
! 5733: -------------------------------------------------------------------------- */
! 5734: /* --- get parameters from base symbol --- */
! 5735: if ( basesp != (subraster *)NULL ) /* we have base symbol for space */
! 5736: { baseht = (basesp->image)->height; /* height of base symbol */
! 5737: baseln = basesp->baseline; } /* and its baseline */
! 5738: /* --- flip params for height --- */
! 5739: if ( isheight ) /* width is actually height */
! 5740: { baseht = width; /* use given width as height */
! 5741: width = 1; } /* and set default width */
! 5742: /* --- generate and init space subraster --- */
! 5743: if ( width > 0 ) /*make sure we have positive width*/
! 5744: if ( (spacesp=new_subraster(width,baseht,pixsz)) /*generate space subraster*/
! 5745: != NULL ) /* and if we succeed... */
! 5746: { /* --- ...re-init subraster parameters --- */
! 5747: spacesp->size = size; /*propagate base font size forward*/
! 5748: spacesp->baseline = baseln; } /* ditto baseline */
! 5749: /* -------------------------------------------------------------------------
! 5750: concat right half if \hfill-ing
! 5751: -------------------------------------------------------------------------- */
! 5752: if ( rightsp != NULL ) /* we have a right half after fill */
! 5753: { spacesp = (spacesp==NULL? rightsp: /* no space, so just use right half*/
! 5754: rastcat(spacesp,rightsp,3)); /* or cat right half after space */
! 5755: spacesp->type = blanksignal; /* need to propagate blanks */
! 5756: *expression += strlen((*expression)); } /* push expression to its null */
! 5757: return ( spacesp );
! 5758: } /* --- end-of-function rastspace() --- */
! 5759:
! 5760:
! 5761: /* ==========================================================================
! 5762: * Function: rastnewline ( expression, size, basesp, arg1, arg2, arg3 )
! 5763: * Purpose: \\ handler, returns subraster corresponding to
! 5764: * left-hand expression preceding \\ above right-hand expression
! 5765: * --------------------------------------------------------------------------
! 5766: * Arguments: expression (I/O) char ** to first char of null-terminated
! 5767: * string immediately following \\ to be
! 5768: * rasterized, and returning ptr immediately
! 5769: * to terminating null.
! 5770: * size (I) int containing 0-4 default font size
! 5771: * basesp (I) subraster * to character (or subexpression)
! 5772: * immediately preceding \accent
! 5773: * (unused, but passed for consistency)
! 5774: * arg1 (I) int unused
! 5775: * arg2 (I) int unused
! 5776: * arg3 (I) int unused
! 5777: * --------------------------------------------------------------------------
! 5778: * Returns: ( subraster * ) ptr to subraster corresponding to expression,
! 5779: * or NULL for any parsing error
! 5780: * (expression ptr unchanged if error occurs)
! 5781: * --------------------------------------------------------------------------
! 5782: * Notes: o
! 5783: * ======================================================================= */
! 5784: /* --- entry point --- */
! 5785: subraster *rastnewline ( char **expression, int size, subraster *basesp,
! 5786: int arg1, int arg2, int arg3 )
! 5787: {
! 5788: /* -------------------------------------------------------------------------
! 5789: Allocations and Declarations
! 5790: -------------------------------------------------------------------------- */
! 5791: subraster *rastack(), *newlsp=NULL; /* subraster for both lines */
! 5792: subraster *rasterize(), *rightsp=NULL; /*rasterize right half of expression*/
! 5793: char *texsubexpr(), spacexpr[129]/*, *xptr=spacexpr*/; /*for \\[vspace]*/
! 5794: double strtod(); /* convert ascii param to double */
! 5795: int vspace = size+2; /* #pixels between lines */
! 5796: /* -------------------------------------------------------------------------
! 5797: obtain optional [vspace] argument immediately following \\ command
! 5798: -------------------------------------------------------------------------- */
! 5799: /* --- check if [vspace] given --- */
! 5800: if ( *(*expression) == '[' ) /*have [vspace] if leading char is [*/
! 5801: {
! 5802: /* ---parse [vspace] and bump expression past it, interpret as double--- */
! 5803: *expression = texsubexpr(*expression,spacexpr,127,"[","]",0,0);
! 5804: if ( *spacexpr == '\000' ) goto end_of_job; /* couldn't get [vspace] */
! 5805: vspace = iround(unitlength*strtod(spacexpr,NULL)); /* vspace in pixels */
! 5806: } /* --- end-of-if(*(*expression)=='[') --- */
! 5807: if ( leftexpression == NULL ) goto end_of_job; /* nothing preceding \\ */
! 5808: /* -------------------------------------------------------------------------
! 5809: rasterize right half of expression and stack left half above it
! 5810: -------------------------------------------------------------------------- */
! 5811: /* --- rasterize right half --- */
! 5812: if ( (rightsp=rasterize(*expression,size)) /* rasterize right half */
! 5813: == NULL ) goto end_of_job; /* quit if failed */
! 5814: /* --- stack left half above it --- */
! 5815: newlsp = rastack(rightsp,leftexpression,1,vspace,0,3); /*right under left*/
! 5816: /* --- back to caller --- */
! 5817: end_of_job:
! 5818: if ( newlsp != NULL ) /* returning entire expression */
! 5819: { int newht = (newlsp->image)->height; /* height of returned subraster */
! 5820: newlsp->baseline = min2(newht-1,newht/2+5); /* guess new baseline */
! 5821: isreplaceleft = 1; /* so set flag to replace left half*/
! 5822: *expression += strlen(*expression); } /* and push to terminating null*/
! 5823: return ( newlsp ); /* 1st line over 2nd, or null=error*/
! 5824: } /* --- end-of-function rastnewline() --- */
! 5825:
! 5826:
! 5827: /* ==========================================================================
! 5828: * Function: rastarrow ( expression, size, basesp, drctn, isBig, arg3 )
! 5829: * Purpose: returns left/right arrow subraster (e.g., for \longrightarrow)
! 5830: * --------------------------------------------------------------------------
! 5831: * Arguments: expression (I) char ** to first char of null-terminated
! 5832: * LaTeX expression (unused/unchanged)
! 5833: * size (I) int containing base font size (not used,
! 5834: * just stored in subraster)
! 5835: * basesp (I) subraster * to character (or subexpression)
! 5836: * immediately preceding space, whose baseline
! 5837: * and height params are transferred to space
! 5838: * drctn (I) int containing +1 for right, -1 for left,
! 5839: * or 0 for leftright
! 5840: * isBig (I) int containing 0 for ---> or 1 for ===>
! 5841: * arg3 (I) int unused
! 5842: * --------------------------------------------------------------------------
! 5843: * Returns: ( subraster * ) ptr to left/right arrow subraster
! 5844: * or NULL for any error
! 5845: * --------------------------------------------------------------------------
! 5846: * Notes: o An optional argument [width] may *immediately* follow
! 5847: * the \longxxx to explicitly set the arrow's width in pixels.
! 5848: * For example, \longrightarrow calculates a default width
! 5849: * (as usual in LaTeX), whereas \longrightarrow[50] explicitly
! 5850: * draws a 50-pixel long arrow. This can be used, e.g.,
! 5851: * to draw commutative diagrams in conjunction with
! 5852: * \array (and maybe with \stackrel and/or \relstack, too).
! 5853: * o In case you really want to render, say, [f]---->[g], just
! 5854: * use an intervening space, i.e., [f]\longrightarrow~[g].
! 5855: * In text mode use two spaces {\rm~[f]\longrightarrow~~[g]}.
! 5856: * ======================================================================= */
! 5857: /* --- entry point --- */
! 5858: subraster *rastarrow ( char **expression, int size, subraster *basesp,
! 5859: int drctn, int isBig, int arg3 )
! 5860: {
! 5861: /* -------------------------------------------------------------------------
! 5862: Allocations and Declarations
! 5863: -------------------------------------------------------------------------- */
! 5864: subraster *arrow_subraster(), *arrowsp=NULL; /* subraster for arrow */
! 5865: char *texsubexpr(), widtharg[256]; /* parse for optional [width] */
! 5866: char *texscripts(), sub[1024],super[1024]; /* and _^limits after [width]*/
! 5867: subraster *rasterize(), *subsp=NULL,*supsp=NULL; /*rasterize limits*/
! 5868: subraster *new_subraster(), *rastack(), *spacesp=NULL; /*space below arrow*/
! 5869: int delete_subraster(); /*free work areas in case of error*/
! 5870: double strtod(); /* convert ascii [width] to value */
! 5871: int width = 10 + 8*size, height; /* width, height for \longxxxarrow */
! 5872: int islimits = 1; /*true to handle limits internally*/
! 5873: int limsize = size-1; /* font size for limits */
! 5874: int vspace = 1; /* #empty rows below arrow */
! 5875: int pixsz = 1; /*default #bits per pixel, 1=bitmap*/
! 5876: /* -------------------------------------------------------------------------
! 5877: construct longleft/rightarrow subraster, with limits, and return it to caller
! 5878: -------------------------------------------------------------------------- */
! 5879: /* --- check for optional width arg and replace default width --- */
! 5880: if ( *(*expression) == '[' ) /*check for []-enclosed optional arg*/
! 5881: { int widthval; /* test [width] before using it */
! 5882: *expression = texsubexpr(*expression,widtharg,255,"[","]",0,0);
! 5883: widthval = /* convert [width] to integer */
! 5884: (int)((unitlength*strtod(widtharg,NULL))+0.5);
! 5885: if ( widthval>=2 && widthval<=600 ) /* sanity check */
! 5886: width = widthval; } /* replace deafault width */
! 5887: /* --- now parse for limits, and bump expression past it(them) --- */
! 5888: if ( islimits ) /* handling limits internally */
! 5889: { *expression = texscripts(*expression,sub,super,3); /* parse for limits */
! 5890: if ( *sub != '\000' ) /*have a subscript following arrow*/
! 5891: subsp = rasterize(sub,limsize); /* so try to rasterize subscript */
! 5892: if ( *super != '\000' ) /*have superscript following arrow*/
! 5893: supsp = rasterize(super,limsize); } /*so try to rasterize superscript*/
! 5894: /* --- set height based on width --- */
! 5895: height = min2(17,max2(9,(width+2)/6)); /* height based on width */
! 5896: height = 1 + (height/2)*2; /* always force odd height */
! 5897: /* --- generate arrow subraster --- */
! 5898: if ( (arrowsp=arrow_subraster(width,height,pixsz,drctn,isBig)) /*build arrow*/
! 5899: == NULL ) goto end_of_job; /* and quit if we failed */
! 5900: /* --- add space below arrow --- */
! 5901: if ( vspace > 0 ) /* if we have space below arrow */
! 5902: if ( (spacesp=new_subraster(width,vspace,pixsz)) /*allocate required space*/
! 5903: != NULL ) /* and if we succeeded */
! 5904: if ( (arrowsp = rastack(spacesp,arrowsp,2,0,1,3)) /* space below arrow */
! 5905: == NULL ) goto end_of_job; /* and quit if we failed */
! 5906: /* --- init arrow subraster parameters --- */
! 5907: arrowsp->size = size; /*propagate base font size forward*/
! 5908: arrowsp->baseline = height+vspace-1; /* set baseline at bottom of arrow */
! 5909: /* --- add limits above/below arrow, as necessary --- */
! 5910: if ( subsp != NULL ) /* stack subscript below arrow */
! 5911: if ( (arrowsp = rastack(subsp,arrowsp,2,0,1,3)) /* subscript below arrow */
! 5912: == NULL ) goto end_of_job; /* quit if failed */
! 5913: if ( supsp != NULL ) /* stack superscript above arrow */
! 5914: if ( (arrowsp = rastack(arrowsp,supsp,1,vspace,1,3)) /*supsc above arrow*/
! 5915: == NULL ) goto end_of_job; /* quit if failed */
! 5916: /* --- return arrow (or NULL) to caller --- */
! 5917: end_of_job:
! 5918: return ( arrowsp );
! 5919: } /* --- end-of-function rastarrow() --- */
! 5920:
! 5921:
! 5922: /* ==========================================================================
! 5923: * Function: rastuparrow ( expression, size, basesp, drctn, isBig, arg3 )
! 5924: * Purpose: returns an up/down arrow subraster (e.g., for \longuparrow)
! 5925: * --------------------------------------------------------------------------
! 5926: * Arguments: expression (I) char ** to first char of null-terminated
! 5927: * LaTeX expression (unused/unchanged)
! 5928: * size (I) int containing base font size (not used,
! 5929: * just stored in subraster)
! 5930: * basesp (I) subraster * to character (or subexpression)
! 5931: * immediately preceding space, whose baseline
! 5932: * and height params are transferred to space
! 5933: * drctn (I) int containing +1 for up, -1 for down,
! 5934: * or 0 for updown
! 5935: * isBig (I) int containing 0 for ---> or 1 for ===>
! 5936: * arg3 (I) int unused
! 5937: * --------------------------------------------------------------------------
! 5938: * Returns: ( subraster * ) ptr to up/down arrow subraster
! 5939: * or NULL for any error
! 5940: * --------------------------------------------------------------------------
! 5941: * Notes: o An optional argument [height] may *immediately* follow
! 5942: * the \longxxx to explicitly set the arrow's height in pixels.
! 5943: * For example, \longuparrow calculates a default height
! 5944: * (as usual in LaTeX), whereas \longuparrow[25] explicitly
! 5945: * draws a 25-pixel high arrow. This can be used, e.g.,
! 5946: * to draw commutative diagrams in conjunction with
! 5947: * \array (and maybe with \stackrel and/or \relstack, too).
! 5948: * o In case you really want to render, say, [f]---->[g], just
! 5949: * use an intervening space, i.e., [f]\longuparrow~[g].
! 5950: * In text use two spaces {\rm~[f]\longuparrow~~[g]}.
! 5951: * ======================================================================= */
! 5952: /* --- entry point --- */
! 5953: subraster *rastuparrow ( char **expression, int size, subraster *basesp,
! 5954: int drctn, int isBig, int arg3 )
! 5955: {
! 5956: /* -------------------------------------------------------------------------
! 5957: Allocations and Declarations
! 5958: -------------------------------------------------------------------------- */
! 5959: subraster *uparrow_subraster(), *arrowsp=NULL; /* subraster for arrow */
! 5960: char *texsubexpr(), heightarg[256]; /* parse for optional [height] */
! 5961: char *texscripts(), sub[1024],super[1024]; /* and _^limits after [width]*/
! 5962: subraster *rasterize(), *subsp=NULL,*supsp=NULL; /*rasterize limits*/
! 5963: subraster *rastcat(); /* cat superscript left, sub right */
! 5964: double strtod(); /* convert ascii [height] to value */
! 5965: int height = 8 + 2*size, width; /* height, width for \longxxxarrow */
! 5966: int islimits = 1; /*true to handle limits internally*/
! 5967: int limsize = size-1; /* font size for limits */
! 5968: int pixsz = 1; /*default #bits per pixel, 1=bitmap*/
! 5969: /* -------------------------------------------------------------------------
! 5970: construct blank subraster, and return it to caller
! 5971: -------------------------------------------------------------------------- */
! 5972: /* --- check for optional height arg and replace default height --- */
! 5973: if ( *(*expression) == '[' ) /*check for []-enclosed optional arg*/
! 5974: { int heightval; /* test height before using it */
! 5975: *expression = texsubexpr(*expression,heightarg,255,"[","]",0,0);
! 5976: heightval = /* convert [height] to integer */
! 5977: (int)((unitlength*strtod(heightarg,NULL))+0.5);
! 5978: if ( heightval>=2 && heightval<=600 ) /* sanity check */
! 5979: height = heightval; } /* replace deafault height */
! 5980: /* --- now parse for limits, and bump expression past it(them) --- */
! 5981: if ( islimits ) /* handling limits internally */
! 5982: { *expression = texscripts(*expression,sub,super,3); /* parse for limits */
! 5983: if ( *sub != '\000' ) /*have a subscript following arrow*/
! 5984: subsp = rasterize(sub,limsize); /* so try to rasterize subscript */
! 5985: if ( *super != '\000' ) /*have superscript following arrow*/
! 5986: supsp = rasterize(super,limsize); } /*so try to rasterize superscript*/
! 5987: /* --- set width based on height --- */
! 5988: width = min2(17,max2(9,(height+2)/4)); /* width based on height */
! 5989: width = 1 + (width/2)*2; /* always force odd width */
! 5990: /* --- generate arrow subraster --- */
! 5991: if ( (arrowsp=uparrow_subraster(width,height,pixsz,drctn,isBig)) /*build arr*/
! 5992: == NULL ) goto end_of_job; /* and quit if we failed */
! 5993: /* --- init arrow subraster parameters --- */
! 5994: arrowsp->size = size; /*propagate base font size forward*/
! 5995: arrowsp->baseline = height-1; /* set baseline at bottom of arrow */
! 5996: /* --- add limits above/below arrow, as necessary --- */
! 5997: if ( supsp != NULL ) /* cat superscript to left of arrow*/
! 5998: { int supht = (supsp->image)->height, /* superscript height */
! 5999: deltab = (1+abs(height-supht))/2; /* baseline difference to center */
! 6000: supsp->baseline = supht-1; /* force script baseline to bottom */
! 6001: if ( supht <= height ) /* arrow usually taller than script*/
! 6002: arrowsp->baseline -= deltab; /* so bottom of script goes here */
! 6003: else supsp->baseline -= deltab; /* else bottom of arrow goes here */
! 6004: if ( (arrowsp = rastcat(supsp,arrowsp,3)) /* superscript left of arrow */
! 6005: == NULL ) goto end_of_job; } /* quit if failed */
! 6006: if ( subsp != NULL ) /* cat subscript to right of arrow */
! 6007: { int subht = (subsp->image)->height, /* subscript height */
! 6008: deltab = (1+abs(height-subht))/2; /* baseline difference to center */
! 6009: arrowsp->baseline = height-1; /* reset arrow baseline to bottom */
! 6010: subsp->baseline = subht-1; /* force script baseline to bottom */
! 6011: if ( subht <= height ) /* arrow usually taller than script*/
! 6012: arrowsp->baseline -= deltab; /* so bottom of script goes here */
! 6013: else subsp->baseline -= deltab; /* else bottom of arrow goes here */
! 6014: if ( (arrowsp = rastcat(arrowsp,subsp,3)) /* subscript right of arrow */
! 6015: == NULL ) goto end_of_job; } /* quit if failed */
! 6016: /* --- return arrow (or NULL) to caller --- */
! 6017: end_of_job:
! 6018: arrowsp->baseline = height-1; /* reset arrow baseline to bottom */
! 6019: return ( arrowsp );
! 6020: } /* --- end-of-function rastuparrow() --- */
! 6021:
! 6022:
! 6023: /* ==========================================================================
! 6024: * Function: rastoverlay (expression, size, basesp, overlay, offset2, arg3)
! 6025: * Purpose: overlays one raster on another
! 6026: * --------------------------------------------------------------------------
! 6027: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6028: * string immediately following overlay \cmd to
! 6029: * be rasterized, and returning ptr immediately
! 6030: * following last character processed.
! 6031: * size (I) int containing 0-5 default font size
! 6032: * basesp (I) subraster * to character (or subexpression)
! 6033: * immediately preceding overlay \cmd
! 6034: * (unused, but passed for consistency)
! 6035: * overlay (I) int containing 1 to overlay / (e.g., \not)
! 6036: * or NOVALUE to pick up 2nd arg from expression
! 6037: * offset2 (I) int containing #pixels to horizontally offset
! 6038: * overlay relative to underlying symbol,
! 6039: * positive(right) or negative or 0,
! 6040: * or NOVALUE to pick up optional [offset] arg
! 6041: * arg3 (I) int unused
! 6042: * --------------------------------------------------------------------------
! 6043: * Returns: ( subraster * ) ptr to subraster corresponding to composite,
! 6044: * or NULL for any parsing error
! 6045: * --------------------------------------------------------------------------
! 6046: * Notes: o
! 6047: * ======================================================================= */
! 6048: /* --- entry point --- */
! 6049: subraster *rastoverlay ( char **expression, int size, subraster *basesp,
! 6050: int overlay, int offset2, int arg3 )
! 6051: {
! 6052: /* -------------------------------------------------------------------------
! 6053: Allocations and Declarations
! 6054: -------------------------------------------------------------------------- */
! 6055: char *texsubexpr(), /*parse expression for base,overlay*/
! 6056: expr1[512], expr2[512]; /* base, overlay */
! 6057: subraster *rasterize(), *sp1=NULL, *sp2=NULL, /*rasterize 1=base, 2=overlay*/
! 6058: *new_subraster(); /*explicitly alloc sp2 if necessary*/
! 6059: subraster *rastcompose(), *overlaysp=NULL; /*subraster for composite overlay*/
! 6060: int line_raster(); /* draw diagonal for \Not */
! 6061: /* -------------------------------------------------------------------------
! 6062: Obtain base, and maybe overlay, and rasterize them
! 6063: -------------------------------------------------------------------------- */
! 6064: /* --- check for optional offset2 arg --- */
! 6065: if ( offset2 == NOVALUE ) /* only if not explicitly specified*/
! 6066: if ( *(*expression) == '[' ) /*check for []-enclosed optional arg*/
! 6067: { int offsetval; /* test before using it */
! 6068: *expression = texsubexpr(*expression,expr2,511,"[","]",0,0);
! 6069: offsetval = (int)(strtod(expr2,NULL)+0.5); /* convert [offset2] to int */
! 6070: if ( abs(offsetval) <= 25 ) /* sanity check */
! 6071: offset2 = offsetval; } /* replace deafault */
! 6072: if ( offset2 == NOVALUE ) offset2 = 0; /* novalue means no offset */
! 6073: /* --- parse for base, bump expression past it, and rasterize it --- */
! 6074: *expression = texsubexpr(*expression,expr1,511,"{","}",0,0);
! 6075: if ( *expr1 == '\000' ) goto end_of_job; /* nothing to overlay, so quit */
! 6076: if ( (sp1=rasterize(expr1,size)) /* rasterize base expression */
! 6077: == NULL ) goto end_of_job; /* quit if failed to rasterize */
! 6078: overlaysp = sp1; /*in case we return with no overlay*/
! 6079: /* --- get overlay expression, and rasterize it --- */
! 6080: if ( overlay == NOVALUE ) /* get overlay from input stream */
! 6081: { *expression = texsubexpr(*expression,expr2,511,"{","}",0,0);
! 6082: if ( *expr2 != '\000' ) /* have an overlay */
! 6083: sp2 = rasterize(expr2,size); } /* so rasterize overlay expression */
! 6084: else /* specific overlay */
! 6085: switch ( overlay )
! 6086: {
! 6087: default: break;
! 6088: case 1: /* e.g., \not overlays slash */
! 6089: sp2 = rasterize("/",size+1); /* rasterize overlay expression */
! 6090: offset2 = max2(1,size-3); /* push / right a bit */
! 6091: offset2 = 0;
! 6092: break;
! 6093: case 2: /* e.g., \Not draws diagonal */
! 6094: sp2 = NULL; /* no overlay required */
! 6095: if ( overlaysp != NULL ) /* check that we have raster */
! 6096: { raster *rp = overlaysp->image; /* raster to be \Not-ed */
! 6097: int width=rp->width, height=rp->height; /* raster dimensions */
! 6098: if ( 0 ) /* diagonal within bounding box */
! 6099: line_raster(rp,0,width-1,height-1,0,1); /* just draw diagonal */
! 6100: else /* construct "wide" diagonal */
! 6101: { int margin=3; /* desired extra margin width */
! 6102: sp2 = new_subraster(width+margin,height+margin,1); /*alloc it*/
! 6103: if ( sp2 != NULL ) /* allocated successfully */
! 6104: line_raster(sp2->image,0,width+margin-1,height+margin-1,0,1);}}
! 6105: break;
! 6106: case 3: /* e.g., \sout for strikeout */
! 6107: sp2 = NULL; /* no overlay required */
! 6108: if ( overlaysp != NULL ) /* check that we have raster */
! 6109: { raster *rp = overlaysp->image; /* raster to be \Not-ed */
! 6110: int width=rp->width, height=rp->height; /* raster dimensions */
! 6111: int baseline = overlaysp->baseline; /* we'll ignore descenders */
! 6112: int midrow = max2(0,min2(height-1,offset2+((baseline+1)/2)));
! 6113: if ( 1 ) /* strikeout within bounding box */
! 6114: line_raster(rp,midrow,0,midrow,width-1,1); } /*draw strikeout*/
! 6115: break;
! 6116: } /* --- end-of-switch(overlay) --- */
! 6117: if ( sp2 == NULL ) goto end_of_job; /*return sp1 if failed to rasterize*/
! 6118: /* -------------------------------------------------------------------------
! 6119: construct composite overlay
! 6120: -------------------------------------------------------------------------- */
! 6121: overlaysp = rastcompose(sp1,sp2,offset2,0,3);
! 6122: end_of_job:
! 6123: return ( overlaysp );
! 6124: } /* --- end-of-function rastoverlay() --- */
! 6125:
! 6126:
! 6127: /* ==========================================================================
! 6128: * Function: rastfrac ( expression, size, basesp, isfrac, arg2, arg3 )
! 6129: * Purpose: \frac,\atop handler, returns a subraster corresponding to
! 6130: * expression (immediately following \frac,\atop) at font size
! 6131: * --------------------------------------------------------------------------
! 6132: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6133: * string immediately following \frac to be
! 6134: * rasterized, and returning ptr immediately
! 6135: * following last character processed.
! 6136: * size (I) int containing 0-5 default font size
! 6137: * basesp (I) subraster * to character (or subexpression)
! 6138: * immediately preceding \frac
! 6139: * (unused, but passed for consistency)
! 6140: * isfrac (I) int containing true to draw horizontal line
! 6141: * between numerator and denominator,
! 6142: * or false not to draw it (for \atop).
! 6143: * arg2 (I) int unused
! 6144: * arg3 (I) int unused
! 6145: * --------------------------------------------------------------------------
! 6146: * Returns: ( subraster * ) ptr to subraster corresponding to fraction,
! 6147: * or NULL for any parsing error
! 6148: * --------------------------------------------------------------------------
! 6149: * Notes: o
! 6150: * ======================================================================= */
! 6151: /* --- entry point --- */
! 6152: subraster *rastfrac ( char **expression, int size, subraster *basesp,
! 6153: int isfrac, int arg2, int arg3 )
! 6154: {
! 6155: /* -------------------------------------------------------------------------
! 6156: Allocations and Declarations
! 6157: -------------------------------------------------------------------------- */
! 6158: char *texsubexpr(), /*parse expression for numer,denom*/
! 6159: numer[8192], denom[8192]; /*numer,denom parsed from expression*/
! 6160: subraster *rasterize(), *numsp=NULL, *densp=NULL; /*rasterize numer, denom*/
! 6161: subraster *rastack(), *fracsp=NULL; /* subraster for numer/denom */
! 6162: subraster *new_subraster()/*, *spacesp=NULL*/; /* space for num or den */
! 6163: int width=0, /* width of constructed raster */
! 6164: numheight=0; /* height of numerator */
! 6165: int baseht=0, baseln=0; /* height,baseline of base symbol */
! 6166: /*int istweak = 1;*/ /*true to tweak baseline alignment*/
! 6167: int rule_raster(), /* draw horizontal line for frac */
! 6168: lineheight = 1; /* thickness of fraction line */
! 6169: int vspace = 1; /*vertical space between components*/
! 6170: int delete_subraster(); /*free work areas in case of error*/
! 6171: int type_raster(); /* display debugging output */
! 6172: /* -------------------------------------------------------------------------
! 6173: Obtain numerator and denominator, and rasterize them
! 6174: -------------------------------------------------------------------------- */
! 6175: /* --- parse for numerator,denominator and bump expression past them --- */
! 6176: *expression = texsubexpr(*expression,numer,0,"{","}",0,0);
! 6177: *expression = texsubexpr(*expression,denom,0,"{","}",0,0);
! 6178: if ( *numer=='\000' && *denom=='\000' ) /* missing both components of frac */
! 6179: goto end_of_job; /* nothing to do, so quit */
! 6180: /* --- rasterize numerator, denominator --- */
! 6181: if ( *numer != '\000' ) /* have a numerator */
! 6182: if ( (numsp = rasterize(numer,size-1)) /* so rasterize numer at size-1 */
! 6183: == NULL ) goto end_of_job; /* and quit if failed */
! 6184: if ( *denom != '\000' ) /* have a denominator */
! 6185: if ( (densp = rasterize(denom,size-1)) /* so rasterize denom at size-1 */
! 6186: == NULL ) /* failed */
! 6187: { if ( numsp != NULL ) /* already rasterized numerator */
! 6188: delete_subraster(numsp); /* so free now-unneeded numerator */
! 6189: goto end_of_job; } /* and quit */
! 6190: /* --- if one componenet missing, use a blank space for it --- */
! 6191: if ( numsp == NULL ) /* no numerator given */
! 6192: numsp = rasterize("[?]",size-1); /* missing numerator */
! 6193: if ( densp == NULL ) /* no denominator given */
! 6194: densp = rasterize("[?]",size-1); /* missing denominator */
! 6195: /* --- check that we got both components --- */
! 6196: if ( numsp==NULL || densp==NULL ) /* some problem */
! 6197: { delete_subraster(numsp); /*delete numerator (if it existed)*/
! 6198: delete_subraster(densp); /*delete denominator (if it existed)*/
! 6199: goto end_of_job; } /* and quit */
! 6200: /* --- get height of numerator (to determine where line belongs) --- */
! 6201: numheight = (numsp->image)->height; /* get numerator's height */
! 6202: /* -------------------------------------------------------------------------
! 6203: construct raster with numerator stacked over denominator
! 6204: -------------------------------------------------------------------------- */
! 6205: /* --- construct raster with numer/denom --- */
! 6206: if ( (fracsp = rastack(densp,numsp,0,2*vspace+lineheight,1,3))/*numer/denom*/
! 6207: == NULL ) /* failed to construct numer/denom */
! 6208: { delete_subraster(numsp); /* so free now-unneeded numerator */
! 6209: delete_subraster(densp); /* and now-unneeded denominator */
! 6210: goto end_of_job; } /* and then quit */
! 6211: /* --- determine width of constructed raster --- */
! 6212: width = (fracsp->image)->width; /*just get width of embedded image*/
! 6213: /* --- initialize subraster parameters --- */
! 6214: fracsp->size = size; /* propagate font size forward */
! 6215: fracsp->baseline = (numheight+vspace+lineheight)+(size+2);/*default baseline*/
! 6216: if ( basesp != (subraster *)NULL ) /* we have base symbol for frac */
! 6217: { baseht = (basesp->image)->height; /* height of base symbol */
! 6218: baseln = basesp->baseline; /* and its baseline */
! 6219: } /* --- end-of-if(basesp!=NULL) --- */
! 6220: /* -------------------------------------------------------------------------
! 6221: draw horizontal line between numerator and denominator
! 6222: -------------------------------------------------------------------------- */
! 6223: if ( isfrac ) /*line for \frac, but not for \atop*/
! 6224: rule_raster(fracsp->image,numheight+vspace,0,width,lineheight,0);
! 6225: /* -------------------------------------------------------------------------
! 6226: return final result to caller
! 6227: -------------------------------------------------------------------------- */
! 6228: end_of_job:
! 6229: if ( msgfp!=NULL && msglevel>=99 )
! 6230: { fprintf(msgfp,"rastfrac> returning %s\n",(fracsp==NULL?"null":"..."));
! 6231: if ( fracsp != NULL ) /* have a constructed raster */
! 6232: type_raster(fracsp->image,msgfp); } /* display constructed raster */
! 6233: return ( fracsp );
! 6234: } /* --- end-of-function rastfrac() --- */
! 6235:
! 6236:
! 6237: /* ==========================================================================
! 6238: * Function: rastackrel ( expression, size, basesp, base, arg2, arg3 )
! 6239: * Purpose: \stackrel handler, returns a subraster corresponding to
! 6240: * stacked relation
! 6241: * --------------------------------------------------------------------------
! 6242: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6243: * string immediately following \stackrel to be
! 6244: * rasterized, and returning ptr immediately
! 6245: * following last character processed.
! 6246: * size (I) int containing 0-4 default font size
! 6247: * basesp (I) subraster * to character (or subexpression)
! 6248: * immediately preceding \stackrel
! 6249: * (unused, but passed for consistency)
! 6250: * base (I) int containing 1 if upper/first subexpression
! 6251: * is base relation, or 2 if lower/second is
! 6252: * arg2 (I) int unused
! 6253: * arg3 (I) int unused
! 6254: * --------------------------------------------------------------------------
! 6255: * Returns: ( subraster * ) ptr to subraster corresponding to stacked
! 6256: * relation, or NULL for any parsing error
! 6257: * --------------------------------------------------------------------------
! 6258: * Notes: o
! 6259: * ======================================================================= */
! 6260: /* --- entry point --- */
! 6261: subraster *rastackrel ( char **expression, int size, subraster *basesp,
! 6262: int base, int arg2, int arg3 )
! 6263: {
! 6264: /* -------------------------------------------------------------------------
! 6265: Allocations and Declarations
! 6266: -------------------------------------------------------------------------- */
! 6267: char *texsubexpr(), /*parse expression for numer,denom*/
! 6268: upper[8192], lower[8192]; /*upper,lower parsed from expression*/
! 6269: subraster *rasterize(), *upsp=NULL, *lowsp=NULL; /* rasterize upper, lower */
! 6270: subraster *rastack(), *relsp=NULL; /* subraster for upper/lower */
! 6271: int upsize = (base==1? size:size-1), /* font size for upper component */
! 6272: lowsize = (base==2? size:size-1); /* font size for lower component */
! 6273: int vspace = 1; /*vertical space between components*/
! 6274: int delete_subraster(); /*free work areas in case of error*/
! 6275: /* -------------------------------------------------------------------------
! 6276: Obtain numerator and denominator, and rasterize them
! 6277: -------------------------------------------------------------------------- */
! 6278: /* --- parse for numerator,denominator and bump expression past them --- */
! 6279: *expression = texsubexpr(*expression,upper,0,"{","}",0,0);
! 6280: *expression = texsubexpr(*expression,lower,0,"{","}",0,0);
! 6281: if ( *upper=='\000' || *lower=='\000' ) /* missing either component */
! 6282: goto end_of_job; /* nothing to do, so quit */
! 6283: /* --- rasterize upper, lower --- */
! 6284: if ( *upper != '\000' ) /* have upper component */
! 6285: if ( (upsp = rasterize(upper,upsize)) /* so rasterize upper component */
! 6286: == NULL ) goto end_of_job; /* and quit if failed */
! 6287: if ( *lower != '\000' ) /* have lower component */
! 6288: if ( (lowsp = rasterize(lower,lowsize)) /* so rasterize lower component */
! 6289: == NULL ) /* failed */
! 6290: { if ( upsp != NULL ) /* already rasterized upper */
! 6291: delete_subraster(upsp); /* so free now-unneeded upper */
! 6292: goto end_of_job; } /* and quit */
! 6293: /* -------------------------------------------------------------------------
! 6294: construct stacked relation raster
! 6295: -------------------------------------------------------------------------- */
! 6296: /* --- construct stacked relation --- */
! 6297: if ( (relsp = rastack(lowsp,upsp,3-base,vspace,1,3)) /* stacked relation */
! 6298: == NULL ) goto end_of_job; /* quit if failed */
! 6299: /* --- initialize subraster parameters --- */
! 6300: relsp->size = size; /* propagate font size forward */
! 6301: /* -------------------------------------------------------------------------
! 6302: return final result to caller
! 6303: -------------------------------------------------------------------------- */
! 6304: end_of_job:
! 6305: return ( relsp );
! 6306: } /* --- end-of-function rastackrel() --- */
! 6307:
! 6308:
! 6309: /* ==========================================================================
! 6310: * Function: rastmathfunc ( expression, size, basesp, base, arg2, arg3 )
! 6311: * Purpose: \log, \lim, etc handler, returns a subraster corresponding
! 6312: * to math functions
! 6313: * --------------------------------------------------------------------------
! 6314: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6315: * string immediately following \mathfunc to be
! 6316: * rasterized, and returning ptr immediately
! 6317: * following last character processed.
! 6318: * size (I) int containing 0-4 default font size
! 6319: * basesp (I) subraster * to character (or subexpression)
! 6320: * immediately preceding \mathfunc
! 6321: * (unused, but passed for consistency)
! 6322: * mathfunc (I) int containing 1=arccos, 2=arcsin, etc.
! 6323: * islimits (I) int containing 1 if function may have
! 6324: * limits underneath, e.g., \lim_{n\to\infty}
! 6325: * arg3 (I) int unused
! 6326: * --------------------------------------------------------------------------
! 6327: * Returns: ( subraster * ) ptr to subraster corresponding to mathfunc,
! 6328: * or NULL for any parsing error
! 6329: * --------------------------------------------------------------------------
! 6330: * Notes: o
! 6331: * ======================================================================= */
! 6332: /* --- entry point --- */
! 6333: subraster *rastmathfunc ( char **expression, int size, subraster *basesp,
! 6334: int mathfunc, int islimits, int arg3 )
! 6335: {
! 6336: /* -------------------------------------------------------------------------
! 6337: Allocations and Declarations
! 6338: -------------------------------------------------------------------------- */
! 6339: char *texscripts(), /* parse expression for _limits */
! 6340: func[4096], limits[8192]; /* func as {\rm func}, limits */
! 6341: char *texsubexpr(), /* parse expression for arg */
! 6342: funcarg[2048]; /* optional func arg */
! 6343: subraster *rasterize(), *funcsp=NULL, *limsp=NULL; /*rasterize func,limits*/
! 6344: subraster *rastack(), *mathfuncsp=NULL; /* subraster for mathfunc/limits */
! 6345: int limsize = size-1; /* font size for limits */
! 6346: int vspace = 1; /*vertical space between components*/
! 6347: int delete_subraster(); /*free work areas in case of error*/
! 6348: /* --- table of function names by mathfunc number --- */
! 6349: static int numnames = 34; /* number of names in table */
! 6350: static char *funcnames[] = {
! 6351: "error", /* 0 index is illegal/error bucket*/
! 6352: "arccos", "arcsin", "arctan", /* 1 - 3 */
! 6353: "arg", "cos", "cosh", /* 4 - 6 */
! 6354: "cot", "coth", "csc", /* 7 - 9 */
! 6355: "deg", "det", "dim", /* 10 - 12 */
! 6356: "exp", "gcd", "hom", /* 13 - 15 */
! 6357: "inf", "ker", "lg", /* 16 - 18 */
! 6358: "lim", "liminf", "limsup", /* 19 - 21 */
! 6359: "ln", "log", "max", /* 22 - 24 */
! 6360: "min", "Pr", "sec", /* 25 - 27 */
! 6361: "sin", "sinh", "sup", /* 28 - 30 */
! 6362: "tan", "tanh", /* 31 - 32 */
! 6363: /* --- extra mimetex funcnames --- */
! 6364: "tr", /* 33 */
! 6365: "pmod" /* 34 */
! 6366: } ;
! 6367: /* -------------------------------------------------------------------------
! 6368: set up and rasterize function name in \rm
! 6369: -------------------------------------------------------------------------- */
! 6370: if ( mathfunc<0 || mathfunc>numnames ) mathfunc=0; /* check index bounds */
! 6371: switch ( mathfunc ) /* check for special processing */
! 6372: {
! 6373: default: /* no special processing */
! 6374: strcpy(func,"{\\rm~"); /* init string with {\rm~ */
! 6375: strcat(func,funcnames[mathfunc]); /* concat function name */
! 6376: strcat(func,"}"); /* and add terminating } */
! 6377: break;
! 6378: case 34: /* \pmod{x} --> (mod x) */
! 6379: /* --- parse for \pmod{arg} argument --- */
! 6380: *expression = texsubexpr(*expression,funcarg,2047,"{","}",0,0);
! 6381: strcpy(func,"{\\({\\rm~mod}"); /* init with {\left({\rm~mod} */
! 6382: strcat(func,"\\hspace2"); /* concat space */
! 6383: strcat(func,funcarg); /* and \pmodargument */
! 6384: strcat(func,"\\)}"); /* and add terminating \right)} */
! 6385: break;
! 6386: } /* --- end-of-switch(mathfunc) --- */
! 6387: if ( (funcsp = rasterize(func,size)) /* rasterize function name */
! 6388: == NULL ) goto end_of_job; /* and quit if failed */
! 6389: mathfuncsp = funcsp; /* just return funcsp if no limits */
! 6390: if ( !islimits ) goto end_of_job; /* treat any subscript normally */
! 6391: /* -------------------------------------------------------------------------
! 6392: Obtain limits, if permitted and if provided, and rasterize them
! 6393: -------------------------------------------------------------------------- */
! 6394: /* --- parse for subscript limits, and bump expression past it(them) --- */
! 6395: *expression = texscripts(*expression,limits,limits,1);
! 6396: if ( *limits=='\000') goto end_of_job; /* no limits, nothing to do, quit */
! 6397: /* --- rasterize limits --- */
! 6398: if ( (limsp = rasterize(limits,limsize)) /* rasterize limits */
! 6399: == NULL ) goto end_of_job; /* and quit if failed */
! 6400: /* -------------------------------------------------------------------------
! 6401: construct func atop limits
! 6402: -------------------------------------------------------------------------- */
! 6403: /* --- construct func atop limits --- */
! 6404: if ( (mathfuncsp = rastack(limsp,funcsp,2,vspace,1,3)) /* func atop limits */
! 6405: == NULL ) goto end_of_job; /* quit if failed */
! 6406: /* --- initialize subraster parameters --- */
! 6407: mathfuncsp->size = size; /* propagate font size forward */
! 6408: /* -------------------------------------------------------------------------
! 6409: return final result to caller
! 6410: -------------------------------------------------------------------------- */
! 6411: end_of_job:
! 6412: return ( mathfuncsp );
! 6413: } /* --- end-of-function rastmathfunc() --- */
! 6414:
! 6415:
! 6416: /* ==========================================================================
! 6417: * Function: rastsqrt ( expression, size, basesp, arg1, arg2, arg3 )
! 6418: * Purpose: \sqrt handler, returns a subraster corresponding to
! 6419: * expression (immediately following \sqrt) at font size
! 6420: * --------------------------------------------------------------------------
! 6421: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6422: * string immediately following \sqrt to be
! 6423: * rasterized, and returning ptr immediately
! 6424: * following last character processed.
! 6425: * size (I) int containing 0-4 default font size
! 6426: * basesp (I) subraster * to character (or subexpression)
! 6427: * immediately preceding \accent
! 6428: * (unused, but passed for consistency)
! 6429: * arg1 (I) int unused
! 6430: * arg2 (I) int unused
! 6431: * arg3 (I) int unused
! 6432: * --------------------------------------------------------------------------
! 6433: * Returns: ( subraster * ) ptr to subraster corresponding to expression,
! 6434: * or NULL for any parsing error
! 6435: * (expression ptr unchanged if error occurs)
! 6436: * --------------------------------------------------------------------------
! 6437: * Notes: o
! 6438: * ======================================================================= */
! 6439: /* --- entry point --- */
! 6440: subraster *rastsqrt ( char **expression, int size, subraster *basesp,
! 6441: int arg1, int arg2, int arg3 )
! 6442: {
! 6443: /* -------------------------------------------------------------------------
! 6444: Allocations and Declarations
! 6445: -------------------------------------------------------------------------- */
! 6446: char *texsubexpr(), subexpr[8192], /* parse subexpr to be sqrt-ed */
! 6447: rootarg[8192]; /* optional \sqrt[rootarg]{...} */
! 6448: subraster *rasterize(), *subsp=NULL; /* rasterize subexpr */
! 6449: subraster *accent_subraster(), *sqrtsp=NULL, /* subraster with the sqrt */
! 6450: *new_subraster(), *rootsp=NULL; /* optionally preceded by [rootarg]*/
! 6451: int sqrtheight=0, sqrtwidth=0, surdwidth=0, /* height,width of sqrt */
! 6452: rootheight=0, rootwidth=0, /* height,width of rootarg raster */
! 6453: subheight=0, subwidth=0, pixsz=0; /* height,width,pixsz of subexpr */
! 6454: int rastput(); /* put subexpr in constructed sqrt */
! 6455: int overspace = 2; /*space between subexpr and overbar*/
! 6456: int delete_subraster(); /* free work areas */
! 6457: /* -------------------------------------------------------------------------
! 6458: Obtain subexpression to be sqrt-ed, and rasterize it
! 6459: -------------------------------------------------------------------------- */
! 6460: /* --- first check for optional \sqrt[rootarg]{...} --- */
! 6461: if ( *(*expression) == '[' ) /*check for []-enclosed optional arg*/
! 6462: { *expression = texsubexpr(*expression,rootarg,0,"[","]",0,0);
! 6463: if ( *rootarg != '\000' ) /* got rootarg */
! 6464: if ( (rootsp=rasterize(rootarg,size-1)) /*rasterize it at smaller size*/
! 6465: != NULL ) /* rasterized successfully */
! 6466: { rootheight = (rootsp->image)->height; /* get height of rootarg */
! 6467: rootwidth = (rootsp->image)->width; } /* and its width */
! 6468: } /* --- end-of-if(**expression=='[') --- */
! 6469: /* --- parse for subexpr to be sqrt-ed, and bump expression past it --- */
! 6470: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 6471: if ( *subexpr == '\000' ) /* couldn't get subexpression */
! 6472: goto end_of_job; /* nothing to do, so quit */
! 6473: /* --- rasterize subexpression to be accented --- */
! 6474: if ( (subsp = rasterize(subexpr,size)) /*rasterize subexpr at original size*/
! 6475: == NULL ) goto end_of_job; /* quit if failed */
! 6476: /* -------------------------------------------------------------------------
! 6477: determine height and width of sqrt raster to be constructed
! 6478: -------------------------------------------------------------------------- */
! 6479: /* --- first get height and width of subexpr --- */
! 6480: subheight = (subsp->image)->height; /* height of subexpr */
! 6481: subwidth = (subsp->image)->width; /* and its width */
! 6482: pixsz = (subsp->image)->pixsz; /* pixsz remains constant */
! 6483: /* --- determine height and width of sqrt to contain subexpr --- */
! 6484: sqrtheight = subheight + overspace; /* subexpr + blank line + overbar */
! 6485: surdwidth = SQRTWIDTH(sqrtheight); /* width of surd */
! 6486: sqrtwidth = subwidth + surdwidth + 1; /* total width */
! 6487: /* -------------------------------------------------------------------------
! 6488: construct sqrt (with room to move in subexpr) and embed subexpr in it
! 6489: -------------------------------------------------------------------------- */
! 6490: /* --- construct sqrt --- */
! 6491: if ( (sqrtsp=accent_subraster(SQRTACCENT,sqrtwidth,sqrtheight,pixsz))
! 6492: == NULL ) goto end_of_job; /* quit if failed to build sqrt */
! 6493: /* --- embed subexpr in sqrt at lower-right corner--- */
! 6494: rastput(sqrtsp->image,subsp->image,overspace,sqrtwidth-subwidth,1);
! 6495: sqrtsp->baseline = subsp->baseline + overspace; /* adjust baseline */
! 6496: /* --- "embed" rootarg at upper-left --- */
! 6497: if ( rootsp != NULL ) /*have optional \sqrt[rootarg]{...}*/
! 6498: {
! 6499: /* --- allocate full raster to contain sqrtsp and rootsp --- */
! 6500: int fullwidth = sqrtwidth +rootwidth - min2(rootwidth,max2(0,surdwidth-4)),
! 6501: fullheight= sqrtheight+rootheight- min2(rootheight,3+size);
! 6502: subraster *fullsp = new_subraster(fullwidth,fullheight,pixsz);
! 6503: if ( fullsp != NULL ) /* allocated successfully */
! 6504: { /* --- embed sqrtsp exactly at lower-right corner --- */
! 6505: rastput(fullsp->image,sqrtsp->image, /* exactly at lower-right corner*/
! 6506: fullheight-sqrtheight,fullwidth-sqrtwidth,1);
! 6507: /* --- embed rootsp near upper-left, nestled above leading surd --- */
! 6508: rastput(fullsp->image,rootsp->image,
! 6509: 0,max2(0,surdwidth-rootwidth-2-size),0);
! 6510: /* --- replace sqrtsp with fullsp --- */
! 6511: delete_subraster(sqrtsp); /* free original sqrtsp */
! 6512: sqrtsp = fullsp; /* and repoint it to fullsp instead*/
! 6513: sqrtsp->baseline = fullheight - (subheight - subsp->baseline); }
! 6514: } /* --- end-of-if(rootsp!=NULL) --- */
! 6515: /* --- initialize subraster parameters --- */
! 6516: sqrtsp->size = size; /* propagate font size forward */
! 6517: /* -------------------------------------------------------------------------
! 6518: free unneeded component subrasters and return final result to caller
! 6519: -------------------------------------------------------------------------- */
! 6520: end_of_job:
! 6521: if ( subsp != NULL ) delete_subraster(subsp); /* free unneeded subexpr */
! 6522: return ( sqrtsp );
! 6523: } /* --- end-of-function rastsqrt() --- */
! 6524:
! 6525:
! 6526: /* ==========================================================================
! 6527: * Function: rastaccent (expression,size,basesp,accent,isabove,isscript)
! 6528: * Purpose: \hat, \vec, \etc handler, returns a subraster corresponding
! 6529: * to expression (immediately following \accent) at font size
! 6530: * --------------------------------------------------------------------------
! 6531: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6532: * string immediately following \accent to be
! 6533: * rasterized, and returning ptr immediately
! 6534: * following last character processed.
! 6535: * size (I) int containing 0-4 default font size
! 6536: * basesp (I) subraster * to character (or subexpression)
! 6537: * immediately preceding \accent
! 6538: * (unused, but passed for consistency)
! 6539: * accent (I) int containing HATACCENT or VECACCENT, etc,
! 6540: * between numerator and denominator,
! 6541: * or false not to draw it (for \over).
! 6542: * isabove (I) int containing true if accent is above
! 6543: * expression to be accented, or false
! 6544: * if accent is below (e.g., underbrace)
! 6545: * isscript (I) int containing true if sub/superscripts
! 6546: * allowed (for under/overbrace), or 0 if not.
! 6547: * --------------------------------------------------------------------------
! 6548: * Returns: ( subraster * ) ptr to subraster corresponding to expression,
! 6549: * or NULL for any parsing error
! 6550: * (expression ptr unchanged if error occurs)
! 6551: * --------------------------------------------------------------------------
! 6552: * Notes: o Also handles \overbrace{}^{} and \underbrace{}_{} by way
! 6553: * of isabove and isscript args.
! 6554: * ======================================================================= */
! 6555: /* --- entry point --- */
! 6556: subraster *rastaccent ( char **expression, int size, subraster *basesp,
! 6557: int accent, int isabove, int isscript )
! 6558: {
! 6559: /* -------------------------------------------------------------------------
! 6560: Allocations and Declarations
! 6561: -------------------------------------------------------------------------- */
! 6562: char *texsubexpr(), subexpr[8192]; /* parse subexpr to be accented */
! 6563: char *texscripts(), *script=NULL, /* \under,overbrace allow scripts */
! 6564: subscript[512], supscript[512]; /* scripts parsed from expression */
! 6565: subraster *rasterize(), *subsp=NULL, *scrsp=NULL; /*rasterize subexpr,script*/
! 6566: subraster *rastack(), *accsubsp=NULL; /* stack accent, subexpr, script */
! 6567: subraster *accent_subraster(), *accsp=NULL; /*raster for the accent itself*/
! 6568: int accheight=0, accwidth=0, /* height, width of accent */
! 6569: subheight=0, subwidth=0, pixsz=0; /* height,width,pixsz of subexpr */
! 6570: int delete_subraster(); /*free work areas in case of error*/
! 6571: int vspace = 0; /*vertical space between accent,sub*/
! 6572: /* -------------------------------------------------------------------------
! 6573: Obtain subexpression to be accented, and rasterize it
! 6574: -------------------------------------------------------------------------- */
! 6575: /* --- parse for subexpr to be accented, and bump expression past it --- */
! 6576: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 6577: if ( *subexpr=='\000' ) /* couldn't get subexpression */
! 6578: goto end_of_job; /* nothing to do, so quit */
! 6579: /* --- rasterize subexpression to be accented --- */
! 6580: if ( (subsp = rasterize(subexpr,size)) /*rasterize subexpr at original size*/
! 6581: == NULL ) goto end_of_job; /* quit if failed */
! 6582: /* -------------------------------------------------------------------------
! 6583: determine desired accent width and height
! 6584: -------------------------------------------------------------------------- */
! 6585: /* --- first get height and width of subexpr --- */
! 6586: subheight = (subsp->image)->height; /* height of subexpr */
! 6587: subwidth = (subsp->image)->width; /* and its width is overall width */
! 6588: pixsz = (subsp->image)->pixsz; /* original pixsz remains constant */
! 6589: /* --- determine desired width, height of accent --- */
! 6590: accwidth = subwidth; /* same width as subexpr */
! 6591: accheight = 3; /* default for bars */
! 6592: switch ( accent )
! 6593: { default: break; /* default okay */
! 6594: case DOTACCENT: case DDOTACCENT:
! 6595: accheight = (size<3? 3:4); /* default for dots */
! 6596: break;
! 6597: case HATACCENT: case VECACCENT:
! 6598: accheight = 7; /* default */
! 6599: if ( subwidth < 10 ) accheight = 5; /* unless small width */
! 6600: else if ( subwidth > 25 ) accheight = 9; /* or large */
! 6601: break;
! 6602: } /* --- end-of-switch(accent) --- */
! 6603: accheight = min2(accheight,subheight); /*never higher than accented subexpr*/
! 6604: /* -------------------------------------------------------------------------
! 6605: construct accent, and construct subraster with accent over (or under) subexpr
! 6606: -------------------------------------------------------------------------- */
! 6607: /* --- first construct accent --- */
! 6608: if ( (accsp = accent_subraster(accent,accwidth,accheight,pixsz)) /* accent */
! 6609: == NULL ) goto end_of_job; /* quit if failed to build accent */
! 6610: /* --- now stack accent above (or below) subexpr, and free both args --- */
! 6611: accsubsp = (isabove? rastack(subsp,accsp,1,vspace,1,3)/*accent above subexpr*/
! 6612: : rastack(accsp,subsp,2,vspace,1,3)); /*accent below subexpr*/
! 6613: if ( accsubsp == NULL ) /* failed to stack accent */
! 6614: { delete_subraster(subsp); /* free unneeded subsp */
! 6615: delete_subraster(accsp); /* and unneeded accsp */
! 6616: goto end_of_job; } /* and quit */
! 6617: /* -------------------------------------------------------------------------
! 6618: look for super/subscript (annotation for over/underbrace)
! 6619: -------------------------------------------------------------------------- */
! 6620: /* --- first check whether accent permits accompanying annotations --- */
! 6621: if ( !isscript ) goto end_of_job; /* no annotations for this accent */
! 6622: /* --- now get scripts if there actually are any --- */
! 6623: *expression = texscripts(*expression,subscript,supscript,(isabove?2:1));
! 6624: script = (isabove? supscript : subscript); /*select above^ or below_ script*/
! 6625: if ( *script == '\000' ) goto end_of_job; /* no accompanying script */
! 6626: /* --- rasterize script annotation at size-2 --- */
! 6627: if ( (scrsp = rasterize(script,size-2)) /* rasterize script at size-2 */
! 6628: == NULL ) goto end_of_job; /* quit if failed */
! 6629: /* --- stack annotation above (or below) accent, and free both args --- */
! 6630: accsubsp = (isabove? rastack(accsubsp,scrsp,1,0,1,3) /* accent above base */
! 6631: : rastack(scrsp,accsubsp,2,0,1,3)); /* accent below base */
! 6632: /* -------------------------------------------------------------------------
! 6633: return final result to caller
! 6634: -------------------------------------------------------------------------- */
! 6635: end_of_job:
! 6636: if ( accsubsp != NULL ) /* initialize subraster parameters */
! 6637: accsubsp->size = size; /* propagate font size forward */
! 6638: return ( accsubsp );
! 6639: } /* --- end-of-function rastaccent() --- */
! 6640:
! 6641:
! 6642: /* ==========================================================================
! 6643: * Function: rastfont (expression,size,basesp,font,arg2,arg3)
! 6644: * Purpose: \cal{}, \scr{}, \etc handler, returns subraster corresponding
! 6645: * to char(s) within {}'s rendered at size
! 6646: * --------------------------------------------------------------------------
! 6647: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6648: * string immediately following \font to be
! 6649: * rasterized, and returning ptr immediately
! 6650: * following last character processed.
! 6651: * size (I) int containing 0-5 default font size
! 6652: * basesp (I) subraster * to character (or subexpression)
! 6653: * immediately preceding \accent
! 6654: * (unused, but passed for consistency)
! 6655: * font (I) int containing 1 for \cal{}, 2 for \scr{}
! 6656: * arg2 (I) int unused
! 6657: * arg3 (I) int unused
! 6658: * --------------------------------------------------------------------------
! 6659: * Returns: ( subraster * ) ptr to subraster corresponding to chars
! 6660: * between {}'s, or NULL for any parsing error
! 6661: * --------------------------------------------------------------------------
! 6662: * Notes: o
! 6663: * ======================================================================= */
! 6664: /* --- entry point --- */
! 6665: subraster *rastfont ( char **expression, int size, subraster *basesp,
! 6666: int font, int arg2, int arg3 )
! 6667: {
! 6668: /* -------------------------------------------------------------------------
! 6669: Allocations and Declarations
! 6670: -------------------------------------------------------------------------- */
! 6671: char *texsubexpr(), fontchars[8192], /*parse chars to be rendered in font*/
! 6672: subexpr[8192]; /* turn \cal{AB} into \calA\calB */
! 6673: char *pfchars=fontchars, fchar='\0'; /* run thru fontchars one at a time*/
! 6674: char *name = NULL; /* fonts[font].name */
! 6675: int class = 0, /* fonts[font].class */
! 6676: istext = 0; /* set true for text type */
! 6677: subraster *rasterize(), *fontsp=NULL, /* rasterize chars in font */
! 6678: *rastflags(); /* or just set flag to switch font */
! 6679: int oldsquashmargin = squashmargin; /* turn off squash in text mode */
! 6680: int blanksignal = (-991234); /*rastsquash signal right-hand blank*/
! 6681: /* --- fonts recognized by rastfont --- */
! 6682: static int nfonts = 5; /* legal font #'s are 1...nfonts */
! 6683: static struct {char *name; int class;}
! 6684: fonts[] =
! 6685: { /* --- name class 1=upper,2=alpha,3=alnum,4=lower,5=digit,9=all --- */
! 6686: { "\\badfont", 0 },
! 6687: { "\\cal", 1 }, /*(1) calligraphic, uppercase */
! 6688: { "\\scr", 1 }, /*(2) rsfs/script, uppercase */
! 6689: { "\\rm", -1 }, /*(3) \rm,\text{abc} --> {\rm~abc} */
! 6690: { "\\it", -1 }, /*(4) \it,\textit{abc}-->{\it~abc} */
! 6691: { "\\bb", -1 }, /*(5) \bb,\mathbb{abc}-->{\bb~abc} */
! 6692: { NULL, 0 }
! 6693: } ; /* --- end-of-fonts[] --- */
! 6694: /* -------------------------------------------------------------------------
! 6695: first get font name and class to determine type of conversion desired
! 6696: -------------------------------------------------------------------------- */
! 6697: if ( font<=0 || font>nfonts ) font=0; /* set error if out-of-bounds */
! 6698: name = fonts[font].name; /* font name */
! 6699: class = fonts[font].class; /* font class */
! 6700: if ( font==3 || font==4 ) /* text (respect blanks) */
! 6701: { istext = 1; /* signal text mode */
! 6702: squashmargin = 0; } /* don't squash internal blanks */
! 6703: /* -------------------------------------------------------------------------
! 6704: now convert \font{abc} --> {\font~abc}, or convert ABC to \calA\calB\calC
! 6705: -------------------------------------------------------------------------- */
! 6706: if ( class < 0 ) /* not character-by-character */
! 6707: {
! 6708: /* ---
! 6709: if \font not immediately followed by { then it has no arg, so just set flag
! 6710: ------------------------------------------------------------------------ */
! 6711: if ( *(*expression) != '{' ) /* no \font arg, so just set flag */
! 6712: {
! 6713: if ( msgfp!=NULL && msglevel>=99 )
! 6714: fprintf(msgfp,"rastfont> \\%s rastflags() for font#%d\n",name,font);
! 6715: switch ( font ) /* set flag by our internal font# */
! 6716: { case 3: /* \rm, \text sets flag istext=1 */
! 6717: fontsp = rastflags(expression,size,basesp,ISTEXT,1,arg3); break;
! 6718: case 4: /* \it, \text sets flag istext=2 */
! 6719: fontsp = rastflags(expression,size,basesp,ISTEXT,2,arg3); break;
! 6720: case 5: /* \bb, \mathbb sets flag istext=3 */
! 6721: fontsp = rastflags(expression,size,basesp,ISTEXT,3,arg3); break;
! 6722: default: break; } /* unrecognized, set no flags */
! 6723: goto end_of_job;
! 6724: } /* --- end-of-if(*(*expression)!='{') --- */
! 6725: /* ---
! 6726: convert \font{abc} --> {\font~abc}
! 6727: ---------------------------------- */
! 6728: /* --- parse for {fontchars} arg, and bump expression past it --- */
! 6729: *expression = texsubexpr(*expression,fontchars,0,"{","}",0,0);
! 6730: if ( msgfp!=NULL && msglevel>=99 )
! 6731: fprintf(msgfp,"rastfont> \\%s fontchars=\"%s\"\n",name,fontchars);
! 6732: /* --- convert all fontchars at the same time --- */
! 6733: strcpy(subexpr,"{"); /* start off with opening { */
! 6734: strcat(subexpr,name); /* followed by font name */
! 6735: strcat(subexpr,"~"); /* followed by whitespace */
! 6736: strcat(subexpr,fontchars); /* followed by all the chars */
! 6737: strcat(subexpr,"}"); /* terminate with closing } */
! 6738: } /* --- end-of-if(class<0) --- */
! 6739: else /* character-by-character */
! 6740: {
! 6741: /* ---
! 6742: convert ABC to \calA\calB\calC
! 6743: ------------------------------ */
! 6744: int isprevchar=0; /* true if prev char converted */
! 6745: /* --- parse for {fontchars} arg, and bump expression past it --- */
! 6746: *expression = texsubexpr(*expression,fontchars,0,"{","}",0,0);
! 6747: if ( msgfp!=NULL && msglevel>=99 )
! 6748: fprintf(msgfp,"rastfont> \\%s fontchars=\"%s\"\n",name,fontchars);
! 6749: /* --- convert fontchars one at a time --- */
! 6750: strcpy(subexpr,"{\\rm~"); /* start off with opening {\rm */
! 6751: strcpy(subexpr,"{"); /* nope, just start off with { */
! 6752: for ( pfchars=fontchars; (fchar= *pfchars)!='\000'; pfchars++ )
! 6753: {
! 6754: if ( isthischar(fchar,WHITEMATH) ) /* some whitespace */
! 6755: { if ( 0 || istext ) /* and we're in a text mode */
! 6756: strcat(subexpr,"\\;"); } /* so respect whitespace */
! 6757: else /* char to be displayed in font */
! 6758: { int exprlen = 0; /* #chars in subexpr before fchar */
! 6759: int isinclass = 0; /* set true if fchar in font class */
! 6760: switch ( class ) /* check if fchar is in font class */
! 6761: { default: break; /* no chars in unrecognized class */
! 6762: case 1: if ( isupper((int)fchar) ) isinclass=1; break;
! 6763: case 2: if ( isalpha((int)fchar) ) isinclass=1; break;
! 6764: case 3: if ( isalnum((int)fchar) ) isinclass=1; break;
! 6765: case 4: if ( islower((int)fchar) ) isinclass=1; break;
! 6766: case 5: if ( isdigit((int)fchar) ) isinclass=1; break;
! 6767: case 9: isinclass=1; break; }
! 6768: if ( isinclass ) /* convert current char to \font */
! 6769: { strcat(subexpr,name); /* by prefixing it with font name */
! 6770: isprevchar = 1; } /* and set flag to signal separator*/
! 6771: else /* current char not in \font */
! 6772: { if ( isprevchar ) /* extra separator only after \font*/
! 6773: if ( isalpha(fchar) ) /* separator only before alpha */
! 6774: strcat(subexpr,"~"); /* need separator after \font */
! 6775: isprevchar = 0; } /* reset flag for next char */
! 6776: exprlen = strlen(subexpr); /* #chars so far */
! 6777: subexpr[exprlen] = fchar; /*fchar immediately after \fontname*/
! 6778: subexpr[exprlen+1] = '\000'; } /* replace terminating '\0' */
! 6779: } /* --- end-of-for(pfchars) --- */
! 6780: strcat(subexpr,"}"); /* add closing } */
! 6781: } /* --- end-of-if/else(class<0) --- */
! 6782: /* -------------------------------------------------------------------------
! 6783: rasterize subexpression containing chars to be rendered at font
! 6784: -------------------------------------------------------------------------- */
! 6785: if ( msgfp!=NULL && msglevel>=99 )
! 6786: fprintf(msgfp,"rastfont> subexpr=\"%s\"\n",subexpr);
! 6787: if ( (fontsp = rasterize(subexpr,size)) /* rasterize chars in font */
! 6788: == NULL ) goto end_of_job; /* and quit if failed */
! 6789: /* -------------------------------------------------------------------------
! 6790: back to caller with chars rendered in font
! 6791: -------------------------------------------------------------------------- */
! 6792: end_of_job:
! 6793: squashmargin = oldsquashmargin; /* restore squash */
! 6794: if ( istext && fontsp!=NULL ) /* raster contains text */
! 6795: fontsp->type = blanksignal; /* signal nosquash */
! 6796: return ( fontsp ); /* chars rendered in font */
! 6797: } /* --- end-of-function rastfont() --- */
! 6798:
! 6799:
! 6800: /* ==========================================================================
! 6801: * Function: rastbegin ( expression, size, basesp, arg1, arg2, arg3 )
! 6802: * Purpose: \begin{}...\end{} handler, returns a subraster corresponding
! 6803: * to array expression within environment, i.e., rewrites
! 6804: * \begin{}...\end{} as mimeTeX equivalent, and rasterizes that.
! 6805: * --------------------------------------------------------------------------
! 6806: * Arguments: expression (I/O) char ** to first char of null-terminated
! 6807: * string immediately following \begin to be
! 6808: * rasterized, and returning ptr immediately
! 6809: * following last character processed.
! 6810: * size (I) int containing 0-4 default font size
! 6811: * basesp (I) subraster * to character (or subexpression)
! 6812: * immediately preceding \begin
! 6813: * (unused, but passed for consistency)
! 6814: * arg1 (I) int unused
! 6815: * arg2 (I) int unused
! 6816: * arg3 (I) int unused
! 6817: * --------------------------------------------------------------------------
! 6818: * Returns: ( subraster * ) ptr to subraster corresponding to array
! 6819: * expression, or NULL for any parsing error
! 6820: * --------------------------------------------------------------------------
! 6821: * Notes: o
! 6822: * ======================================================================= */
! 6823: /* --- entry point --- */
! 6824: subraster *rastbegin ( char **expression, int size, subraster *basesp,
! 6825: int arg1, int arg2, int arg3 )
! 6826: {
! 6827: /* -------------------------------------------------------------------------
! 6828: Allocations and Declarations
! 6829: -------------------------------------------------------------------------- */
! 6830: char *texsubexpr(), subexpr[8210], /* \begin{} environment paramaters */
! 6831: *exprptr=NULL,*begptr=NULL,*endptr=NULL,*braceptr=NULL; /* ptrs */
! 6832: char *begtoken="\\begin{", *endtoken="\\end{"; /*tokens we're looking for*/
! 6833: int strreplace(); /* replace substring in string */
! 6834: char *strchange(); /*\begin...\end --> {\begin...\end}*/
! 6835: char *delims = (char *)NULL; /* mdelims[ienviron] */
! 6836: subraster *rasterize(), *sp=NULL; /* rasterize environment */
! 6837: int ienviron = 0; /* environs[] index */
! 6838: int nbegins = 0; /* #\begins nested beneath this one*/
! 6839: int envlen=0, sublen=0; /* #chars in environ, subexpr */
! 6840: static int blevel = 0; /* \begin...\end nesting level */
! 6841: static char *mdelims[] = { NULL, NULL, NULL, NULL,
! 6842: "()","[]","{}","||","==", /* for pbBvVmatrix */
! 6843: NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
! 6844: NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
! 6845: static char *environs[] = { /* types of environments we process*/
! 6846: "eqnarray", /* 0 eqnarray environment */
! 6847: "array", /* 1 array environment */
! 6848: "matrix", /* 2 array environment */
! 6849: "tabular", /* 3 array environment */
! 6850: "pmatrix", /* 4 ( ) */
! 6851: "bmatrix", /* 5 [ ] */
! 6852: "Bmatrix", /* 6 { } */
! 6853: "vmatrix", /* 7 | | */
! 6854: "Vmatrix", /* 8 || || */
! 6855: "gather", /* 9 gather environment */
! 6856: "align", /* 10 align environment */
! 6857: "verbatim", /* 11 verbatim environment */
! 6858: "picture", /* 12 picture environment */
! 6859: NULL }; /* trailer */
! 6860: /* -------------------------------------------------------------------------
! 6861: determine type of environment we're beginning
! 6862: -------------------------------------------------------------------------- */
! 6863: /* --- first bump nesting level --- */
! 6864: blevel++; /* count \begin...\begin...'s */
! 6865: /* --- \begin must be followed by {type_of_environment} --- */
! 6866: exprptr = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 6867: if ( *subexpr == '\000' ) goto end_of_job; /* no environment given */
! 6868: while ( (delims=strchr(subexpr,'*')) != NULL ) /* have environment* */
! 6869: strcpy(delims,delims+1); /* treat it as environment */
! 6870: /* --- look up environment in our table --- */
! 6871: for ( ienviron=0; ;ienviron++ ) /* search table till NULL */
! 6872: if ( environs[ienviron] == NULL ) /* found NULL before match */
! 6873: goto end_of_job; /* so quit */
! 6874: else /* see if we have an exact match */
! 6875: if ( memcmp(environs[ienviron],subexpr,strlen(subexpr)) == 0 ) /*match*/
! 6876: break; /* leave loop with ienviron index */
! 6877: /* --- accumulate any additional params for this environment --- */
! 6878: *subexpr = '\000'; /* reset subexpr to empty string */
! 6879: delims = mdelims[ienviron]; /* mdelims[] string for ienviron */
! 6880: if ( delims != NULL ) /* add appropriate opening delim */
! 6881: { strcpy(subexpr,"\\"); /* start with \ for (,[,{,|,= */
! 6882: strcat(subexpr,delims); /* then add opening delim */
! 6883: subexpr[2] = '\000'; } /* remove extraneous closing delim */
! 6884: switch ( ienviron )
! 6885: {
! 6886: default: goto end_of_job; /* environ not implemented yet */
! 6887: case 0: /* \begin{eqnarray} */
! 6888: strcpy(subexpr,"\\array{rcl$"); /* set default rcl for eqnarray */
! 6889: break;
! 6890: case 1: case 2: case 3: /* \begin{array} followed by {lcr} */
! 6891: strcpy(subexpr,"\\array{"); /*start with mimeTeX \array{ command*/
! 6892: skipwhite(exprptr); /* bump to next non-white char */
! 6893: if ( *exprptr == '{' ) /* assume we have {lcr} argument */
! 6894: { exprptr = texsubexpr(exprptr,subexpr+7,0,"{","}",0,0); /*add on lcr*/
! 6895: if ( *(subexpr+7) == '\000' ) goto end_of_job; /* quit if no lcr */
! 6896: strcat(subexpr,"$"); } /* add terminating $ to lcr */
! 6897: break;
! 6898: case 4: case 5: case 6: /* \begin{pmatrix} or b,B,v,Vmatrix */
! 6899: case 7: case 8:
! 6900: strcat(subexpr,"\\array{"); /*start with mimeTeX \array{ command*/
! 6901: break;
! 6902: case 9: /* gather */
! 6903: strcat(subexpr,"\\array{c$"); /* center equations */
! 6904: break;
! 6905: case 10: /* align */
! 6906: strcat(subexpr,"\\array{rclrclrclrclrclrcl$"); /* a&=b & c&=d & etc */
! 6907: break;
! 6908: case 11: /* verbatim */
! 6909: strcat(subexpr,"{\\rm "); /* {\rm ...} */
! 6910: /*strcat(subexpr,"\\\\{\\rm ");*/ /* \\{\rm } doesn't work in context */
! 6911: break;
! 6912: case 12: /* picture */
! 6913: strcat(subexpr,"\\picture"); /* picture environment */
! 6914: skipwhite(exprptr); /* bump to next non-white char */
! 6915: if ( *exprptr == '(' ) /*assume we have (width,height) arg*/
! 6916: { exprptr = texsubexpr(exprptr,subexpr+8,0,"(",")",0,1); /*add on arg*/
! 6917: if ( *(subexpr+8) == '\000' ) goto end_of_job; } /* quit if no arg */
! 6918: strcat(subexpr,"{"); /* opening { after (width,height) */
! 6919: break;
! 6920: } /* --- end-of-switch(ienviron) --- */
! 6921: /* -------------------------------------------------------------------------
! 6922: locate matching \end{...}
! 6923: -------------------------------------------------------------------------- */
! 6924: /* --- first \end following \begin --- */
! 6925: if ( (endptr=strstr(exprptr,endtoken)) /* find 1st \end following \begin */
! 6926: == NULL ) goto end_of_job; /* and quit if no \end found */
! 6927: /* --- find matching endptr by pushing past any nested \begin's --- */
! 6928: begptr = exprptr; /* start after first \begin{...} */
! 6929: while ( 1 ) /*break when we find matching \end*/
! 6930: {
! 6931: /* --- first, set ptr to closing } terminating current \end{...} --- */
! 6932: if ( (braceptr=strchr(endptr+1,'}')) /* find 1st } following \end{ */
! 6933: == NULL ) goto end_of_job; /* and quit if no } found */
! 6934: /* -- locate next nested \begin --- */
! 6935: if ( (begptr=strstr(begptr,begtoken)) /* find next \begin{...} */
! 6936: == NULL ) break; /*no more, so we have matching \end*/
! 6937: begptr += strlen(begtoken); /* push ptr past token */
! 6938: if ( begptr >= endptr ) break; /* past endptr, so not nested */
! 6939: /* --- have nested \begin, so push forward to next \end --- */
! 6940: nbegins++; /* count another nested \begin */
! 6941: if ( (endptr=strstr(endptr+strlen(endtoken),endtoken)) /* find next \end */
! 6942: == NULL ) goto end_of_job; /* and quit if none found */
! 6943: } /* --- end-of-while(1) --- */
! 6944: /* --- push expression past closing } of \end{} --- */
! 6945: *expression = braceptr+1; /* resume processing after } */
! 6946: /* -------------------------------------------------------------------------
! 6947: add on everything (i.e., the ...'s) between \begin{}[{}] ... \end{}
! 6948: -------------------------------------------------------------------------- */
! 6949: /* --- add on everything, completing subexpr for \begin{}...\end{} --- */
! 6950: sublen = strlen(subexpr); /* #chars in "preamble" */
! 6951: envlen = (int)(endptr-exprptr); /* #chars between \begin{}{}...\end */
! 6952: memcpy(subexpr+sublen,exprptr,envlen); /*concatanate environ after subexpr*/
! 6953: subexpr[sublen+envlen] = '\000'; /* and null-terminate */
! 6954: if ( 2 > 1 ) /* always... */
! 6955: strcat(subexpr,"}"); /* ...followed by terminating } */
! 6956: /* --- add terminating \right), etc, if necessary --- */
! 6957: if ( delims != (char *)NULL ) /* need closing delim */
! 6958: { strcat(subexpr,"\\"); /* start with \ for ),],},|,= */
! 6959: strcat(subexpr,delims+1); } /* add appropriate closing delim */
! 6960: /* -------------------------------------------------------------------------
! 6961: change nested \begin...\end to {\begin...\end} so \array{} can handle them
! 6962: -------------------------------------------------------------------------- */
! 6963: if ( nbegins > 0 ) /* have nested begins */
! 6964: if ( blevel < 2 ) /* only need to do this once */
! 6965: {
! 6966: begptr = subexpr; /* start at beginning of subexpr */
! 6967: while( (begptr=strstr(begptr,begtoken)) != NULL ) /* have \begin{...} */
! 6968: { strchange(0,begptr,"{"); /* \begin --> {\begin */
! 6969: begptr += strlen(begtoken); } /* continue past {\begin */
! 6970: endptr = subexpr; /* start at beginning of subexpr */
! 6971: while( (endptr=strstr(endptr,endtoken)) != NULL ) /* have \end{...} */
! 6972: if ( (braceptr=strchr(endptr+1,'}')) /* find 1st } following \end{ */
! 6973: == NULL ) goto end_of_job; /* and quit if no } found */
! 6974: else /* found terminating } */
! 6975: { strchange(0,braceptr,"}"); /* \end{...} --> \end{...}} */
! 6976: endptr = braceptr+1; } /* continue past \end{...} */
! 6977: } /* --- end-of-if(nbegins>0) --- */
! 6978: /* -------------------------------------------------------------------------
! 6979: post process as necessary
! 6980: -------------------------------------------------------------------------- */
! 6981: switch ( ienviron )
! 6982: {
! 6983: default: break; /* no post-processing required */
! 6984: case 10: /* align */
! 6985: strreplace(subexpr,"&=","#*@*#=",0); /* tag all &='s */
! 6986: strreplace(subexpr,"&<","#*@*#<",0); /* tag all &<'s */
! 6987: strreplace(subexpr,"&\\lt","#*@*#<",0); /* tag all &\lt's */
! 6988: strreplace(subexpr,"&\\leq","#*@*#\\leq",0); /* tag all &\leq's */
! 6989: strreplace(subexpr,"&>","#*@*#>",0); /* tag all &>'s */
! 6990: strreplace(subexpr,"&\\gt","#*@*#>",0); /* tag all &\gt's */
! 6991: strreplace(subexpr,"&\\geq","#*@*#\\geq",0); /* tag all &\geq's */
! 6992: if ( nbegins < 1 ) /* don't modify nested arrays */
! 6993: strreplace(subexpr,"&","\\hspace{10}&\\hspace{10}",0); /* add space */
! 6994: strreplace(subexpr,"#*@*#=","& = &",0); /*restore and xlate tagged &='s*/
! 6995: strreplace(subexpr,"#*@*#<","& \\lt &",0); /*restore, xlate tagged &<'s*/
! 6996: strreplace(subexpr,"#*@*#\\leq","& \\leq &",0); /*xlate tagged &\leq's*/
! 6997: strreplace(subexpr,"#*@*#>","& \\gt &",0); /*restore, xlate tagged &>'s*/
! 6998: strreplace(subexpr,"#*@*#\\geq","& \\geq &",0); /*xlate tagged &\geq's*/
! 6999: break;
! 7000: case 11: /* verbatim */
! 7001: strreplace(subexpr,"\n","\\\\",0); /* xlate \n newline to latex \\ */
! 7002: /*strcat(subexpr,"\\\\");*/ /* add final latex \\ newline */
! 7003: break;
! 7004: case 12: /* picture */
! 7005: strreplace(subexpr,"\\put "," ",0); /*remove \put's (not really needed)*/
! 7006: strreplace(subexpr,"\\put(","(",0); /*remove \put's (not really needed)*/
! 7007: strreplace(subexpr,"\\oval","\\circle",0); /* actually an ellipse */
! 7008: break;
! 7009: } /* --- end-of-switch(ienviron) --- */
! 7010: /* -------------------------------------------------------------------------
! 7011: return rasterized mimeTeX equivalent of \begin{}...\end{} environment
! 7012: -------------------------------------------------------------------------- */
! 7013: /* --- debugging output --- */
! 7014: if ( msgfp!=NULL && msglevel>=99 )
! 7015: fprintf(msgfp,"rastbegin> subexpr=%s\n",subexpr);
! 7016: /* --- rasterize mimeTeX equivalent of \begin{}...\end{} environment --- */
! 7017: sp = rasterize(subexpr,size); /* rasterize subexpr */
! 7018: end_of_job:
! 7019: blevel--; /* decrement \begin nesting level */
! 7020: return ( sp ); /* back to caller with sp or NULL */
! 7021: } /* --- end-of-function rastbegin() --- */
! 7022:
! 7023:
! 7024: /* ==========================================================================
! 7025: * Function: rastarray ( expression, size, basesp, arg1, arg2, arg3 )
! 7026: * Purpose: \array handler, returns a subraster corresponding to array
! 7027: * expression (immediately following \array) at font size
! 7028: * --------------------------------------------------------------------------
! 7029: * Arguments: expression (I/O) char ** to first char of null-terminated
! 7030: * string immediately following \array to be
! 7031: * rasterized, and returning ptr immediately
! 7032: * following last character processed.
! 7033: * size (I) int containing 0-4 default font size
! 7034: * basesp (I) subraster * to character (or subexpression)
! 7035: * immediately preceding \array
! 7036: * (unused, but passed for consistency)
! 7037: * arg1 (I) int unused
! 7038: * arg2 (I) int unused
! 7039: * arg3 (I) int unused
! 7040: * --------------------------------------------------------------------------
! 7041: * Returns: ( subraster * ) ptr to subraster corresponding to array
! 7042: * expression, or NULL for any parsing error
! 7043: * --------------------------------------------------------------------------
! 7044: * Notes: o Summary of syntax...
! 7045: * \array{3,lcrBC$a&b&c\\d&e&f\\etc}
! 7046: * o The 3,lcrBC$ part is an optional "preamble". The lcr means
! 7047: * what you think, i.e., "horizontal" left,center,right
! 7048: * justification down corresponding column. The new BC means
! 7049: * "vertical" baseline,center justification across corresponding
! 7050: * row. The leading 3 specifies the font size 0-4 to be used.
! 7051: * You may also specify +1,-1,+2,-2, etc, which is used as an
! 7052: * increment to the current font size, e.g., -1,lcr$ uses
! 7053: * one font size smaller than current. Without a leading
! 7054: * + or -, the font size is "absolute".
! 7055: * o The preamble can also be just lcrBC$ without a leading
! 7056: * size-part, or just 3$ without a trailing lcrBC-part.
! 7057: * The default size is whatever is current, and the
! 7058: * default justification is c(entered) and B(aseline).
! 7059: * ======================================================================= */
! 7060: /* --- entry point --- */
! 7061: subraster *rastarray ( char **expression, int size, subraster *basesp,
! 7062: int arg1, int arg2, int arg3 )
! 7063: {
! 7064: /* -------------------------------------------------------------------------
! 7065: Allocations and Declarations
! 7066: -------------------------------------------------------------------------- */
! 7067: char *texsubexpr(), subexpr[8210], *exprptr, /* parse array subexpr */
! 7068: subtok[4096], *subptr=subtok, /* & or \\ inside { }'s not a delim*/
! 7069: token[4096], *tokptr=token, /* token from subexpr to rasterize */
! 7070: *preamble(), *preptr=token; /*process optional size,lcr preamble*/
! 7071: char *coldelim="&", *rowdelim="\\"; /* need escaped rowdelim */
! 7072: int maxarraysz = 64; /* max #rows, cols */
! 7073: int justify[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* -1,0,+1 = l,c,r */
! 7074: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7075: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7076: hline[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* hline above row? */
! 7077: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7078: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7079: vline[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*vline left of col?*/
! 7080: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7081: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7082: colwidth[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*widest tokn in col*/
! 7083: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7084: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7085: rowheight[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* "highest" in row */
! 7086: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7087: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7088: fixcolsize[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*1=fixed col width*/
! 7089: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7090: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7091: fixrowsize[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*1=fixed row height*/
! 7092: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7093: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7094: rowbaseln[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* baseline for row */
! 7095: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7096: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7097: rowcenter[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*true = vcenter row*/
! 7098: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7099: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
! 7100: static int /* --- propagate global values across arrays --- */
! 7101: gjustify[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* -1,0,+1 = l,c,r */
! 7102: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7103: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7104: gcolwidth[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*widest tokn in col*/
! 7105: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7106: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7107: growheight[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* "highest" in row */
! 7108: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7109: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7110: gfixcolsize[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*1=fixed col width*/
! 7111: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7112: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7113: gfixrowsize[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*1=fixed row height*/
! 7114: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7115: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
! 7116: growcenter[65]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /*true = vcenter row*/
! 7117: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
! 7118: 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
! 7119: int rowglobal=0, colglobal=0, /* true to set global values */
! 7120: rowpropagate=0, colpropagate=0; /* true if propagating values */
! 7121: int irow,nrows=0, icol,ncols[65], /*#rows in array, #cols in each row*/
! 7122: maxcols=0; /* max# cols in any single row */
! 7123: int itoken, ntokens=0, /* index, total #tokens in array */
! 7124: subtoklen=0, /* strlen of {...} subtoken */
! 7125: istokwhite=1, /* true if token all whitespace */
! 7126: nnonwhite=0; /* #non-white tokens */
! 7127: int isescape=0,wasescape=0, /* current,prev chars escape? */
! 7128: ischarescaped=0, /* is current char escaped? */
! 7129: nescapes=0; /* #consecutive escapes */
! 7130: subraster *rasterize(), *toksp[1025], /* rasterize tokens */
! 7131: *new_subraster(), *arraysp=NULL; /* subraster for entire array */
! 7132: raster *arrayrp=NULL; /* raster for entire array */
! 7133: int delete_subraster(); /* free toksp[] workspace at eoj */
! 7134: int rowspace=2, colspace=4, /* blank space between rows, cols */
! 7135: hspace=1, vspace=1; /*space to accommodate hline,vline*/
! 7136: int width=0, height=0, /* width,height of array */
! 7137: leftcol=0, toprow=0; /*upper-left corner for cell in it*/
! 7138: int rastput(); /* embed tokens/cells in array */
! 7139: int rule_raster(); /* draw hlines and vlines in array */
! 7140: char *hlchar="\\hline", *hdchar="\\hdash"; /* token signals hline */
! 7141: char *texchar(), hltoken[1025]; /* extract \hline from token */
! 7142: int ishonly=0, hltoklen, minhltoklen=3; /*flag, token must be \hl or \hd*/
! 7143: int isnewrow=1; /* true for new row */
! 7144: int pixsz = 1; /*default #bits per pixel, 1=bitmap*/
! 7145: /* -------------------------------------------------------------------------
! 7146: Macros to determine extra raster space required for vline/hline
! 7147: -------------------------------------------------------------------------- */
! 7148: #define vlinespace(icol) \
! 7149: ( vline[icol] == 0? 0 : /* no vline so no space needed */ \
! 7150: ( icol<1 || icol>=maxcols? vspace+(colspace+1)/2 : vspace ) )
! 7151: #define hlinespace(irow) \
! 7152: ( hline[irow] == 0? 0 : /* no hline so no space needed */ \
! 7153: ( irow<1 || irow>=nrows? hspace+(rowspace+1)/2 : hspace ) )
! 7154: /* -------------------------------------------------------------------------
! 7155: Obtain array subexpression
! 7156: -------------------------------------------------------------------------- */
! 7157: /* --- parse for array subexpression, and bump expression past it --- */
! 7158: subexpr[1] = *subexpr = ' '; /* set two leading blanks */
! 7159: *expression = texsubexpr(*expression,subexpr+2,0,"{","}",0,0);
! 7160: if ( msglevel>=29 && msgfp!=NULL ) /* debugging, display array */
! 7161: fprintf(msgfp,"rastarray> %.256s\n",subexpr+2);
! 7162: if ( *(subexpr+2)=='\000' ) /* couldn't get subexpression */
! 7163: goto end_of_job; /* nothing to do, so quit */
! 7164: /* -------------------------------------------------------------------------
! 7165: process optional size,lcr preamble if present
! 7166: -------------------------------------------------------------------------- */
! 7167: /* --- reset size, get lcr's, and push exprptr past preamble --- */
! 7168: exprptr = preamble(subexpr+2,&size,preptr); /* reset size and get lcr's */
! 7169: /* --- init with global values --- */
! 7170: for(icol=0; icol<=maxarraysz; icol++) { /* propagate global values... */
! 7171: justify[icol] = gjustify[icol]; /* -1,0,+1 = l,c,r */
! 7172: colwidth[icol] = gcolwidth[icol]; /* column width */
! 7173: rowheight[icol] = growheight[icol]; /* row height */
! 7174: fixcolsize[icol] = gfixcolsize[icol]; /* 1=fixed col width */
! 7175: fixrowsize[icol] = gfixrowsize[icol]; /* 1=fixed row height */
! 7176: rowcenter[icol] = growcenter[icol]; } /* true = vcenter row */
! 7177: /* --- process lcr's, etc in preamble --- */
! 7178: itoken = 0; /* debugging flag */
! 7179: if ( msglevel>=29 && msgfp!=NULL ) /* debugging, display preamble */
! 7180: if ( *preptr != '\000' ) /* if we have one */
! 7181: fprintf(msgfp,"rastarray> preamble= \"%.256s\"\nrastarray> preamble: ",
! 7182: preptr);
! 7183: irow = icol = 0; /* init lcr counts */
! 7184: while ( *preptr != '\000' ) /* check preamble text for lcr */
! 7185: {
! 7186: char prepchar = *preptr; /* current preamble character */
! 7187: int prepcase = (islower(prepchar)?1:(isupper(prepchar)?2:0)); /*1,2,or 0*/
! 7188: if ( irow<maxarraysz && icol<maxarraysz )
! 7189: switch ( /*tolower*/(prepchar) )
! 7190: { default: break; /* just flush unrecognized chars */
! 7191: case 'l': justify[icol] = (-1); /*left-justify this column*/
! 7192: if (colglobal) gjustify[irow] = justify[irow]; break;
! 7193: case 'c': justify[icol] = (0); /* center this column */
! 7194: if (colglobal) gjustify[irow] = justify[irow]; break;
! 7195: case 'r': justify[icol] = (+1); /* right-justify this col */
! 7196: if (colglobal) gjustify[irow] = justify[irow]; break;
! 7197: case '|': vline[icol] += 1; break; /* solid vline left of col */
! 7198: case '.': vline[icol] = (-1); break; /*dashed vline left of col */
! 7199: case 'b': prepchar='B'; prepcase=2; /* alias for B */
! 7200: case 'B': break; /* baseline-justify row */
! 7201: case 'v': prepchar='C'; prepcase=2; /* alias for C */
! 7202: case 'C': rowcenter[irow] = 1; /* vertically center row */
! 7203: if (rowglobal) growcenter[irow] = rowcenter[irow]; break;
! 7204: case 'g': colglobal=1; prepcase=0; break; /* set global col values */
! 7205: case 'G': rowglobal=1; prepcase=0; break; /* set global row values */
! 7206: case '#': colglobal=rowglobal=1; break; } /* set global col,row vals */
! 7207: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7208: fprintf(msgfp," %c[%d]",prepchar,
! 7209: (prepcase==1?icol+1:(prepcase==2?irow+1:0)));
! 7210: preptr++; /* check next char for lcr */
! 7211: itoken++; /* #lcr's processed (debugging only)*/
! 7212: /* --- check for number or +number specifying colwidth or rowheight --- */
! 7213: if ( prepcase != 0 ) /* only check upper,lowercase */
! 7214: {
! 7215: int ispropagate = (*preptr=='+'?1:0); /* leading + propagates width/ht */
! 7216: if ( ispropagate ) /* set row or col propagation */
! 7217: if ( prepcase == 1 ) colpropagate = 1; /* propagating col values */
! 7218: else if ( prepcase == 2 ) rowpropagate = 1; /* propagating row values */
! 7219: if ( !colpropagate && prepcase == 1 )
! 7220: { colwidth[icol] = 0; /* reset colwidth */
! 7221: fixcolsize[icol] = 0; } /* reset width flag */
! 7222: if ( !rowpropagate && prepcase == 2 )
! 7223: { rowheight[irow] = 0; /* reset row height */
! 7224: fixrowsize[irow] = 0; } /* reset height flag */
! 7225: if ( ispropagate ) preptr++; /* bump past leading + */
! 7226: if ( isdigit(*preptr) ) /* digit follows character */
! 7227: { char *endptr = NULL; /* preptr set to 1st char after num*/
! 7228: int size = (int)(strtol(preptr,&endptr,10)); /* interpret number */
! 7229: char *whchars="?wh"; /* debugging width/height labels */
! 7230: preptr = endptr; /* skip over all digits */
! 7231: if ( size==0 || (size>=3&&size<=500) ) { /* sanity check */
! 7232: int index; /* icol,irow...maxarraysz index */
! 7233: if ( prepcase == 1 ) /* lowercase signifies colwidth */
! 7234: for(index=icol; index<=maxarraysz; index++) { /*propagate col size*/
! 7235: colwidth[index] = size; /* set colwidth to fixed size */
! 7236: fixcolsize[index] = (size>0?1:0); /* set fixed width flag */
! 7237: justify[index] = justify[icol]; /* and propagate justification */
! 7238: if ( colglobal ) { /* set global values */
! 7239: gcolwidth[index] = colwidth[index]; /* set global col width */
! 7240: gfixcolsize[index] = fixcolsize[index]; /*set global width flag*/
! 7241: gjustify[index] = justify[icol]; } /* set global col justify */
! 7242: if ( !ispropagate ) break; } /* don't propagate */
! 7243: else /* uppercase signifies rowheight */
! 7244: for(index=irow; index<=maxarraysz; index++) { /*propagate row size*/
! 7245: rowheight[index] = size; /* set rowheight to size */
! 7246: fixrowsize[index] = (size>0?1:0); /* set fixed height flag */
! 7247: rowcenter[index] = rowcenter[irow]; /* and propagate row center */
! 7248: if ( rowglobal ) { /* set global values */
! 7249: growheight[index] = rowheight[index]; /* set global row height */
! 7250: gfixrowsize[index] = fixrowsize[index]; /*set global height flag*/
! 7251: growcenter[index] = rowcenter[irow]; } /*set global row center*/
! 7252: if ( !ispropagate ) break; } /* don't propagate */
! 7253: } /* --- end-of-if(size>=3&&size<=500) --- */
! 7254: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7255: fprintf(msgfp,":%c=%d/fix#%d",whchars[prepcase],
! 7256: (prepcase==1?colwidth[icol]:rowheight[irow]),
! 7257: (prepcase==1?fixcolsize[icol]:fixrowsize[irow]));
! 7258: } /* --- end-of-if(isdigit()) --- */
! 7259: } /* --- end-of-if(prepcase!=0) --- */
! 7260: if ( prepcase == 1 ) icol++; /* bump col if lowercase lcr */
! 7261: else if ( prepcase == 2 ) irow++; /* bump row if uppercase BC */
! 7262: } /* --- end-of-while(*preptr!='\000') --- */
! 7263: if ( msglevel>=29 && msgfp!=NULL ) /* debugging, emit final newline */
! 7264: if ( itoken > 0 ) /* if we have preamble */
! 7265: fprintf(msgfp,"\n");
! 7266: /* -------------------------------------------------------------------------
! 7267: tokenize and rasterize components a & b \\ c & d \\ etc of subexpr
! 7268: -------------------------------------------------------------------------- */
! 7269: /* --- rasterize tokens one at a time, and maintain row,col counts --- */
! 7270: ncols[nrows] = 0; /* no tokens/cols in top row yet */
! 7271: while ( 1 ) /* scan chars till end */
! 7272: {
! 7273: /* --- local control flags --- */
! 7274: int iseox = (*exprptr == '\000'), /* null signals end-of-expression */
! 7275: iseor = iseox, /* \\ or eox signals end-of-row */
! 7276: iseoc = iseor; /* & or eor signals end-of-col */
! 7277: /* --- check for escapes --- */
! 7278: isescape = isthischar(*exprptr,ESCAPE); /* is current char escape? */
! 7279: wasescape= (!isnewrow&&isthischar(*(exprptr-1),ESCAPE)); /*prev char esc?*/
! 7280: nescapes = (wasescape?nescapes+1:0); /* # preceding consecutive escapes */
! 7281: ischarescaped = (nescapes%2==0?0:1); /* is current char escaped? */
! 7282: /* -----------------------------------------------------------------------
! 7283: check for {...} subexpression starting from where we are now
! 7284: ------------------------------------------------------------------------ */
! 7285: if ( *exprptr == '{' /* start of {...} subexpression */
! 7286: && !ischarescaped ) /* if not escaped \{ */
! 7287: {
! 7288: subptr = texsubexpr(exprptr,subtok,4095,"{","}",1,1); /*entire subexpr*/
! 7289: subtoklen = strlen(subtok); /* #chars in {...} */
! 7290: memcpy(tokptr,exprptr,subtoklen); /* copy {...} to accumulated token */
! 7291: tokptr += subtoklen; /* bump tokptr to end of token */
! 7292: exprptr += subtoklen; /* and bump exprptr past {...} */
! 7293: istokwhite = 0; /* signal non-empty token */
! 7294: continue; /* continue with char after {...} */
! 7295: } /* --- end-of-if(*exprptr=='{') --- */
! 7296: /* -----------------------------------------------------------------------
! 7297: check for end-of-row(\\) and/or end-of-col(&)
! 7298: ------------------------------------------------------------------------ */
! 7299: /* --- check for (escaped) end-of-row delimiter --- */
! 7300: if ( isescape && !ischarescaped ) /* current char is escaped */
! 7301: if ( isthischar(*(exprptr+1),rowdelim) /* next char is rowdelim */
! 7302: || *(exprptr+1) == '\000' ) /* or a pathological null */
! 7303: { iseor = 1; /* so set end-of-row flag */
! 7304: wasescape=isescape=nescapes = 0; } /* reset flags for new row */
! 7305: /* --- check for end-of-col delimiter --- */
! 7306: if (iseor /* end-of-row signals end-of-col */
! 7307: || (!ischarescaped&&isthischar(*exprptr,coldelim))) /*or unescaped coldel*/
! 7308: iseoc = 1; /* so set end-of-col flag */
! 7309: /* -----------------------------------------------------------------------
! 7310: rasterize completed token
! 7311: ------------------------------------------------------------------------ */
! 7312: if ( iseoc ) /* we have a completed token */
! 7313: {
! 7314: *tokptr = '\000'; /* first, null-terminate token */
! 7315: /* --- check first token in row for \hline or \hdash --- */
! 7316: ishonly = 0; /*init for token not only an \hline*/
! 7317: if ( ncols[nrows] == 0 ) /*\hline must be first token in row*/
! 7318: {
! 7319: tokptr=token; skipwhite(tokptr); /* skip whitespace after // */
! 7320: tokptr = texchar(tokptr,hltoken); /* extract first char from token */
! 7321: hltoklen = strlen(hltoken); /* length of first char */
! 7322: if ( hltoklen >= minhltoklen ) /*token must be at least \hl or \hd*/
! 7323: if ( memcmp(hlchar,hltoken,hltoklen) == 0 ) /* we have an \hline */
! 7324: hline[nrows] += 1; /* bump \hline count for row */
! 7325: else if ( memcmp(hdchar,hltoken,hltoklen) == 0 ) /*we have an \hdash*/
! 7326: hline[nrows] = (-1); /* set \hdash flag for row */
! 7327: if ( hline[nrows] != 0 ) /* \hline or \hdash prefixes token */
! 7328: { skipwhite(tokptr); /* flush whitespace after \hline */
! 7329: if ( *tokptr == '\000' /* end-of-expression after \hline */
! 7330: || isthischar(*tokptr,coldelim) ) /* or unescaped coldelim */
! 7331: istokwhite = ishonly = 1; /* so token contains \hline only */
! 7332: else /* token contains more than \hline */
! 7333: strcpy(token,tokptr); } /* so flush \hline from token */
! 7334: } /* --- end-of-if(ncols[nrows]==0) --- */
! 7335: /* --- rasterize completed token --- */
! 7336: toksp[ntokens] = (istokwhite? NULL : /* don't rasterize empty token */
! 7337: rasterize(token,size)); /* rasterize non-empty token */
! 7338: if ( toksp[ntokens] != NULL ) /* have a rasterized token */
! 7339: nnonwhite++; /* bump rasterized token count */
! 7340: /* --- maintain colwidth[], rowheight[] max, and rowbaseln[] --- */
! 7341: if ( toksp[ntokens] != NULL ) /* we have a rasterized token */
! 7342: {
! 7343: /* --- update max token "height" in current row, and baseline --- */
! 7344: int twidth = ((toksp[ntokens])->image)->width, /* width of token */
! 7345: theight = ((toksp[ntokens])->image)->height, /* height of token */
! 7346: tbaseln = (toksp[ntokens])->baseline, /* baseline of token */
! 7347: rheight = rowheight[nrows], /* current max height for row */
! 7348: rbaseln = rowbaseln[nrows]; /* current baseline for max height */
! 7349: if ( 0 || fixrowsize[nrows]==0 ) /* rowheight not fixed */
! 7350: rowheight[nrows] = /*max2( rheight,*/( /* current (max) rowheight */
! 7351: max2(rbaseln+1,tbaseln+1) /* max height above baseline */
! 7352: + max2(rheight-rbaseln-1,theight-tbaseln-1) ); /* plus max below */
! 7353: rowbaseln[nrows] = max2(rbaseln,tbaseln); /*max space above baseline*/
! 7354: /* --- update max token width in current column --- */
! 7355: icol = ncols[nrows]; /* current column index */
! 7356: if ( 0 || fixcolsize[icol]==0 ) /* colwidth not fixed */
! 7357: colwidth[icol] = max2(colwidth[icol],twidth); /*widest token in col*/
! 7358: } /* --- end-of-if(toksp[]!=NULL) --- */
! 7359: /* --- bump counters --- */
! 7360: if ( !ishonly ) /* don't count only an \hline */
! 7361: { ntokens++; /* bump total token count */
! 7362: ncols[nrows] += 1; } /* and bump #cols in current row */
! 7363: /* --- get ready for next token --- */
! 7364: tokptr = token; /* reset ptr for next token */
! 7365: istokwhite = 1; /* next token starts all white */
! 7366: } /* --- end-of-if(iseoc) --- */
! 7367: /* -----------------------------------------------------------------------
! 7368: bump row as necessary
! 7369: ------------------------------------------------------------------------ */
! 7370: if ( iseor ) /* we have a completed row */
! 7371: {
! 7372: maxcols = max2(maxcols,ncols[nrows]); /* max# cols in array */
! 7373: if ( ncols[nrows]>0 || hline[nrows]==0 ) /*ignore row with only \hline*/
! 7374: nrows++; /* bump row count */
! 7375: ncols[nrows] = 0; /* no cols in this row yet */
! 7376: if ( !iseox ) /* don't have a null yet */
! 7377: { exprptr++; /* bump past extra \ in \\ delim */
! 7378: iseox = (*exprptr == '\000'); } /* recheck for pathological \null */
! 7379: isnewrow = 1; /* signal start of new row */
! 7380: } /* --- end-of-if(iseor) --- */
! 7381: else
! 7382: isnewrow = 0; /* no longer first col of new row */
! 7383: /* -----------------------------------------------------------------------
! 7384: quit when done, or accumulate char in token and proceed to next char
! 7385: ------------------------------------------------------------------------ */
! 7386: /* --- quit when done --- */
! 7387: if ( iseox ) break; /* null terminator signalled done */
! 7388: /* --- accumulate chars in token --- */
! 7389: if ( !iseoc ) /* don't accumulate delimiters */
! 7390: { *tokptr++ = *exprptr; /* accumulate non-delim char */
! 7391: if ( !isthischar(*exprptr,WHITESPACE) ) /* this token isn't empty */
! 7392: istokwhite = 0; } /* so reset flag to rasterize it */
! 7393: /* --- ready for next char --- */
! 7394: exprptr++; /* bump ptr */
! 7395: } /* --- end-of-while(*exprptr!='\000') --- */
! 7396: /* --- make sure we got something to do --- */
! 7397: if ( nnonwhite < 1 ) /* completely empty array */
! 7398: goto end_of_job; /* NULL back to caller */
! 7399: /* -------------------------------------------------------------------------
! 7400: determine dimensions of array raster and allocate it
! 7401: -------------------------------------------------------------------------- */
! 7402: /* --- adjust colspace --- */
! 7403: colspace = 2 + 2*size; /* temp kludge */
! 7404: /* --- reset propagated sizes at boundaries of array --- */
! 7405: colwidth[maxcols] = rowheight[nrows] = 0; /* reset explicit 0's at edges */
! 7406: /* --- determine width of array raster --- */
! 7407: width = colspace*(maxcols-1); /* empty space between cols */
! 7408: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7409: fprintf(msgfp,"rastarray> %d cols, widths: ",maxcols);
! 7410: for ( icol=0; icol<=maxcols; icol++ ) /* and for each col */
! 7411: { width += colwidth[icol]; /*width of this col (0 for maxcols)*/
! 7412: width += vlinespace(icol); /*plus space for vline, if present*/
! 7413: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7414: fprintf(msgfp," %d=%2d+%d",icol+1,colwidth[icol],(vlinespace(icol))); }
! 7415: /* --- determine height of array raster --- */
! 7416: height = rowspace*(nrows-1); /* empty space between rows */
! 7417: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7418: fprintf(msgfp,"\nrastarray> %d rows, heights: ",nrows);
! 7419: for ( irow=0; irow<=nrows; irow++ ) /* and for each row */
! 7420: { height += rowheight[irow]; /*height of this row (0 for nrows)*/
! 7421: height += hlinespace(irow); /*plus space for hline, if present*/
! 7422: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7423: fprintf(msgfp," %d=%2d+%d",irow+1,rowheight[irow],(hlinespace(irow))); }
! 7424: /* --- allocate subraster and raster for array --- */
! 7425: if ( msglevel>=29 && msgfp!=NULL ) /* debugging */
! 7426: fprintf(msgfp,"\nrastarray> tot width=%d(colspc=%d) height=%d(rowspc=%d)\n",
! 7427: width,colspace, height,rowspace);
! 7428: if ( (arraysp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 7429: == NULL ) goto end_of_job; /* quit if failed */
! 7430: /* --- initialize subraster parameters --- */
! 7431: arraysp->type = IMAGERASTER; /* image */
! 7432: arraysp->symdef = NULL; /* not applicable for image */
! 7433: arraysp->baseline=min2(height/2+5,height-1); /*is a little above center good?*/
! 7434: arraysp->size = size; /* size (probably unneeded) */
! 7435: arrayrp = arraysp->image; /* raster embedded in subraster */
! 7436: /* -------------------------------------------------------------------------
! 7437: embed tokens/cells in array
! 7438: -------------------------------------------------------------------------- */
! 7439: itoken = 0; /* start with first token */
! 7440: toprow = 0; /* start at top row of array */
! 7441: for ( irow=0; irow<=nrows; irow++ ) /*tokens were accumulated row-wise*/
! 7442: {
! 7443: /* --- initialization for row --- */
! 7444: int baseline = rowbaseln[irow]; /* baseline for this row */
! 7445: if ( hline[irow] != 0 ) /* need hline above this row */
! 7446: { int hrow = (irow<1? 0 : toprow - rowspace/2); /* row for hline */
! 7447: if ( irow >= nrows ) hrow = height-1; /* row for bottom hline */
! 7448: rule_raster(arrayrp,hrow,0,width,1,(hline[irow]<0?1:0)); } /* hline */
! 7449: if ( irow >= nrows ) break; /*just needed \hline for irow=nrows*/
! 7450: toprow += hlinespace(irow); /* space for hline above irow */
! 7451: leftcol = 0; /* start at leftmost column */
! 7452: for ( icol=0; icol<ncols[irow]; icol++ ) /* go through cells in this row */
! 7453: {
! 7454: subraster *tsp = toksp[itoken]; /* token that belongs in this cell */
! 7455: if ( tsp != NULL ) /* have a rasterized cell token */
! 7456: {
! 7457: /* --- local parameters --- */
! 7458: int cwidth = colwidth[icol], /* total column width */
! 7459: twidth = (tsp->image)->width, /* token width */
! 7460: theight= (tsp->image)->height, /* token height */
! 7461: tokencol = 0, /*H offset (init for left justify)*/
! 7462: tokenrow = baseline - tsp->baseline;/*V offset (init for baseline)*/
! 7463: /* --- adjust leftcol for vline to left of icol, if present ---- */
! 7464: leftcol += vlinespace(icol); /* space for vline to left of col */
! 7465: /* --- reset justification (if not left-justified) --- */
! 7466: if ( justify[icol] == 0 ) /* but user wants it centered */
! 7467: tokencol = (cwidth-twidth+1)/2; /* so split margin left/right */
! 7468: else if ( justify[icol] == 1 ) /* or user wants right-justify */
! 7469: tokencol = cwidth-twidth; /* so put entire margin at left */
! 7470: /* --- reset vertical centering (if not baseline-aligned) --- */
! 7471: if ( rowcenter[irow] ) /* center cells in row vertically */
! 7472: tokenrow = (rowheight[irow]-theight)/2; /* center row */
! 7473: /* --- embed token raster at appropriate place in array raster --- */
! 7474: rastput(arrayrp,tsp->image, /* overlay cell token in array */
! 7475: toprow+ tokenrow, /*with aligned baseline or centered*/
! 7476: leftcol+tokencol, 1); /* and justified as requested */
! 7477: } /* --- end-of-if(tsp!=NULL) --- */
! 7478: itoken++; /* bump index for next cell */
! 7479: leftcol += colwidth[icol] + colspace /*move leftcol right for next col*/
! 7480: /* + vlinespace(icol) */ ; /*don't add space for vline to left of col*/
! 7481: } /* --- end-of-for(icol) --- */
! 7482: toprow += rowheight[irow] + rowspace; /* move toprow down for next row */
! 7483: } /* --- end-of-for(irow) --- */
! 7484: /* -------------------------------------------------------------------------
! 7485: draw vlines as necessary
! 7486: -------------------------------------------------------------------------- */
! 7487: leftcol = 0; /* start at leftmost column */
! 7488: for ( icol=0; icol<=maxcols; icol++ ) /* check each col for a vline */
! 7489: {
! 7490: if ( vline[icol] != 0 ) /* need vline to left of this col */
! 7491: { int vcol = (icol<1? 0 : leftcol - colspace/2); /* column for vline */
! 7492: if ( icol >= maxcols ) vcol = width-1; /*column for right edge vline*/
! 7493: rule_raster(arrayrp,0,vcol,1,height,(vline[icol]<0?2:0)); } /* vline */
! 7494: leftcol += vlinespace(icol); /* space for vline to left of col */
! 7495: if ( icol < maxcols ) /* don't address past end of array */
! 7496: leftcol += colwidth[icol] + colspace; /*move leftcol right for next col*/
! 7497: } /* --- end-of-for(icol) --- */
! 7498: /* -------------------------------------------------------------------------
! 7499: free workspace and return final result to caller
! 7500: -------------------------------------------------------------------------- */
! 7501: end_of_job:
! 7502: /* --- free workspace --- */
! 7503: if ( ntokens > 0 ) /* if we have workspace to free */
! 7504: while ( --ntokens >= 0 ) /* free each token subraster */
! 7505: if ( toksp[ntokens] != NULL ) /* if we rasterized this cell */
! 7506: delete_subraster(toksp[ntokens]); /* then free it */
! 7507: /* --- return final result to caller --- */
! 7508: return ( arraysp );
! 7509: } /* --- end-of-function rastarray() --- */
! 7510:
! 7511:
! 7512: /* ==========================================================================
! 7513: * Function: rastpicture ( expression, size, basesp, arg1, arg2, arg3 )
! 7514: * Purpose: \picture handler, returns subraster corresponding to picture
! 7515: * expression (immediately following \picture) at font size
! 7516: * --------------------------------------------------------------------------
! 7517: * Arguments: expression (I/O) char ** to first char of null-terminated
! 7518: * string immediately following \picture to be
! 7519: * rasterized, and returning ptr immediately
! 7520: * following last character processed.
! 7521: * size (I) int containing 0-4 default font size
! 7522: * basesp (I) subraster * to character (or subexpression)
! 7523: * immediately preceding \picture
! 7524: * (unused, but passed for consistency)
! 7525: * arg1 (I) int unused
! 7526: * arg2 (I) int unused
! 7527: * arg3 (I) int unused
! 7528: * --------------------------------------------------------------------------
! 7529: * Returns: ( subraster * ) ptr to subraster corresponding to picture
! 7530: * expression, or NULL for any parsing error
! 7531: * --------------------------------------------------------------------------
! 7532: * Notes: o Summary of syntax...
! 7533: * \picture(width,height){(x,y){pic_elem}~(x,y){pic_elem}~etc}
! 7534: * o
! 7535: * ======================================================================= */
! 7536: /* --- entry point --- */
! 7537: subraster *rastpicture ( char **expression, int size, subraster *basesp,
! 7538: int arg1, int arg2, int arg3 )
! 7539: {
! 7540: /* -------------------------------------------------------------------------
! 7541: Allocations and Declarations
! 7542: -------------------------------------------------------------------------- */
! 7543: char *texsubexpr(), picexpr[2049], *picptr=picexpr, /* picture {expre} */
! 7544: putexpr[256], *putptr,*multptr, /*[multi]put (x,y[;xinc,yinc;num])*/
! 7545: pream[64], *preptr, /* optional put preamble */
! 7546: picelem[1025]; /* picture element following put */
! 7547: subraster *rasterize(), *picelemsp=NULL, /* rasterize picture elements */
! 7548: *new_subraster(), *picturesp=NULL, /* subraster for entire picture */
! 7549: *oldworkingbox = workingbox; /* save working box on entry */
! 7550: raster *picturerp=NULL; /* raster for entire picture */
! 7551: int delete_subraster(); /* free picelemsp[] workspace */
! 7552: int pixsz = 1; /* pixels are one bit each */
! 7553: double strtod(), /* convert ascii params to doubles */
! 7554: x=0.0,y=0.0, /* x,y-coords for put,multiput*/
! 7555: xinc=0.0,yinc=0.0; /* x,y-incrementss for multiput*/
! 7556: int width=0, height=0, /* #pixels width,height of picture */
! 7557: ewidth=0, eheight=0, /* pic element width,height */
! 7558: ix=0,xpos=0, iy=0,ypos=0, /* mimeTeX x,y pixel coords */
! 7559: num=1, inum; /* number reps, index of element */
! 7560: int iscenter=0; /* center or lowerleft put position*/
! 7561: int *oldworkingparam = workingparam, /* save working param on entry */
! 7562: origin = 0; /* x,yinc ++=00 +-=01 -+=10 --=11 */
! 7563: int rastput(); /* embed elements in picture */
! 7564: int type_raster(); /* display debugging output */
! 7565: /* -------------------------------------------------------------------------
! 7566: First obtain (width,height) arguments immediately following \picture command
! 7567: -------------------------------------------------------------------------- */
! 7568: /* --- parse for (width,height) arguments, and bump expression past it --- */
! 7569: *expression = texsubexpr(*expression,putexpr,254,"(",")",0,0);
! 7570: if ( *putexpr == '\000' ) goto end_of_job; /* couldn't get (width,height) */
! 7571: /* --- now interpret width,height returned in putexpr --- */
! 7572: if ( (putptr=strchr(putexpr,',')) != NULL ) /* look for ',' in width,height*/
! 7573: *putptr = '\000'; /* found it, so replace ',' by '\0'*/
! 7574: width=height = iround(unitlength*strtod(putexpr,NULL)); /*width pixels*/
! 7575: if ( putptr != NULL ) /* 2nd arg, if present, is height */
! 7576: height = iround(unitlength*strtod(putptr+1,NULL)); /*in pixels*/
! 7577: /* -------------------------------------------------------------------------
! 7578: Then obtain entire picture {...} subexpression following (width,height)
! 7579: -------------------------------------------------------------------------- */
! 7580: /* --- parse for picture subexpression, and bump expression past it --- */
! 7581: *expression = texsubexpr(*expression,picexpr,2047,"{","}",0,0);
! 7582: if ( *picexpr == '\000' ) goto end_of_job; /* couldn't get {pic_elements} */
! 7583: /* -------------------------------------------------------------------------
! 7584: allocate subraster and raster for complete picture
! 7585: -------------------------------------------------------------------------- */
! 7586: /* --- sanity check on width,height args --- */
! 7587: if ( width < 2 || width > 600
! 7588: || height < 2 || height > 600 ) goto end_of_job;
! 7589: /* --- allocate and initialize subraster for constructed picture --- */
! 7590: if ( (picturesp=new_subraster(width,height,pixsz)) /*allocate new subraster*/
! 7591: == NULL ) goto end_of_job; /* quit if failed */
! 7592: workingbox = picturesp; /* set workingbox to our picture */
! 7593: /* --- initialize picture subraster parameters --- */
! 7594: picturesp->type = IMAGERASTER; /* image */
! 7595: picturesp->symdef = NULL; /* not applicable for image */
! 7596: picturesp->baseline = height/2 + 2; /* is a little above center good? */
! 7597: picturesp->size = size; /* size (probably unneeded) */
! 7598: picturerp = picturesp->image; /* raster embedded in subraster */
! 7599: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7600: fprintf(msgfp,"picture> width,height=%d,%d\n",width,height);
! 7601: /* -------------------------------------------------------------------------
! 7602: parse out each picture element, rasterize it, and place it in picture
! 7603: -------------------------------------------------------------------------- */
! 7604: while ( *picptr != '\000' ) /* until we run out of pic_elems */
! 7605: {
! 7606: /* -----------------------------------------------------------------------
! 7607: first obtain leading \[multi]put(x,y[;xinc,yinc;num]) args for pic_elem
! 7608: ------------------------------------------------------------------------ */
! 7609: /* --- init default values in case not explicitly supplied in args --- */
! 7610: x=y=0.0; xinc=yinc=0.0; num=1; /* init default values */
! 7611: iscenter = origin = 0; /* center, origin */
! 7612: /* --- get (pream$x,y;xinc,yinc;num ) args and bump picptr past it --- */
! 7613: while ( *picptr != '\000' ) /* skip invalid chars preceding ( */
! 7614: if ( *picptr == '(' ) break; /* found opening ( */
! 7615: else picptr++; /* else skip invalid char */
! 7616: picptr = texsubexpr(picptr,putexpr,254,"(",")",0,0);
! 7617: if ( *putexpr == '\000' ) goto end_of_job; /* couldn't get (x,y) */
! 7618: /* --- first look for $-terminated or for any non-digit preamble --- */
! 7619: *pream = '\000'; /* init preamble as empty string */
! 7620: if ( (putptr=strchr(putexpr,'$')) != NULL ) /*check for $ pream terminator*/
! 7621: { *putptr++ = '\000'; /* replace $ by '\0', bump past $ */
! 7622: strcpy(pream,putexpr); } /* copy leading preamble from put */
! 7623: else /* look for any non-digit preamble */
! 7624: { for ( preptr=pream,putptr=putexpr; ; putptr++ )
! 7625: if ( *putptr == '\000' /* end-of-putdata signalled */
! 7626: || !isalpha((int)(*putptr)) ) break; /* or found non-alpha char */
! 7627: else *preptr++ = *putptr; /* copy alpha char to preamble */
! 7628: *preptr = '\000'; } /* null-terminate preamble */
! 7629: /* --- interpret preamble --- */
! 7630: for ( preptr=pream; ; preptr++ ) /* examine each preamble char */
! 7631: if ( *preptr == '\000' ) break; /* end-of-preamble signalled */
! 7632: else switch ( tolower(*preptr) ) /* check lowercase preamble char */
! 7633: {
! 7634: default: break; /* unrecognized flag */
! 7635: case 'c': iscenter=1; break; /* center pic_elem at x,y coords */
! 7636: } /* --- end-of-switch --- */
! 7637: /* --- interpret x,y;xinc,yinc;num following preamble --- */
! 7638: if ( *putptr != '\000' ) /*check for put data after preamble*/
! 7639: {
! 7640: /* --- first squeeze preamble out of put expression --- */
! 7641: if ( *pream != '\000' ) strcpy(putexpr,putptr); /* squeeze out preamble */
! 7642: /* --- interpret x,y --- */
! 7643: if ( (multptr=strchr(putexpr,';')) != NULL ) /*semicolon signals multiput*/
! 7644: *multptr = '\000'; /* replace semicolon by '\0' */
! 7645: if ( (putptr=strchr(putexpr,',')) != NULL ) /* comma separates x,y */
! 7646: *putptr = '\000'; /* replace comma by '\0' */
! 7647: if ( *putexpr != '\000' ) /* leading , may be placeholder */
! 7648: x = unitlength*strtod(putexpr,NULL); /* x coord in pixels*/
! 7649: if ( putptr != NULL ) /* 2nd arg, if present, is y coord */
! 7650: y = unitlength*strtod(putptr+1,NULL); /* in pixels */
! 7651: /* --- interpret xinc,yinc,num if we have a multiput --- */
! 7652: if ( multptr != NULL ) /* found ';' signalling multiput */
! 7653: {
! 7654: if ( (preptr=strchr(multptr+1,';')) != NULL ) /* ';' preceding num arg*/
! 7655: *preptr = '\000'; /* replace ';' by '\0' */
! 7656: if ( (putptr=strchr(multptr+1,',')) != NULL ) /* ',' between xinc,yinc*/
! 7657: *putptr = '\000'; /* replace ',' by '\0' */
! 7658: if ( *(multptr+1) != '\000' ) /* leading , may be placeholder */
! 7659: xinc = unitlength*strtod(multptr+1,NULL); /* xinc in pixels */
! 7660: if ( putptr != NULL ) /* 2nd arg, if present, is yinc */
! 7661: yinc = unitlength*strtod(putptr+1,NULL); /* in user pixels */
! 7662: num = (preptr==NULL? 999 : atoi(preptr+1)); /*explicit num val or 999*/
! 7663: } /* --- end-of-if(multptr!=NULL) --- */
! 7664: } /* --- end-of-if(*preptr!='\000') --- */
! 7665: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7666: fprintf(msgfp,
! 7667: "picture> pream;x,y;xinc,yinc;num=\"%s\";%.2f,%.2f;%.2f,%.2f;%d\n",
! 7668: pream,x,y,xinc,yinc,num);
! 7669: /* -----------------------------------------------------------------------
! 7670: now obtain {...} picture element following [multi]put, and rasterize it
! 7671: ------------------------------------------------------------------------ */
! 7672: /* --- parse for {...} picture element and bump picptr past it --- */
! 7673: picptr = texsubexpr(picptr,picelem,1023,"{","}",0,0);
! 7674: if ( *picelem == '\000' ) goto end_of_job; /* couldn't get {pic_elem} */
! 7675: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7676: fprintf(msgfp, "picture> picelem=\"%.50s\"\n",picelem);
! 7677: /* --- rasterize picture element --- */
! 7678: origin = 0; /* init origin as working param */
! 7679: workingparam = &origin; /* and point working param to it */
! 7680: picelemsp = rasterize(picelem,size); /* rasterize picture element */
! 7681: if ( picelemsp == NULL ) continue; /* failed to rasterize, skip elem */
! 7682: ewidth = (picelemsp->image)->width; /* width of element, in pixels */
! 7683: eheight = (picelemsp->image)->height; /* height of element, in pixels */
! 7684: if ( origin == 55 ) iscenter = 1; /* origin set to (.5,.5) for center*/
! 7685: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7686: { fprintf(msgfp, "picture> ewidth,eheight,origin,num=%d,%d,%d,%d\n",
! 7687: ewidth,eheight,origin,num);
! 7688: if ( msglevel >= 999 ) type_raster(picelemsp->image,msgfp); }
! 7689: /* -----------------------------------------------------------------------
! 7690: embed element in picture (once, or multiple times if requested)
! 7691: ------------------------------------------------------------------------ */
! 7692: for ( inum=0; inum<num; inum++ ) /* once, or for num repetitions */
! 7693: {
! 7694: /* --- set x,y-coords for this iteration --- */
! 7695: ix = iround(x); iy = iround(y); /* round x,y to nearest integer */
! 7696: if ( iscenter ) /* place center of element at x,y */
! 7697: { xpos = ix - ewidth/2; /* x picture coord to center elem */
! 7698: ypos = height - iy - eheight/2; } /* y pixel coord to center elem */
! 7699: else /* default places lower-left at x,y*/
! 7700: { xpos = ix; /* set x pixel coord for left */
! 7701: if ( origin==10 || origin==11 ) /* x,yinc's are -+ or -- */
! 7702: xpos = ix - ewidth; /* so set for right instead */
! 7703: ypos = height - iy - eheight; /* set y pixel coord for lower */
! 7704: if ( origin==1 || origin==11 ) /* x,yinc's are +- or -- */
! 7705: ypos = height - iy; } /* so set for upper instead */
! 7706: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7707: fprintf(msgfp,
! 7708: "picture> inum,x,y,ix,iy,xpos,ypos=%d,%.2f,%.2f,%d,%d,%d,%d\n",
! 7709: inum,x,y,ix,iy,xpos,ypos);
! 7710: /* --- embed token raster at xpos,ypos, and quit if out-of-bounds --- */
! 7711: if ( !rastput(picturerp,picelemsp->image,ypos,xpos,0) ) break;
! 7712: /* --- apply increment --- */
! 7713: if ( xinc==0. && yinc==0. ) break; /* quit if both increments zero */
! 7714: x += xinc; y += yinc; /* increment coords for next iter */
! 7715: } /* --- end-of-for(inum) --- */
! 7716: /* --- free picture element subraster after embedding it in picture --- */
! 7717: delete_subraster(picelemsp); /* done with subraster, so free it */
! 7718: } /* --- end-of-while(*picptr!=0) --- */
! 7719: /* -------------------------------------------------------------------------
! 7720: return picture constructed from pic_elements to caller
! 7721: -------------------------------------------------------------------------- */
! 7722: end_of_job:
! 7723: workingbox = oldworkingbox; /* restore original working box */
! 7724: workingparam = oldworkingparam; /* restore original working param */
! 7725: return ( picturesp ); /* return our picture to caller */
! 7726: } /* --- end-of-function rastpicture() --- */
! 7727:
! 7728:
! 7729: /* ==========================================================================
! 7730: * Function: rastline ( expression, size, basesp, arg1, arg2, arg3 )
! 7731: * Purpose: \line handler, returns subraster corresponding to line
! 7732: * parameters (xinc,yinc){xlen}
! 7733: * --------------------------------------------------------------------------
! 7734: * Arguments: expression (I/O) char ** to first char of null-terminated
! 7735: * string immediately following \line to be
! 7736: * rasterized, and returning ptr immediately
! 7737: * following last character processed.
! 7738: * size (I) int containing 0-4 default font size
! 7739: * basesp (I) subraster * to character (or subexpression)
! 7740: * immediately preceding \line
! 7741: * (unused, but passed for consistency)
! 7742: * arg1 (I) int unused
! 7743: * arg2 (I) int unused
! 7744: * arg3 (I) int unused
! 7745: * --------------------------------------------------------------------------
! 7746: * Returns: ( subraster * ) ptr to subraster corresponding to line
! 7747: * requested, or NULL for any parsing error
! 7748: * --------------------------------------------------------------------------
! 7749: * Notes: o Summary of syntax...
! 7750: * \line(xinc,yinc){xlen}
! 7751: * o if {xlen} not given, then it's assumed xlen = |xinc|
! 7752: * ======================================================================= */
! 7753: /* --- entry point --- */
! 7754: subraster *rastline ( char **expression, int size, subraster *basesp,
! 7755: int arg1, int arg2, int arg3 )
! 7756: {
! 7757: /* -------------------------------------------------------------------------
! 7758: Allocations and Declarations
! 7759: -------------------------------------------------------------------------- */
! 7760: char *texsubexpr(),linexpr[257], *xptr=linexpr; /*line(xinc,yinc){xlen}*/
! 7761: subraster *new_subraster(), *linesp=NULL; /* subraster for line */
! 7762: /*char *origexpression = *expression;*/ /*original expression after \line*/
! 7763: int pixsz = 1; /* pixels are one bit each */
! 7764: double strtod(), /* convert ascii params to doubles */
! 7765: xinc=0.0, yinc=0.0, /* x,y-increments for line, */
! 7766: xlen=0.0, ylen=0.0; /* x,y lengths for line */
! 7767: int width=0, height=0; /* #pixels width,height of line */
! 7768: int istop=0, isright=0, /* origin at bot-left if x,yinc>=0 */
! 7769: origin = 0; /* x,yinc: ++=00 +-=01 -+=10 --=11 */
! 7770: int line_raster(); /* draw line in linesp->image */
! 7771: /* -------------------------------------------------------------------------
! 7772: obtain (xinc,yinc) arguments immediately following \line command
! 7773: -------------------------------------------------------------------------- */
! 7774: /* --- parse for (xinc,yinc) arguments, and bump expression past it --- */
! 7775: *expression = texsubexpr(*expression,linexpr,253,"(",")",0,0);
! 7776: if ( *linexpr == '\000' ) goto end_of_job; /* couldn't get (xinc,yinc) */
! 7777: /* --- now interpret xinc,yinc returned in linexpr --- */
! 7778: if ( (xptr=strchr(linexpr,',')) != NULL ) /* look for ',' in xinc,yinc */
! 7779: *xptr = '\000'; /* found it, so replace ',' by '\0'*/
! 7780: if ( *linexpr != '\000' ) /* check against missing 1st arg */
! 7781: xinc = xlen = strtod(linexpr,NULL); /* xinc in user units */
! 7782: if ( xptr != NULL ) /* 2nd arg, if present, is yinc */
! 7783: yinc = ylen = strtod(xptr+1,NULL); /* in user units */
! 7784: /* -------------------------------------------------------------------------
! 7785: obtain optional {xlen} following (xinc,yinc), and calculate ylen
! 7786: -------------------------------------------------------------------------- */
! 7787: /* --- check if {xlen} given --- */
! 7788: if ( *(*expression) == '{' ) /*have {xlen} if leading char is { */
! 7789: {
! 7790: /* --- parse {xlen} and bump expression past it, interpret as double --- */
! 7791: *expression = texsubexpr(*expression,linexpr,253,"{","}",0,0);
! 7792: if ( *linexpr == '\000' ) goto end_of_job; /* couldn't get {xlen} */
! 7793: xlen = strtod(linexpr,NULL); /* xlen in user units */
! 7794: /* --- set other values accordingly --- */
! 7795: if ( xlen < 0.0 ) xinc = -xinc; /* if xlen negative, flip xinc sign*/
! 7796: if ( xinc != 0.0 ) ylen = xlen*yinc/xinc; /* set ylen from xlen and slope*/
! 7797: else xlen = 0.0; /* can't have xlen if xinc=0 */
! 7798: } /* --- end-of-if(*(*expression)=='{') --- */
! 7799: /* -------------------------------------------------------------------------
! 7800: calculate width,height, etc, based on xlen,ylen, etc
! 7801: -------------------------------------------------------------------------- */
! 7802: /* --- force lengths positive --- */
! 7803: xlen = absval(xlen); /* force xlen positive */
! 7804: ylen = absval(ylen); /* force ylen positive */
! 7805: /* --- calculate corresponding lengths in pixels --- */
! 7806: width = max2(1,iround(unitlength*xlen)); /*scale by unitlength and round,*/
! 7807: height = max2(1,iround(unitlength*ylen)); /* and must be at least 1 pixel */
! 7808: /* --- set origin corner, x,yinc's: ++=0=(0,0) +-=1=(0,1) -+=10=(1,0) --- */
! 7809: if ( xinc < 0.0 ) isright = 1; /*negative xinc, so corner is (1,?)*/
! 7810: if ( yinc < 0.0 ) istop = 1; /*negative yinc, so corner is (?,1)*/
! 7811: origin = isright*10 + istop; /* interpret 0=(0,0), 11=(1,1), etc*/
! 7812: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7813: fprintf(msgfp,"rastline> width,height,origin;x,yinc=%d,%d,%d;%g,%g\n",
! 7814: width,height,origin,xinc,yinc);
! 7815: /* -------------------------------------------------------------------------
! 7816: allocate subraster and raster for complete picture
! 7817: -------------------------------------------------------------------------- */
! 7818: /* --- sanity check on width,height args --- */
! 7819: if ( width < 1 || width > 600
! 7820: || height < 1 || height > 600 ) goto end_of_job;
! 7821: /* --- allocate and initialize subraster for constructed line --- */
! 7822: if ( (linesp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 7823: == NULL ) goto end_of_job; /* quit if failed */
! 7824: /* --- initialize line subraster parameters --- */
! 7825: linesp->type = IMAGERASTER; /* image */
! 7826: linesp->symdef = NULL; /* not applicable for image */
! 7827: linesp->baseline = height/2 + 2; /* is a little above center good? */
! 7828: linesp->size = size; /* size (probably unneeded) */
! 7829: /* -------------------------------------------------------------------------
! 7830: draw the line
! 7831: -------------------------------------------------------------------------- */
! 7832: line_raster ( linesp->image, /* embedded raster image */
! 7833: (istop? 0 : height-1), /* row0, from bottom or top */
! 7834: (isright? width-1 : 0), /* col0, from left or right */
! 7835: (istop? height-1 : 0), /* row1, to top or bottom */
! 7836: (isright? 0 : width-1), /* col1, to right or left */
! 7837: 1 ); /* line thickness is 1 pixel */
! 7838: /* -------------------------------------------------------------------------
! 7839: return constructed line to caller
! 7840: -------------------------------------------------------------------------- */
! 7841: end_of_job:
! 7842: if ( workingparam != NULL ) /* caller wants origin */
! 7843: *workingparam = origin; /* return origin corner to caller */
! 7844: return ( linesp ); /* return line to caller */
! 7845: } /* --- end-of-function rastline() --- */
! 7846:
! 7847:
! 7848: /* ==========================================================================
! 7849: * Function: rastcircle ( expression, size, basesp, arg1, arg2, arg3 )
! 7850: * Purpose: \circle handler, returns subraster corresponding to ellipse
! 7851: * parameters (xdiam[,ydiam])
! 7852: * --------------------------------------------------------------------------
! 7853: * Arguments: expression (I/O) char ** to first char of null-terminated
! 7854: * string immediately following \circle to be
! 7855: * rasterized, and returning ptr immediately
! 7856: * following last character processed.
! 7857: * size (I) int containing 0-4 default font size
! 7858: * basesp (I) subraster * to character (or subexpression)
! 7859: * immediately preceding \circle
! 7860: * (unused, but passed for consistency)
! 7861: * arg1 (I) int unused
! 7862: * arg2 (I) int unused
! 7863: * arg3 (I) int unused
! 7864: * --------------------------------------------------------------------------
! 7865: * Returns: ( subraster * ) ptr to subraster corresponding to ellipse
! 7866: * requested, or NULL for any parsing error
! 7867: * --------------------------------------------------------------------------
! 7868: * Notes: o Summary of syntax...
! 7869: * \circle(xdiam[,ydiam])
! 7870: * o
! 7871: * ======================================================================= */
! 7872: /* --- entry point --- */
! 7873: subraster *rastcircle ( char **expression, int size, subraster *basesp,
! 7874: int arg1, int arg2, int arg3 )
! 7875: {
! 7876: /* -------------------------------------------------------------------------
! 7877: Allocations and Declarations
! 7878: -------------------------------------------------------------------------- */
! 7879: char *texsubexpr(), circexpr[512],*xptr=circexpr; /*circle(xdiam[,ydiam])*/
! 7880: char *qptr=NULL, quads[256]="1234"; /* default to draw all quadrants */
! 7881: double theta0=0.0, theta1=0.0; /* ;theta0,theta1 instead of ;quads*/
! 7882: subraster *new_subraster(), *circsp=NULL; /* subraster for ellipse */
! 7883: int pixsz = 1; /* pixels are one bit each */
! 7884: double strtod(), /* convert ascii params to doubles */
! 7885: xdiam=0.0, ydiam=0.0; /* x,y major/minor axes/diameters */
! 7886: int width=0, height=0; /* #pixels width,height of ellipse */
! 7887: int thickness = 1; /* drawn lines are one pixel thick */
! 7888: int origin = 55; /* force origin centered */
! 7889: int circle_raster(), /* draw ellipse in circsp->image */
! 7890: circle_recurse(); /* for theta0,theta1 args */
! 7891: /* -------------------------------------------------------------------------
! 7892: obtain (xdiam[,ydiam]) arguments immediately following \circle command
! 7893: -------------------------------------------------------------------------- */
! 7894: /* --- parse for (xdiam[,ydiam]) args, and bump expression past it --- */
! 7895: *expression = texsubexpr(*expression,circexpr,511,"(",")",0,0);
! 7896: if ( *circexpr == '\000' ) goto end_of_job; /* couldn't get (xdiam[,ydiam])*/
! 7897: /* --- now interpret xdiam[,ydiam] returned in circexpr --- */
! 7898: if ( (qptr=strchr(circexpr,';')) != NULL ) /* semicolon signals quads data */
! 7899: { *qptr = '\000'; /* replace semicolon by '\0' */
! 7900: strcpy(quads,qptr+1); /* save user-requested quads */
! 7901: if ( (qptr=strchr(quads,',')) != NULL ) /* have theta0,theta1 instead */
! 7902: { *qptr = '\000'; /* replace , with null */
! 7903: theta0 = strtod(quads,NULL); /* theta0 precedes , */
! 7904: theta1 = strtod(qptr+1,NULL); /* theta1 follows , */
! 7905: qptr = NULL; } /* signal thetas instead of quads */
! 7906: else
! 7907: qptr = quads; } /* set qptr arg for circle_raster()*/
! 7908: else /* no ;quads at all */
! 7909: qptr = quads; /* default to all 4 quadrants */
! 7910: if ( (xptr=strchr(circexpr,',')) != NULL ) /* look for ',' in xdiam[,ydiam]*/
! 7911: *xptr = '\000'; /* found it, so replace ',' by '\0'*/
! 7912: xdiam = ydiam = strtod(circexpr,NULL); /* xdiam=ydiam in user units */
! 7913: if ( xptr != NULL ) /* 2nd arg, if present, is ydiam */
! 7914: ydiam = strtod(xptr+1,NULL); /* in user units */
! 7915: /* -------------------------------------------------------------------------
! 7916: calculate width,height, etc
! 7917: -------------------------------------------------------------------------- */
! 7918: /* --- calculate width,height in pixels --- */
! 7919: width = max2(1,iround(unitlength*xdiam)); /*scale by unitlength and round,*/
! 7920: height = max2(1,iround(unitlength*ydiam)); /* and must be at least 1 pixel */
! 7921: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 7922: fprintf(msgfp,"rastcircle> width,height;quads=%d,%d,%s\n",
! 7923: width,height,(qptr==NULL?"default":qptr));
! 7924: /* -------------------------------------------------------------------------
! 7925: allocate subraster and raster for complete picture
! 7926: -------------------------------------------------------------------------- */
! 7927: /* --- sanity check on width,height args --- */
! 7928: if ( width < 1 || width > 600
! 7929: || height < 1 || height > 600 ) goto end_of_job;
! 7930: /* --- allocate and initialize subraster for constructed ellipse --- */
! 7931: if ( (circsp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 7932: == NULL ) goto end_of_job; /* quit if failed */
! 7933: /* --- initialize ellipse subraster parameters --- */
! 7934: circsp->type = IMAGERASTER; /* image */
! 7935: circsp->symdef = NULL; /* not applicable for image */
! 7936: circsp->baseline = height/2 + 2; /* is a little above center good? */
! 7937: circsp->size = size; /* size (probably unneeded) */
! 7938: /* -------------------------------------------------------------------------
! 7939: draw the ellipse
! 7940: -------------------------------------------------------------------------- */
! 7941: if ( qptr != NULL ) /* have quads */
! 7942: circle_raster ( circsp->image, /* embedded raster image */
! 7943: 0, 0, /* row0,col0 are upper-left corner */
! 7944: height-1, width-1, /* row1,col1 are lower-right */
! 7945: thickness, /* line thickness is 1 pixel */
! 7946: qptr ); /* "1234" quadrants to be drawn */
! 7947: else /* have theta0,theta1 */
! 7948: circle_recurse ( circsp->image, /* embedded raster image */
! 7949: 0, 0, /* row0,col0 are upper-left corner */
! 7950: height-1, width-1, /* row1,col1 are lower-right */
! 7951: thickness, /* line thickness is 1 pixel */
! 7952: theta0,theta1 ); /* theta0,theta1 arc to be drawn */
! 7953: /* -------------------------------------------------------------------------
! 7954: return constructed ellipse to caller
! 7955: -------------------------------------------------------------------------- */
! 7956: end_of_job:
! 7957: if ( workingparam != NULL ) /* caller wants origin */
! 7958: *workingparam = origin; /* return center origin to caller */
! 7959: return ( circsp ); /* return ellipse to caller */
! 7960: } /* --- end-of-function rastcircle() --- */
! 7961:
! 7962:
! 7963: /* ==========================================================================
! 7964: * Function: rastbezier ( expression, size, basesp, arg1, arg2, arg3 )
! 7965: * Purpose: \bezier handler, returns subraster corresponding to bezier
! 7966: * parameters (col0,row0)(col1,row1)(colt,rowt)
! 7967: * --------------------------------------------------------------------------
! 7968: * Arguments: expression (I/O) char ** to first char of null-terminated
! 7969: * string immediately following \bezier to be
! 7970: * rasterized, and returning ptr immediately
! 7971: * following last character processed.
! 7972: * size (I) int containing 0-5 default font size
! 7973: * basesp (I) subraster * to character (or subexpression)
! 7974: * immediately preceding \bezier
! 7975: * (unused, but passed for consistency)
! 7976: * arg1 (I) int unused
! 7977: * arg2 (I) int unused
! 7978: * arg3 (I) int unused
! 7979: * --------------------------------------------------------------------------
! 7980: * Returns: ( subraster * ) ptr to subraster corresponding to bezier
! 7981: * requested, or NULL for any parsing error
! 7982: * --------------------------------------------------------------------------
! 7983: * Notes: o Summary of syntax...
! 7984: * \bezier(col1,row1)(colt,rowt)
! 7985: * o col0=0,row0=0 assumed, i.e., given by
! 7986: * \picture(){~(col0,row0){\bezier(col1,row1)(colt,rowt)}~}
! 7987: * ======================================================================= */
! 7988: /* --- entry point --- */
! 7989: subraster *rastbezier ( char **expression, int size, subraster *basesp,
! 7990: int arg1, int arg2, int arg3 )
! 7991: {
! 7992: /* -------------------------------------------------------------------------
! 7993: Allocations and Declarations
! 7994: -------------------------------------------------------------------------- */
! 7995: subraster *new_subraster(), *bezsp=NULL; /* subraster for bezier */
! 7996: char *texsubexpr(), bezexpr[129],*xptr=bezexpr; /*\bezier(r,c)(r,c)(r,c)*/
! 7997: double strtod(); /* convert ascii params to doubles */
! 7998: double r0=0.0,c0=0.0, r1=0.0,c1=0.0, rt=0.0,ct=0.0, /* bezier points */
! 7999: rmid=0.0, cmid=0.0, /* coords at parameterized midpoint*/
! 8000: rmin=0.0, cmin=0.0, /* minimum r,c */
! 8001: rmax=0.0, cmax=0.0, /* maximum r,c */
! 8002: rdelta=0.0, cdelta=0.0, /* rmax-rmin, cmax-cmin */
! 8003: r=0.0, c=0.0; /* some point */
! 8004: int iarg=0; /* 0=r0,c0 1=r1,c1 2=rt,ct */
! 8005: int width=0, height=0; /* dimensions of bezier raster */
! 8006: int pixsz = 1; /* pixels are one bit each */
! 8007: /*int thickness = 1;*/ /* drawn lines are one pixel thick */
! 8008: int origin = 0; /*c's,r's reset to lower-left origin*/
! 8009: int bezier_raster(); /* draw bezier in bezsp->image */
! 8010: /* -------------------------------------------------------------------------
! 8011: obtain (c1,r1)(ct,rt) args immediately following \bezier command
! 8012: -------------------------------------------------------------------------- */
! 8013: for ( iarg=1; iarg<=2; iarg++ ) /* 0=c0,r0 1=c1,r1 2=ct,rt */
! 8014: {
! 8015: /* --- parse for (r,c) args, and bump expression past them all --- */
! 8016: *expression = texsubexpr(*expression,bezexpr,127,"(",")",0,0);
! 8017: if ( *bezexpr == '\000' ) goto end_of_job; /* couldn't get (r,c)*/
! 8018: /* --- now interpret (r,c) returned in bezexpr --- */
! 8019: c = r = 0.0; /* init x-coord=col, y-coord=row */
! 8020: if ( (xptr=strchr(bezexpr,',')) != NULL ) /* comma separates row,col */
! 8021: { *xptr = '\000'; /* found it, so replace ',' by '\0'*/
! 8022: r = unitlength*strtod(xptr+1,NULL); } /* row=y-coord in pixels */
! 8023: c = unitlength*strtod(bezexpr,NULL); /* col=x-coord in pixels */
! 8024: /* --- store r,c --- */
! 8025: switch ( iarg )
! 8026: { case 0: r0=r; c0=c; break;
! 8027: case 1: r1=r; c1=c; break;
! 8028: case 2: rt=r; ct=c; break; }
! 8029: } /* --- end-of-for(iarg) --- */
! 8030: /* --- determine midpoint and maximum,minimum points --- */
! 8031: rmid = 0.5*(rt + 0.5*(r0+r1)); /* y-coord at middle of bezier */
! 8032: cmid = 0.5*(ct + 0.5*(c0+c1)); /* x-coord at middle of bezier */
! 8033: rmin = min3(r0,r1,rmid); /* lowest row */
! 8034: cmin = min3(c0,c1,cmid); /* leftmost col */
! 8035: rmax = max3(r0,r1,rmid); /* highest row */
! 8036: cmax = max3(c0,c1,cmid); /* rightmost col */
! 8037: rdelta = rmax-rmin; /* height */
! 8038: cdelta = cmax-cmin; /* width */
! 8039: /* --- rescale coords so we start at 0,0 --- */
! 8040: r0 -= rmin; c0 -= cmin; /* rescale r0,c0 */
! 8041: r1 -= rmin; c1 -= cmin; /* rescale r1,c1 */
! 8042: rt -= rmin; ct -= cmin; /* rescale rt,ct */
! 8043: /* --- flip rows so 0,0 becomes lower-left corner instead of upper-left--- */
! 8044: r0 = rdelta - r0 + 1; /* map 0-->height-1, height-1-->0 */
! 8045: r1 = rdelta - r1 + 1;
! 8046: rt = rdelta - rt + 1;
! 8047: /* --- determine width,height of raster needed for bezier --- */
! 8048: width = (int)(cdelta + 0.9999) + 1; /* round width up */
! 8049: height = (int)(rdelta + 0.9999) + 1; /* round height up */
! 8050: if ( msgfp!=NULL && msglevel>=29 ) /* debugging */
! 8051: fprintf(msgfp,"rastbezier> width,height,origin=%d,%d,%d; c0,r0=%g,%g; "
! 8052: "c1,r1=%g,%g\n rmin,mid,max=%g,%g,%g; cmin,mid,max=%g,%g,%g\n",
! 8053: width,height,origin, c0,r0, c1,r1, rmin,rmid,rmax, cmin,cmid,cmax);
! 8054: /* -------------------------------------------------------------------------
! 8055: allocate raster
! 8056: -------------------------------------------------------------------------- */
! 8057: /* --- sanity check on width,height args --- */
! 8058: if ( width < 1 || width > 600
! 8059: || height < 1 || height > 600 ) goto end_of_job;
! 8060: /* --- allocate and initialize subraster for constructed bezier --- */
! 8061: if ( (bezsp=new_subraster(width,height,pixsz)) /* allocate new subraster */
! 8062: == NULL ) goto end_of_job; /* quit if failed */
! 8063: /* --- initialize bezier subraster parameters --- */
! 8064: bezsp->type = IMAGERASTER; /* image */
! 8065: bezsp->symdef = NULL; /* not applicable for image */
! 8066: bezsp->baseline = height/2 + 2; /* is a little above center good? */
! 8067: bezsp->size = size; /* size (probably unneeded) */
! 8068: /* -------------------------------------------------------------------------
! 8069: draw the bezier
! 8070: -------------------------------------------------------------------------- */
! 8071: bezier_raster ( bezsp->image, /* embedded raster image */
! 8072: r0, c0, /* row0,col0 are lower-left corner */
! 8073: r1, c1, /* row1,col1 are upper-right */
! 8074: rt, ct ); /* bezier tangent point */
! 8075: /* -------------------------------------------------------------------------
! 8076: return constructed bezier to caller
! 8077: -------------------------------------------------------------------------- */
! 8078: end_of_job:
! 8079: if ( workingparam != NULL ) /* caller wants origin */
! 8080: *workingparam = origin; /* return center origin to caller */
! 8081: return ( bezsp ); /* return bezier to caller */
! 8082: } /* --- end-of-function rastbezier() --- */
! 8083:
! 8084:
! 8085: /* ==========================================================================
! 8086: * Function: rastraise ( expression, size, basesp, arg1, arg2, arg3 )
! 8087: * Purpose: \raisebox{lift}{subexpression} handler, returns subraster
! 8088: * containing subexpression with its baseline "lifted" by lift
! 8089: * pixels, scaled by \unitlength, or "lowered" if lift arg
! 8090: * negative
! 8091: * --------------------------------------------------------------------------
! 8092: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8093: * string immediately following \raisebox to be
! 8094: * rasterized, and returning ptr immediately
! 8095: * following last character processed.
! 8096: * size (I) int containing 0-5 default font size
! 8097: * basesp (I) subraster * to character (or subexpression)
! 8098: * immediately preceding \rotatebox
! 8099: * (unused, but passed for consistency)
! 8100: * arg1 (I) int unused
! 8101: * arg2 (I) int unused
! 8102: * arg3 (I) int unused
! 8103: * --------------------------------------------------------------------------
! 8104: * Returns: ( subraster * ) ptr to subraster corresponding to \raisebox
! 8105: * requested, or NULL for any parsing error
! 8106: * --------------------------------------------------------------------------
! 8107: * Notes: o Summary of syntax...
! 8108: * \raisebox{lift}{subexpression}
! 8109: * o
! 8110: * ======================================================================= */
! 8111: /* --- entry point --- */
! 8112: subraster *rastraise ( char **expression, int size, subraster *basesp,
! 8113: int arg1, int arg2, int arg3 )
! 8114: {
! 8115: /* -------------------------------------------------------------------------
! 8116: Allocations and Declarations
! 8117: -------------------------------------------------------------------------- */
! 8118: char *texsubexpr(), subexpr[8192], *liftexpr=subexpr; /* args */
! 8119: subraster *rasterize(), *raisesp=NULL; /* rasterize subexpr to be raised */
! 8120: int lift=0; /* amount to raise/lower baseline */
! 8121: /* -------------------------------------------------------------------------
! 8122: obtain {lift} argument immediately following \raisebox command
! 8123: -------------------------------------------------------------------------- */
! 8124: /* --- parse for {lift} arg, and bump expression past it --- */
! 8125: *expression = texsubexpr(*expression,liftexpr,0,"{","}",0,0);
! 8126: if ( *liftexpr == '\000' ) goto end_of_job; /* couldn't get {lift} */
! 8127: lift = (int)((unitlength*strtod(liftexpr,NULL))+0.0); /*{lift} to integer*/
! 8128: if ( abs(lift) > 200 ) lift=0; /* sanity check */
! 8129: /* -------------------------------------------------------------------------
! 8130: obtain {subexpr} argument after {lift}, and rasterize it
! 8131: -------------------------------------------------------------------------- */
! 8132: /* --- parse for {subexpr} arg, and bump expression past it --- */
! 8133: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 8134: /* --- rasterize subexpression to be raised/lowered --- */
! 8135: if ( (raisesp = rasterize(subexpr,size)) /* rasterize subexpression */
! 8136: == NULL ) goto end_of_job; /* and quit if failed */
! 8137: /* -------------------------------------------------------------------------
! 8138: raise/lower baseline and return it to caller
! 8139: -------------------------------------------------------------------------- */
! 8140: /* --- raise/lower baseline --- */
! 8141: raisesp->baseline += lift; /* new baseline (no height checks) */
! 8142: /* --- return raised subexpr to caller --- */
! 8143: end_of_job:
! 8144: return ( raisesp ); /* return raised subexpr to caller */
! 8145: } /* --- end-of-function rastraise() --- */
! 8146:
! 8147:
! 8148: /* ==========================================================================
! 8149: * Function: rastrotate ( expression, size, basesp, arg1, arg2, arg3 )
! 8150: * Purpose: \rotatebox{degrees}{subexpression} handler, returns subraster
! 8151: * containing subexpression rotated by degrees (counterclockwise
! 8152: * if degrees positive)
! 8153: * --------------------------------------------------------------------------
! 8154: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8155: * string immediately following \rotatebox to be
! 8156: * rasterized, and returning ptr immediately
! 8157: * following last character processed.
! 8158: * size (I) int containing 0-5 default font size
! 8159: * basesp (I) subraster * to character (or subexpression)
! 8160: * immediately preceding \rotatebox
! 8161: * (unused, but passed for consistency)
! 8162: * arg1 (I) int unused
! 8163: * arg2 (I) int unused
! 8164: * arg3 (I) int unused
! 8165: * --------------------------------------------------------------------------
! 8166: * Returns: ( subraster * ) ptr to subraster corresponding to \rotatebox
! 8167: * requested, or NULL for any parsing error
! 8168: * --------------------------------------------------------------------------
! 8169: * Notes: o Summary of syntax...
! 8170: * \rotatebox{degrees}{subexpression}
! 8171: * o
! 8172: * ======================================================================= */
! 8173: /* --- entry point --- */
! 8174: subraster *rastrotate ( char **expression, int size, subraster *basesp,
! 8175: int arg1, int arg2, int arg3 )
! 8176: {
! 8177: /* -------------------------------------------------------------------------
! 8178: Allocations and Declarations
! 8179: -------------------------------------------------------------------------- */
! 8180: char *texsubexpr(), subexpr[8192], *degexpr=subexpr; /* args */
! 8181: subraster *rasterize(), *rotsp=NULL; /* subraster for rotated subexpr */
! 8182: raster *rastrot(), *rotrp=NULL; /* rotate subraster->image 90 degs */
! 8183: int delete_raster(); /* delete intermediate rasters */
! 8184: int baseline=0; /* baseline of rasterized image */
! 8185: double strtod(), /* convert ascii params to doubles */
! 8186: degrees=0.0, ipart,fpart; /* degrees to be rotated */
! 8187: int idegrees=0, isneg=0; /* positive ipart, isneg=1 if neg */
! 8188: int n90=0, isn90=1; /* degrees is n90 multiples of 90 */
! 8189: /* -------------------------------------------------------------------------
! 8190: obtain {degrees} argument immediately following \rotatebox command
! 8191: -------------------------------------------------------------------------- */
! 8192: /* --- parse for {degrees} arg, and bump expression past it --- */
! 8193: *expression = texsubexpr(*expression,degexpr,0,"{","}",0,0);
! 8194: if ( *degexpr == '\000' ) goto end_of_job; /* couldn't get {degrees} */
! 8195: degrees = strtod(degexpr,NULL); /* degrees to be rotated */
! 8196: if ( degrees < 0.0 ) /* clockwise rotation desired */
! 8197: { degrees = -degrees; /* flip sign so degrees positive */
! 8198: isneg = 1; } /* and set flag to indicate flip */
! 8199: fpart = modf(degrees,&ipart); /* integer and fractional parts */
! 8200: ipart = (double)(((int)degrees)%360); /* degrees mod 360 */
! 8201: degrees = ipart + fpart; /* restore fractional part */
! 8202: if ( isneg ) /* if clockwise rotation requested */
! 8203: degrees = 360.0 - degrees; /* do equivalent counterclockwise */
! 8204: idegrees = (int)(degrees+0.5); /* integer degrees */
! 8205: n90 = idegrees/90; /* degrees is n90 multiples of 90 */
! 8206: isn90 = (90*n90==idegrees); /*true if degrees is multiple of 90*/
! 8207: isn90 = 1; /* forced true for time being */
! 8208: /* -------------------------------------------------------------------------
! 8209: obtain {subexpr} argument after {degrees}, and rasterize it
! 8210: -------------------------------------------------------------------------- */
! 8211: /* --- parse for {subexpr} arg, and bump expression past it --- */
! 8212: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 8213: /* --- rasterize subexpression to be rotated --- */
! 8214: if ( (rotsp = rasterize(subexpr,size)) /* rasterize subexpression */
! 8215: == NULL ) goto end_of_job; /* and quit if failed */
! 8216: /* --- return unmodified image if no rotation requested --- */
! 8217: if ( abs(idegrees) < 2 ) goto end_of_job; /* don't bother rotating image */
! 8218: /* --- extract params for image to be rotated --- */
! 8219: rotrp = rotsp->image; /* unrotated rasterized image */
! 8220: baseline = rotsp->baseline; /* and baseline of that image */
! 8221: /* -------------------------------------------------------------------------
! 8222: rotate by multiples of 90 degrees
! 8223: -------------------------------------------------------------------------- */
! 8224: if ( isn90 ) /* rotation by multiples of 90 */
! 8225: if ( n90 > 0 ) /* do nothing for 0 degrees */
! 8226: {
! 8227: n90 = 4-n90; /* rasrot() rotates clockwise */
! 8228: while ( n90 > 0 ) /* still have remaining rotations */
! 8229: { raster *nextrp = rastrot(rotrp); /* rotate raster image */
! 8230: if ( nextrp == NULL ) break; /* something's terribly wrong */
! 8231: delete_raster(rotrp); /* free previous raster image */
! 8232: rotrp = nextrp; /* and replace it with rotated one */
! 8233: n90--; } /* decrement remaining count */
! 8234: } /* --- end-of-if(isn90) --- */
! 8235: /* -------------------------------------------------------------------------
! 8236: requested rotation not multiple of 90 degrees
! 8237: -------------------------------------------------------------------------- */
! 8238: if ( !isn90 ) /* explicitly construct rotation */
! 8239: { ; } /* not yet implemented */
! 8240: /* -------------------------------------------------------------------------
! 8241: re-populate subraster envelope with rotated image
! 8242: -------------------------------------------------------------------------- */
! 8243: /* --- re-init various subraster parameters, embedding raster in it --- */
! 8244: if ( rotrp != NULL ) /* rotated raster constructed okay */
! 8245: { rotsp->type = IMAGERASTER; /* signal constructed image */
! 8246: rotsp->image = rotrp; /* raster we just constructed */
! 8247: /* --- now try to guess pleasing baseline --- */
! 8248: if ( idegrees > 2 ) /* leave unchanged if unrotated */
! 8249: if ( strlen(subexpr) < 3 /* we rotated a short expression */
! 8250: || abs(idegrees-180) < 3 ) /* or just turned it upside-down */
! 8251: baseline = rotrp->height - 1; /* so set with nothing descending */
! 8252: else /* rotated a long expression */
! 8253: baseline = (65*(rotrp->height-1))/100; /* roughly center long expr */
! 8254: rotsp->baseline = baseline; } /* set baseline as calculated above*/
! 8255: /* --- return rotated subexpr to caller --- */
! 8256: end_of_job:
! 8257: return ( rotsp ); /*return rotated subexpr to caller*/
! 8258: } /* --- end-of-function rastrotate() --- */
! 8259:
! 8260:
! 8261: /* ==========================================================================
! 8262: * Function: rastfbox ( expression, size, basesp, arg1, arg2, arg3 )
! 8263: * Purpose: \fbox{subexpression} handler, returns subraster
! 8264: * containing subexpression with frame box drawn around it
! 8265: * --------------------------------------------------------------------------
! 8266: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8267: * string immediately following \fbox to be
! 8268: * rasterized, and returning ptr immediately
! 8269: * following last character processed.
! 8270: * size (I) int containing 0-5 default font size
! 8271: * basesp (I) subraster * to character (or subexpression)
! 8272: * immediately preceding \fbox
! 8273: * (unused, but passed for consistency)
! 8274: * arg1 (I) int unused
! 8275: * arg2 (I) int unused
! 8276: * arg3 (I) int unused
! 8277: * --------------------------------------------------------------------------
! 8278: * Returns: ( subraster * ) ptr to subraster corresponding to \fbox
! 8279: * requested, or NULL for any parsing error
! 8280: * --------------------------------------------------------------------------
! 8281: * Notes: o Summary of syntax...
! 8282: * \fbox[width][height]{subexpression}
! 8283: * o
! 8284: * ======================================================================= */
! 8285: /* --- entry point --- */
! 8286: subraster *rastfbox ( char **expression, int size, subraster *basesp,
! 8287: int arg1, int arg2, int arg3 )
! 8288: {
! 8289: /* -------------------------------------------------------------------------
! 8290: Allocations and Declarations
! 8291: -------------------------------------------------------------------------- */
! 8292: char *texsubexpr(), subexpr[8192], widtharg[512]; /* args */
! 8293: subraster *rasterize(), *framesp=NULL; /* rasterize subexpr to be framed */
! 8294: raster *border_raster(), *bp=NULL; /* framed image raster */
! 8295: double strtod(); /* interpret [width][height] */
! 8296: int fwidth=6, fthick=1; /*extra frame width, line thickness*/
! 8297: int width=(-1), height=(-1), /* optional [width][height] args */
! 8298: iscompose = 0; /* set true if optional args given */
! 8299: /* -------------------------------------------------------------------------
! 8300: obtain optional [width][height] arguments immediately following \fbox
! 8301: -------------------------------------------------------------------------- */
! 8302: /* --- first check for optional \fbox[width] --- */
! 8303: if ( *(*expression) == '[' ) /* check for []-enclosed width arg */
! 8304: { *expression = texsubexpr(*expression,widtharg,511,"[","]",0,0);
! 8305: if ( *widtharg != '\000' ) /* got widtharg */
! 8306: { width = max2(1,iround(unitlength*strtod(widtharg,NULL)));
! 8307: height = 1; fwidth = 2; iscompose = 1; }
! 8308: } /* --- end-of-if(**expression=='[') --- */
! 8309: if ( width > 0 ) /* found leading [width], so... */
! 8310: if ( *(*expression) == '[' ) /* check for []-enclosed height arg */
! 8311: { *expression = texsubexpr(*expression,widtharg,511,"[","]",0,0);
! 8312: if ( *widtharg != '\000' ) /* got widtharg */
! 8313: { height = max2(1,iround(unitlength*strtod(widtharg,NULL)));
! 8314: fwidth = 0; } /* no extra border */
! 8315: } /* --- end-of-if(**expression=='[') --- */
! 8316: /* -------------------------------------------------------------------------
! 8317: obtain {subexpr} argument
! 8318: -------------------------------------------------------------------------- */
! 8319: /* --- parse for {subexpr} arg, and bump expression past it --- */
! 8320: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0);
! 8321: /* --- rasterize subexpression to be framed --- */
! 8322: if ( width<0 || height<0 ) /* no explicit dimensions given */
! 8323: { if ( (framesp = rasterize(subexpr,size)) /* rasterize subexpression */
! 8324: == NULL ) goto end_of_job; } /* and quit if failed */
! 8325: else
! 8326: { char composexpr[8192]; /* compose subexpr with empty box */
! 8327: sprintf(composexpr,"\\compose{\\hspace{%d}\\vspace{%d}}{%s}",
! 8328: width,height,subexpr);
! 8329: if ( (framesp = rasterize(composexpr,size)) /* rasterize subexpression */
! 8330: == NULL ) goto end_of_job; } /* and quit if failed */
! 8331: /* -------------------------------------------------------------------------
! 8332: draw frame, reset params, and return it to caller
! 8333: -------------------------------------------------------------------------- */
! 8334: /* --- draw border --- */
! 8335: if ( (bp = border_raster(framesp->image,-fwidth,-fwidth,fthick,1))
! 8336: == NULL ) goto end_of_job; /* draw border and quit if failed */
! 8337: /* --- replace original image and raise baseline to accommodate frame --- */
! 8338: framesp->image = bp; /* replace image with framed one */
! 8339: if ( !iscompose ) /* simple border around subexpr */
! 8340: framesp->baseline += fwidth; /* so just raise baseline */
! 8341: else
! 8342: framesp->baseline = (framesp->image)->height - 1; /* set at bottom */
! 8343: /* --- return framed subexpr to caller --- */
! 8344: end_of_job:
! 8345: return ( framesp ); /* return framed subexpr to caller */
! 8346: } /* --- end-of-function rastfbox() --- */
! 8347:
! 8348:
! 8349: /* ==========================================================================
! 8350: * Function: rastinput ( expression, size, basesp, arg1, arg2, arg3 )
! 8351: * Purpose: \input{filename} handler, reads filename and returns
! 8352: * subraster containing image of expression read from filename
! 8353: * --------------------------------------------------------------------------
! 8354: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8355: * string immediately following \input to be
! 8356: * rasterized, and returning ptr immediately
! 8357: * following last character processed.
! 8358: * size (I) int containing 0-5 default font size
! 8359: * basesp (I) subraster * to character (or subexpression)
! 8360: * immediately preceding \input
! 8361: * (unused, but passed for consistency)
! 8362: * arg1 (I) int unused
! 8363: * arg2 (I) int unused
! 8364: * arg3 (I) int unused
! 8365: * --------------------------------------------------------------------------
! 8366: * Returns: ( subraster * ) ptr to subraster corresponding to expression
! 8367: * in filename, or NULL for any parsing error
! 8368: * --------------------------------------------------------------------------
! 8369: * Notes: o Summary of syntax...
! 8370: * \input{filename}
! 8371: * o
! 8372: * ======================================================================= */
! 8373: /* --- entry point --- */
! 8374: subraster *rastinput ( char **expression, int size, subraster *basesp,
! 8375: int arg1, int arg2, int arg3 )
! 8376: {
! 8377: /* -------------------------------------------------------------------------
! 8378: Allocations and Declarations
! 8379: -------------------------------------------------------------------------- */
! 8380: char *texsubexpr(), tag[512]="\000", filename[1024]="\000"; /* args */
! 8381: subraster *rasterize(), *inputsp=NULL; /* rasterized input image */
! 8382: int status, rastreadfile(); /* read input file */
! 8383: int format=0, npts=0; /* don't reformat (numerical) input */
! 8384: char subexpr[8192], /* concatanated lines from input file */
! 8385: *mimeprep(), /* preprocess inputted data */
! 8386: *dtoa(), *reformat=NULL; /* reformat numerical input */
! 8387: /* -------------------------------------------------------------------------
! 8388: obtain [tag]{filename} argument
! 8389: -------------------------------------------------------------------------- */
! 8390: /* --- parse for optional [tag] or [fmt] arg, bump expression past it --- */
! 8391: if ( *(*expression) == '[' ) /* check for []-enclosed value */
! 8392: { char argfld[2048]; /* optional argument field */
! 8393: *expression = texsubexpr(*expression,argfld,2047,"[","]",0,0);
! 8394: if ( (reformat=strstr(argfld,"dtoa")) != NULL ) /* dtoa requested */
! 8395: { format = 1; /* signal dtoa() format */
! 8396: if ( (reformat=strchr(reformat,'=')) != NULL ) /* have dtoa= */
! 8397: npts = (int)strtol(reformat+1,NULL,0); } /* so set npts */
! 8398: if ( format == 0 ) /* reformat not requested */
! 8399: strcpy(tag,argfld); } /* so interpret arg as tag */
! 8400: /* --- parse for {filename} arg, and bump expression past it --- */
! 8401: *expression = texsubexpr(*expression,filename,1023,"{","}",0,0);
! 8402: /* --- check for alternate filename:tag --- */
! 8403: if ( *filename != '\000' /* got filename */
! 8404: /*&& *tag == '\000'*/ ) /* but no [tag] */
! 8405: { char *delim = strchr(filename,':'); /* look for : in filename:tag */
! 8406: if ( delim != (char *)NULL ) /* found it */
! 8407: { *delim = '\000'; /* null-terminate filename at : */
! 8408: strcpy(tag,delim+1); } } /* and stuff after : is tag */
! 8409: /* --------------------------------------------------------------------------
! 8410: Read file and rasterize constructed subexpression
! 8411: -------------------------------------------------------------------------- */
! 8412: status = rastreadfile(filename,tag,subexpr); /* read file */
! 8413: if ( *subexpr == '\000' ) goto end_of_job; /* quit if problem */
! 8414: /* --- rasterize input subexpression --- */
! 8415: mimeprep(subexpr); /* preprocess subexpression */
! 8416: if ( format == 1 ) /* dtoa() */
! 8417: { double d = strtod(subexpr,NULL); /* interpret subexpr as double */
! 8418: if ( d != 0.0 ) /* conversion to double successful */
! 8419: if ( (reformat=dtoa(d,npts)) != NULL ) /* reformat successful */
! 8420: strcpy(subexpr,reformat); } /*replace subexpr with reformatted*/
! 8421: inputsp = rasterize(subexpr,size); /* rasterize subexpression */
! 8422: /* --- return input image to caller --- */
! 8423: end_of_job:
! 8424: return ( inputsp ); /* return input image to caller */
! 8425: } /* --- end-of-function rastinput() --- */
! 8426:
! 8427:
! 8428: /* ==========================================================================
! 8429: * Function: rastcounter ( expression, size, basesp, arg1, arg2, arg3 )
! 8430: * Purpose: \counter[value]{filename} handler, returns subraster
! 8431: * containing image of counter value read from filename
! 8432: * (or optional [value]), and increments counter
! 8433: * --------------------------------------------------------------------------
! 8434: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8435: * string immediately following \counter to be
! 8436: * rasterized, and returning ptr immediately
! 8437: * following last character processed.
! 8438: * size (I) int containing 0-5 default font size
! 8439: * basesp (I) subraster * to character (or subexpression)
! 8440: * immediately preceding \counter
! 8441: * (unused, but passed for consistency)
! 8442: * arg1 (I) int unused
! 8443: * arg2 (I) int unused
! 8444: * arg3 (I) int unused
! 8445: * --------------------------------------------------------------------------
! 8446: * Returns: ( subraster * ) ptr to subraster corresponding to \counter
! 8447: * requested, or NULL for any parsing error
! 8448: * --------------------------------------------------------------------------
! 8449: * Notes: o Summary of syntax...
! 8450: * \counter[value][logfile]{filename}
! 8451: * o
! 8452: * ======================================================================= */
! 8453: /* --- entry point --- */
! 8454: subraster *rastcounter ( char **expression, int size, subraster *basesp,
! 8455: int arg1, int arg2, int arg3 )
! 8456: {
! 8457: /* -------------------------------------------------------------------------
! 8458: Allocations and Declarations
! 8459: -------------------------------------------------------------------------- */
! 8460: char *texsubexpr(), filename[1024]="\000", /* counter file */
! 8461: logfile[1024]="\000", tag[512]="\000"; /* log file and tag */
! 8462: subraster *rasterize(), *countersp=NULL; /* rasterized counter image */
! 8463: FILE /* *fp=NULL,*/ *logfp=NULL; /* counter and log file pointers */
! 8464: int rastreadfile(), rastwritefile(); /* to read and write counter file */
! 8465: char text[2048] = "1_", /* first (and only) line in counter file */
! 8466: *delim = NULL, /* delimiter in text */
! 8467: utext[32] = "1_", /* default delimiter */
! 8468: *udelim = utext+1; /* underscore delimiter */
! 8469: char *timestamp(), /* timestamp for logging */
! 8470: *dtoa(); /* double to comma-separated */
! 8471: int counter = 1, /* atoi(text) (after _ removed, if present) */
! 8472: gotcount = 0, /* set true once counter value determined */
! 8473: ordindex = (-1); /* ordinal[] index to append ordinal suffix */
! 8474: /*--- ordinal suffixes based on units digit of counter ---*/
! 8475: static char *ordinal[]={"th","st","nd","rd","th","th","th","th","th","th"};
! 8476: static char *logvars[]={"REMOTE_ADDR","HTTP_REFERER",NULL}; /* log vars*/
! 8477: static int commentvar = 1; /* logvars[commentvar] replaced by comment */
! 8478: /* -------------------------------------------------------------------------
! 8479: first obtain optional [value][logfile] args immediately following \counter
! 8480: -------------------------------------------------------------------------- */
! 8481: /* --- first check for optional \counter[value] --- */
! 8482: if ( *(*expression) == '[' ) /* check for []-enclosed value */
! 8483: { *expression = texsubexpr(*expression,text,2047,"[","]",0,0);
! 8484: if ( *text != '\000' ) /* got counter value */
! 8485: if ( strlen(text) >= 1 ) /* and it's not an empty string */
! 8486: if ( isdigit((int)(*text)) ) /* leading 0-9 digit signals value */
! 8487: { counter = (int)(strtod(text,&udelim)+0.1); /* value and delim */
! 8488: gotcount = 1; } /* signal we got counter value */
! 8489: else /* not a digit, so must be logfile */
! 8490: strcpy(logfile,text); /* so just copy it */
! 8491: } /* --- end-of-if(**expression=='[') --- */
! 8492: /* --- next check for optional \counter[][logfile] --- */
! 8493: if ( *(*expression) == '[' ) /* check for []-enclosed logfile */
! 8494: { *expression = texsubexpr(*expression,filename,1023,"[","]",0,0);
! 8495: if ( *text != '\000' ) /* got logfile value */
! 8496: if ( strlen(filename) >= 1 ) /* and it's not an empty string */
! 8497: if ( !(isdigit((int)(*filename))) /*leading non-digit signals logfile*/
! 8498: || gotcount ) /* or we already got counter value */
! 8499: strcpy(logfile,filename); /* so just copy it */
! 8500: else /* 0-9 digit, so must be value */
! 8501: { strcpy(text,filename); /* copy value to text line */
! 8502: counter = (int)(strtod(text,&udelim)+0.1); /* value and delim */
! 8503: gotcount = 1; } /* signal we got counter value */
! 8504: } /* --- end-of-if(**expression=='[') --- */
! 8505: /* -------------------------------------------------------------------------
! 8506: obtain counter {filename} argument
! 8507: -------------------------------------------------------------------------- */
! 8508: /* --- parse for {filename} arg, and bump expression past it --- */
! 8509: *expression = texsubexpr(*expression,filename,1023,"{","}",0,0);
! 8510: /* --- check for counter filename:tag --- */
! 8511: if ( *filename != '\000' ) /* got filename */
! 8512: if ( (delim=strchr(filename,':')) /* look for : in filename:tag */
! 8513: != (char *)NULL ) /* found it */
! 8514: { *delim = '\000'; /* null-terminate filename at : */
! 8515: strcpy(tag,delim+1); } /* and stuff after : is tag */
! 8516: /* --------------------------------------------------------------------------
! 8517: Read and parse file, increment and rewrite counter (with optional underscore)
! 8518: -------------------------------------------------------------------------- */
! 8519: if ( strlen(filename) > 1 ) /* make sure we got {filename} arg */
! 8520: {
! 8521: /* --- read and interpret first (and only) line from counter file --- */
! 8522: if ( !gotcount ) /* if no [count] argument supplied */
! 8523: if ( rastreadfile(filename,tag,text) != 0 ) /* try reading it from file */
! 8524: { counter= 1 + (int)(strtod(text,&udelim)+0.1); /*counter val and delim*/
! 8525: gotcount = 1; } /* signal we got counter value */
! 8526: /* --- check for ordinal suffix --- */
! 8527: if ( udelim != (char *)NULL ) /* have some delim after value */
! 8528: if ( *udelim == '_' ) /* underscore signals ordinal */
! 8529: { ordindex = counter%10; /* least significant digit */
! 8530: if ( counter >= 10 ) /* counter is 10 or greater */
! 8531: if ( (counter/10)%10 == 1 ) /* and the last two are 10-19 */
! 8532: ordindex = 0; } /* use th for 11,12,13 rather than st,nd,rd */
! 8533: /* --- rewrite counter file --- */
! 8534: sprintf(text,"%d",counter); /*build image of incremented counter*/
! 8535: if ( ordindex >= 0 ) strcat(text,"_"); /* tack on _ */
! 8536: if ( *tag == '\000' ) strcat(text,"\n"); /* and newline */
! 8537: rastwritefile(filename,tag,text,1); /* rewrite incremented counter */
! 8538: } /* --- end-of-if(strlen(filename)>1) --- */
! 8539: /* --------------------------------------------------------------------------
! 8540: log counter request
! 8541: -------------------------------------------------------------------------- */
! 8542: if ( strlen(logfile) > 1 ) /* optional [logfile] given */
! 8543: {
! 8544: char comment[1024] = "\000", /* embedded comment, logfile:comment*/
! 8545: *commptr = strchr(logfile,':'); /* check for : signalling comment */
! 8546: if ( commptr != NULL ) /* have embedded comment */
! 8547: { strcpy(comment,commptr+1); /* comment follows : */
! 8548: *commptr = '\000'; } /* null-terminate actual logfile */
! 8549: if ( (logfp = fopen(logfile,"a")) /* open logfile */
! 8550: != (FILE *)NULL ) /* opened successfully */
! 8551: {
! 8552: int ilog=0; /* logvars[] index */
! 8553: fprintf(logfp,"%s ",timestamp()); /* first emit timestamp */
! 8554: if (*tag=='\000') fprintf(logfp,"%s",filename); /* emit counter filename */
! 8555: else fprintf(logfp,"<%s>",tag); /* or tag if we have one */
! 8556: fprintf(logfp,"=%d",counter); /* emit counter value */
! 8557: for ( ilog=0; logvars[ilog] != NULL; ilog++ ) /* log till end-of-table */
! 8558: if ( ilog == commentvar /* replace with comment... */
! 8559: && commptr != NULL ) /* ...if available */
! 8560: fprintf(logfp," %.256s",comment); /* log embedded comment */
! 8561: else
! 8562: { char *logval = getenv(logvars[ilog]); /* getenv(variable) to be logged*/
! 8563: fprintf(logfp," %.64s", /* log variable */
! 8564: (logval!=NULL?logval:"<unknown>")); } /* emit value or <unknown> */
! 8565: fprintf(logfp,"\n"); /* terminating newline */
! 8566: fclose(logfp); /* close logfile */
! 8567: } /* --- end-of-if(logfp!=NULL) --- */
! 8568: } /* --- end-of-if(strlen(logfile)>1) --- */
! 8569: /* --------------------------------------------------------------------------
! 8570: construct counter expression and rasterize it
! 8571: -------------------------------------------------------------------------- */
! 8572: /* --- construct expression --- */
! 8573: /*sprintf(text,"%d",counter);*/ /* start with counter */
! 8574: strcpy(text,dtoa(((double)counter),0)); /* comma-separated counter value */
! 8575: if ( ordindex >= 0 ) /* need to tack on ordinal suffix */
! 8576: { strcat(text,"^{\\underline{\\rm~"); /* start with ^ and {\underline{\rm */
! 8577: strcat(text,ordinal[ordindex]); /* then st,nd,rd, or th */
! 8578: strcat(text,"}}"); } /* finish with }} */
! 8579: /* --- rasterize it --- */
! 8580: countersp = rasterize(text,size); /* rasterize counter subexpression */
! 8581: /* --- return counter image to caller --- */
! 8582: /*end_of_job:*/
! 8583: return ( countersp ); /* return counter image to caller */
! 8584: } /* --- end-of-function rastcounter() --- */
! 8585:
! 8586:
! 8587: /* ==========================================================================
! 8588: * Function: rastnoop ( expression, size, basesp, nargs, arg2, arg3 )
! 8589: * Purpose: no op -- flush \escape without error
! 8590: * --------------------------------------------------------------------------
! 8591: * Arguments: expression (I/O) char ** to first char of null-terminated
! 8592: * string immediately following \escape to be
! 8593: * flushed, and returning ptr immediately
! 8594: * following last character processed.
! 8595: * size (I) int containing 0-5 default font size
! 8596: * basesp (I) subraster * to character (or subexpression)
! 8597: * immediately preceding \fbox
! 8598: * (unused, but passed for consistency)
! 8599: * nargs (I) int containing number of {}-args after
! 8600: * \escape to be flushed along with it
! 8601: * arg2 (I) int unused
! 8602: * arg3 (I) int unused
! 8603: * --------------------------------------------------------------------------
! 8604: * Returns: ( subraster * ) NULL subraster ptr
! 8605: * --------------------------------------------------------------------------
! 8606: * Notes: o
! 8607: * ======================================================================= */
! 8608: /* --- entry point --- */
! 8609: subraster *rastnoop ( char **expression, int size, subraster *basesp,
! 8610: int nargs, int arg2, int arg3 )
! 8611: {
! 8612: /* -------------------------------------------------------------------------
! 8613: Allocations and Declarations
! 8614: -------------------------------------------------------------------------- */
! 8615: char *texsubexpr(), subexpr[8192]; /* flush dummy args eaten by \escape*/
! 8616: subraster *rasterize(), *noopsp=NULL; /* rasterize subexpr */
! 8617: /* --- flush accompanying args if necessary --- */
! 8618: if ( nargs != NOVALUE /* not unspecified */
! 8619: && nargs > 0 ) /* and args to be flushed */
! 8620: while ( --nargs >= 0 ) /* count down */
! 8621: *expression = texsubexpr(*expression,subexpr,0,"{","}",0,0); /*flush arg*/
! 8622: /* --- return null ptr to caller --- */
! 8623: /*end_of_job:*/
! 8624: return ( noopsp ); /* return NULL ptr to caller */
! 8625: } /* --- end-of-function rastnoop() --- */
! 8626:
! 8627:
! 8628: /* ==========================================================================
! 8629: * Function: rastopenfile ( filename, mode )
! 8630: * Purpose: Opens filename[.tex] in mode, returning FILE *
! 8631: * --------------------------------------------------------------------------
! 8632: * Arguments: filename (I/O) char * to null-terminated string containing
! 8633: * name of file to open (preceded by path
! 8634: * relative to mimetex executable)
! 8635: * If fopen() fails, .tex appeneded,
! 8636: * and returned if that fopen() succeeds
! 8637: * mode (I) char * to null-terminated string containing
! 8638: * fopen() mode
! 8639: * --------------------------------------------------------------------------
! 8640: * Returns: ( FILE * ) pointer to opened file, or NULL if error
! 8641: * --------------------------------------------------------------------------
! 8642: * Notes: o
! 8643: * ======================================================================= */
! 8644: /* --- entry point --- */
! 8645: FILE *rastopenfile ( char *filename, char *mode )
! 8646: {
! 8647: /* -------------------------------------------------------------------------
! 8648: Allocations and Declarations
! 8649: -------------------------------------------------------------------------- */
! 8650: FILE *fp = (FILE *)NULL /*,*fopen()*/; /*file pointer to opened filename*/
! 8651: char texfile[2048] = "\000", /* local copy of input filename */
! 8652: amode[128] = "r"; /* test open mode if arg mode=NULL */
! 8653: int ismode = 0, /* true of mode!=NULL */
! 8654: isprefix = (*pathprefix=='\000'?0:1); /* true if paths have prefix */
! 8655: /* --------------------------------------------------------------------------
! 8656: Check mode and open file
! 8657: -------------------------------------------------------------------------- */
! 8658: /* --- check filename --- */
! 8659: if ( filename != (char *)NULL ) /* caller passed filename arg */
! 8660: if ( strlen(filename) >= 1 ) /* make sure we got actual filename*/
! 8661: { char *pfilename = filename; /* ptr to 1st char of filename */
! 8662: *texfile = '\000'; /* init filename as null string */
! 8663: while ( isthischar(*pfilename," /\\") ) /* absolute paths invalid */
! 8664: pfilename++; /* so flush leading / or \ (or ' ')*/
! 8665: if ( isprefix && *pfilename!='\000' ) /* paths preceded by prefix */
! 8666: { strcat(texfile,pathprefix); /* init filename with path */
! 8667: while ( memcmp(pfilename,"../",3)==0 /* have leading ../ */
! 8668: || memcmp(pfilename,"..\\",3)==0 ) /* or ..\ with prefix */
! 8669: pfilename += 3; } /* flush leading ../ or ..\ */
! 8670: strcat(texfile,pfilename); /* local copy of given filename */
! 8671: compress(texfile,' '); } /* remove embedded blanks */
! 8672: /* --- check mode --- */
! 8673: if ( mode != (char *)NULL ) /* caller passed mode arg */
! 8674: if ( *mode != '\000' ) /* and it's not an empty string */
! 8675: { ismode = 1; /* so flip mode flag true */
! 8676: strcpy(amode,mode); /* and replace "r" with caller's */
! 8677: compress(amode,' '); } /* remove embedded blanks */
! 8678: /* --- open filename or filename.tex --- */
! 8679: if ( strlen(texfile) > 1 ) /* make sure we got actual filename*/
! 8680: if ( (fp = fopen(texfile,amode)) /* try opening given filename */
! 8681: == NULL ) /* failed to open given filename */
! 8682: { strcpy(filename,texfile); /* signal possible filename error */
! 8683: strcat(texfile,".tex"); /* but first try adding .tex */
! 8684: if ( (fp = fopen(texfile,amode)) /* now try opening filename.tex */
! 8685: != NULL ) /* filename.tex succeeded */
! 8686: strcpy(filename,texfile); } /* replace caller's filename */
! 8687: /* --- close file if only opened to check name --- */
! 8688: if ( !ismode && fp!=NULL ) /* no mode, so just checking */
! 8689: fclose(fp); /* close file, fp signals success */
! 8690: /* --- return fp or NULL to caller --- */
! 8691: /*end_of_job:*/
! 8692: if ( msglevel>=9 && msgfp!=NULL ) /* debuging */
! 8693: { fprintf(msgfp,"rastopenfile> returning fopen(%s,%s) = %s\n",
! 8694: filename,amode,(fp==NULL?"NULL":"Okay")); fflush(msgfp); }
! 8695: return ( fp ); /* return fp or NULL to caller */
! 8696: } /* --- end-of-function rastopenfile() --- */
! 8697:
! 8698:
! 8699: /* ==========================================================================
! 8700: * Function: rastreadfile ( filename, tag, value )
! 8701: * Purpose: Read filename, returning value as string
! 8702: * between <tag>...</tag> or entire file if tag=NULL passed.
! 8703: * --------------------------------------------------------------------------
! 8704: * Arguments: filename (I) char * to null-terminated string containing
! 8705: * name of file to read (preceded by path
! 8706: * relative to mimetex executable)
! 8707: * tag (I) char * to null-terminated string containing
! 8708: * html-like tagname. File contents between
! 8709: * <tag> and </tag> will be returned, or
! 8710: * entire file if tag=NULL passed.
! 8711: * value (O) char * returning value between <tag>...</tag>
! 8712: * or entire file if tag=NULL.
! 8713: * --------------------------------------------------------------------------
! 8714: * Returns: ( int ) 1=okay, 0=some error
! 8715: * --------------------------------------------------------------------------
! 8716: * Notes: o
! 8717: * ======================================================================= */
! 8718: /* --- entry point --- */
! 8719: int rastreadfile ( char *filename, char *tag, char *value )
! 8720: {
! 8721: /* -------------------------------------------------------------------------
! 8722: Allocations and Declarations
! 8723: -------------------------------------------------------------------------- */
! 8724: FILE *fp = (FILE *)NULL, *rastopenfile(); /* pointer to opened filename */
! 8725: char texfile[2048] = "\000", /* local copy of input filename */
! 8726: text[4096]; /* line from input file */
! 8727: char *tagp, tag1[512], tag2[512]; /* left <tag> and right <tag/> */
! 8728: int vallen=0, maxvallen=8000; /* #chars in value, max allowed */
! 8729: int status = 0; /* status returned, 1=okay */
! 8730: int tagnum = 0; /* tag we're looking for */
! 8731: /* --------------------------------------------------------------------------
! 8732: Open file
! 8733: -------------------------------------------------------------------------- */
! 8734: /* --- first check output arg --- */
! 8735: if ( value == (char *)NULL ) goto end_of_job; /* no output buffer supplied */
! 8736: *value = '\000'; /* init buffer with empty string */
! 8737: /* --- open filename or filename.tex --- */
! 8738: if ( filename != (char *)NULL ) /* make sure we got filename arg */
! 8739: { strcpy(texfile,filename); /* local copy of filename */
! 8740: fp = rastopenfile(texfile,"r"); } /* try opening it */
! 8741: /* --- check that file opened --- */
! 8742: if ( fp == (FILE *)NULL ) /* failed to open file */
! 8743: { sprintf(value,"{\\normalsize\\rm[file %s?]}",texfile);
! 8744: goto end_of_job; } /* return error message to caller */
! 8745: /* --------------------------------------------------------------------------
! 8746: construct <tag>'s
! 8747: -------------------------------------------------------------------------- */
! 8748: if ( tag != (char *)NULL ) /* caller passed tag arg */
! 8749: if ( *tag != '\000' ) /* and it's not an empty string */
! 8750: { strcpy(tag1,"<"); strcpy(tag2,"</"); /* begin with < and </ */
! 8751: strcat(tag1,tag); strcat(tag2,tag); /* followed by caller's tag */
! 8752: strcat(tag1,">"); strcat(tag2,">"); /* ending both tags with > */
! 8753: compress(tag1,' '); compress(tag2,' '); /* remove embedded blanks */
! 8754: tagnum = 1; } /* signal that we have tag */
! 8755: /* --------------------------------------------------------------------------
! 8756: Read file, concatnate lines
! 8757: -------------------------------------------------------------------------- */
! 8758: while ( fgets(text,4090,fp) != (char *)NULL ) { /* read input till eof */
! 8759: switch ( tagnum ) { /* look for left- or right-tag */
! 8760: case 0: break; /* no tag to look for */
! 8761: case 1: /* looking for opening left <tag> */
! 8762: if ( (tagp=strstr(text,tag1)) == NULL ) break; /*haven't found it yet*/
! 8763: strcpy(text,tagp+strlen(tag1)); /* shift out preceding text */
! 8764: tagnum = 2; /*now looking for closing right tag*/
! 8765: case 2: /* looking for closing right </tag> */
! 8766: if ( (tagp=strstr(text,tag2)) == NULL ) break; /*haven't found it yet*/
! 8767: *tagp = '\000'; /* terminate line at tag */
! 8768: tagnum = 3; /* done after this line */
! 8769: break;
! 8770: } /* ---end-of-switch(tagnum) --- */
! 8771: if ( tagnum != 1 ) { /* no tag or left tag already found*/
! 8772: int textlen = strlen(text); /* #chars in current line */
! 8773: if ( vallen+textlen > maxvallen ) break; /* quit before overflow */
! 8774: strcat(value,text); /* concat line to end of value */
! 8775: vallen += textlen; /* bump length */
! 8776: if ( tagnum > 2 ) break; } /* found right tag, so we're done */
! 8777: } /* --- end-of-while(fgets()!=NULL) --- */
! 8778: if ( tagnum<1 || tagnum>2 ) status=1; /* okay if no tag or we found tag */
! 8779: fclose ( fp ); /* close input file after reading */
! 8780: /* --- return value and status to caller --- */
! 8781: end_of_job:
! 8782: return ( status ); /* return status to caller */
! 8783: } /* --- end-of-function rastreadfile() --- */
! 8784:
! 8785:
! 8786: /* ==========================================================================
! 8787: * Function: rastwritefile ( filename, tag, value, isstrict )
! 8788: * Purpose: Re/writes filename, replacing string between <tag>...</tag>
! 8789: * with value, or writing entire file as value if tag=NULL.
! 8790: * --------------------------------------------------------------------------
! 8791: * Arguments: filename (I) char * to null-terminated string containing
! 8792: * name of file to write (preceded by path
! 8793: * relative to mimetex executable)
! 8794: * tag (I) char * to null-terminated string containing
! 8795: * html-like tagname. File contents between
! 8796: * <tag> and </tag> will be replaced, or
! 8797: * entire file written if tag=NULL passed.
! 8798: * value (I) char * containing string replacing value
! 8799: * between <tag>...</tag> or replacing entire
! 8800: * file if tag=NULL.
! 8801: * isstrict (I) int containing 1 to only rewrite existing
! 8802: * files, or 0 to create new file if necessary.
! 8803: * --------------------------------------------------------------------------
! 8804: * Returns: ( int ) 1=okay, 0=some error
! 8805: * --------------------------------------------------------------------------
! 8806: * Notes: o
! 8807: * ======================================================================= */
! 8808: /* --- entry point --- */
! 8809: int rastwritefile( char *filename, char *tag, char *value, int isstrict )
! 8810: {
! 8811: /* -------------------------------------------------------------------------
! 8812: Allocations and Declarations
! 8813: -------------------------------------------------------------------------- */
! 8814: FILE *fp = (FILE *)NULL, *rastopenfile(); /* pointer to opened filename */
! 8815: char texfile[2048] = "\000", /* local copy of input filename */
! 8816: filebuff[16384] = "\000", /* entire contents of file */
! 8817: tag1[512], tag2[512], /* left <tag> and right <tag/> */
! 8818: *strchange(), /* put value between <tag>...</tag>*/
! 8819: *timestamp(); /* log modification time */
! 8820: int istag=0, rastreadfile(), /* read file if tag!=NULL */
! 8821: /*isstrict = (seclevel>5? 1:0),*/ /*true only writes existing files*/
! 8822: isnewfile = 0, /* true if writing new file */
! 8823: status = 0; /* status returned, 1=okay */
! 8824: /* --------------------------------------------------------------------------
! 8825: check args
! 8826: -------------------------------------------------------------------------- */
! 8827: /* --- check filename and value --- */
! 8828: if ( filename == (char *)NULL /* quit if no filename arg supplied*/
! 8829: || value == (char *)NULL ) goto end_of_job; /* or no value arg supplied */
! 8830: if ( strlen(filename) < 2 /* quit if unreasonable filename */
! 8831: || *value == '\000' ) goto end_of_job; /* or empty value string supplied */
! 8832: /* --- establish filename[.tex] --- */
! 8833: strcpy(texfile,filename); /* local copy of input filename */
! 8834: if ( rastopenfile(texfile,NULL) /* unchanged or .tex appended */
! 8835: == (FILE *)NULL ) /* can't open, so write new file */
! 8836: { if ( isstrict ) goto end_of_job; /* fail if new files not permitted */
! 8837: isnewfile = 1; } /* signal we're writing new file */
! 8838: /* --- check whether tag supplied by caller --- */
! 8839: if ( tag != (char *)NULL ) /* caller passed tag argument */
! 8840: if ( *tag != '\000' ) /* and it's not an empty string */
! 8841: { istag = 1; /* so flip tag flag true */
! 8842: strcpy(tag1,"<"); strcpy(tag2,"</"); /* begin tags with < and </ */
! 8843: strcat(tag1,tag); strcat(tag2,tag); /* followed by caller's tag */
! 8844: strcat(tag1,">"); strcat(tag2,">"); /* ending both tags with > */
! 8845: compress(tag1,' '); compress(tag2,' '); } /* remove embedded blanks */
! 8846: /* --------------------------------------------------------------------------
! 8847: read existing file if just rewriting a single tag
! 8848: -------------------------------------------------------------------------- */
! 8849: /* --- read original file if only replacing a tag within it --- */
! 8850: *filebuff = '\000'; /* init as empty file */
! 8851: if ( !isnewfile ) /* if file already exists */
! 8852: if ( istag ) /* and just rewriting one tag */
! 8853: if ( rastreadfile(texfile,NULL,filebuff) /* read entire existing file */
! 8854: == 0 ) goto end_of_job; /* signal error if failed to read */
! 8855: /* --------------------------------------------------------------------------
! 8856: construct new file data if needed (entire file replaced by value if no tag)
! 8857: -------------------------------------------------------------------------- */
! 8858: if ( istag ) /* only replacing tag in file */
! 8859: {
! 8860: /* --- find <tag> and </tag> in file --- */
! 8861: int tlen1=strlen(tag1), tlen2=strlen(tag2), flen; /*tag,buff lengths*/
! 8862: char *tagp1 = (isnewfile? NULL:strstr(filebuff,tag1)), /* <tag> in file*/
! 8863: *tagp2 = (isnewfile? NULL:strstr(filebuff,tag2)); /*</tag> in file*/
! 8864: /* --- if adding new <tag> just concatanate at end of file --- */
! 8865: if ( tagp1 == (char *)NULL ) /* add new tag to file */
! 8866: {
! 8867: /* --- preprocess filebuff --- */
! 8868: if ( tagp2 != (char *)NULL ) /* apparently have ...</tag> */
! 8869: strcpy(filebuff,tagp2+tlen2); /* so get rid of leading ...</tag> */
! 8870: if ( (flen = strlen(filebuff)) /* #chars currently in buffer */
! 8871: > 0 ) /* we have non-empty buffer */
! 8872: if (!isthischar(*(filebuff+flen-1),"\n\r")) /*no newline at end of file*/
! 8873: if(0)strcat(filebuff,"\n"); /* so add one before new tag */
! 8874: /* --- add new tag --- */
! 8875: strcat(filebuff,tag1); /* add opening <tag> */
! 8876: strcat(filebuff,value); /* then value */
! 8877: strcat(filebuff,tag2); /* finally closing </tag> */
! 8878: strcat(filebuff,"\n"); /* newline at end of file */
! 8879: } /* --- end-of-if(tagp1==NULL) --- */
! 8880: else /* found existing opening <tag> */
! 8881: {
! 8882: if ( tagp2 == NULL ) /* apparently have <tag>... */
! 8883: { *(tagp1+tlen1) = '\000'; /* so get rid of trailing ... */
! 8884: strcat(filebuff,value); /* then concatanate value */
! 8885: strcat(filebuff,tag2); } /* and finally closing </tag> */
! 8886: else /* else have <tag>...<tag/> */
! 8887: if ( (flen=((int)(tagp2-tagp1))-tlen1) /* len of .'s in <tag>...</tag> */
! 8888: >= 0 ) /* usually <tag> precedes </tag> */
! 8889: strchange(flen,tagp1+tlen1,value); /* change ...'s to value */
! 8890: else /* weirdly, </tag> precedes <tag> */
! 8891: { char fbuff[2048]; /* field buff for <tag>value</tag> */
! 8892: if ( (flen = ((int)(tagp1-tagp2))+tlen1) /* strlen(</tag>...<tag>) */
! 8893: <= 0 ) goto end_of_job; /* must be internal error */
! 8894: strcpy(fbuff,tag1); /* set opening <tag> */
! 8895: strcat(fbuff,value); /* then value */
! 8896: strcat(fbuff,tag2); /* finally closing </tag> */
! 8897: strchange(flen,tagp2,fbuff); } /* replace original </tag>...<tag> */
! 8898: } /* --- end-of-if/else(tagp1==NULL) --- */
! 8899: } /* --- end-of-if(istag) --- */
! 8900: /* --------------------------------------------------------------------------
! 8901: rewrite file and return to caller
! 8902: -------------------------------------------------------------------------- */
! 8903: /* --- first open file for write --- */
! 8904: if ( (fp=rastopenfile(texfile,"w")) /* open for write */
! 8905: == (FILE *)NULL ) goto end_of_job; /* signal error if can't open */
! 8906: /* --- rewrite and close file --- */
! 8907: if ( fputs((istag?filebuff:value),fp) /* write filebuff or value */
! 8908: != EOF ) status = 1; /* signal success if succeeded */
! 8909: fclose ( fp ); /* close output file after writing */
! 8910: /* --- modify timestamp --- */
! 8911: if ( istag ) /* log mod time in tagged file */
! 8912: if ( strstr(tag,"timestamp") == (char *)NULL ) /* but avoid recursion */
! 8913: { char fbuff[2048]; /* field buff <timestamp> value */
! 8914: strcpy(fbuff,tag); /* tag modified */
! 8915: strcat(fbuff," modified at "); /* spacer */
! 8916: strcat(fbuff,timestamp()); /* start with timestamp */
! 8917: rastwritefile(filename,"timestamp",fbuff,1); }
! 8918: /* --- return status to caller --- */
! 8919: end_of_job:
! 8920: return ( status ); /* return status to caller */
! 8921: } /* --- end-of-function rastwritefile() --- */
! 8922:
! 8923:
! 8924: /* ==========================================================================
! 8925: * Function: timestamp ( )
! 8926: * Purpose: returns null-terminated character string containing
! 8927: * current date:time stamp as ccyy-mm-dd:hh:mm:ss{am,pm}
! 8928: * --------------------------------------------------------------------------
! 8929: * Arguments: ( none )
! 8930: * --------------------------------------------------------------------------
! 8931: * Returns: ( char * ) ptr to null-terminated buffer
! 8932: * containing current date:time stamp
! 8933: * --------------------------------------------------------------------------
! 8934: * Notes: o
! 8935: * ======================================================================= */
! 8936: /* --- entry point --- */
! 8937: char *timestamp( )
! 8938: {
! 8939: /* -------------------------------------------------------------------------
! 8940: Allocations and Declarations
! 8941: -------------------------------------------------------------------------- */
! 8942: static char timebuff[64]; /* date:time buffer back to caller */
! 8943: /*long time_val = 0L;*/ /* binary value returned by time() */
! 8944: time_t time_val = (time_t)(0); /* binary value returned by time() */
! 8945: struct tm *tmstruct=(struct tm *)NULL, *localtime(); /* interpret time_val */
! 8946: int year=0, hour=0,ispm=1; /* adjust year, and set am/pm hour */
! 8947: /* -------------------------------------------------------------------------
! 8948: get current date:time, adjust values, and and format stamp
! 8949: -------------------------------------------------------------------------- */
! 8950: /* --- get current date:time --- */
! 8951: time((time_t *)(&time_val)); /* get date and time */
! 8952: tmstruct = localtime((time_t *)(&time_val)); /* interpret time_val */
! 8953: /* --- adjust year and hour as necessary --- */
! 8954: year = (int)(tmstruct->tm_year); /* local copy of year */
! 8955: hour = (int)(tmstruct->tm_hour); /* local copy of hour */
! 8956: year += 1900; /* set century in year */
! 8957: if ( hour < 12 ) /* am check */
! 8958: { ispm=0; /* reset pm flag */
! 8959: if ( hour == 0 ) hour = 12; } /* set 00hrs = 12am */
! 8960: if ( hour > 12 ) hour -= 12; /* pm check sets 13hrs to 1pm, etc */
! 8961: /* --- format date:time stamp --- */
! 8962: sprintf(timebuff,"%04d-%02d-%02d:%02d:%02d:%02d%s",
! 8963: year,(int)((tmstruct->tm_mon)+1),(int)(tmstruct->tm_mday),
! 8964: hour,(int)(tmstruct->tm_min),(int)(tmstruct->tm_sec),((ispm)?"pm":"am"));
! 8965: return ( timebuff ); /* return stamp to caller */
! 8966: } /* --- end-of-function timestamp() --- */
! 8967:
! 8968:
! 8969: /* ==========================================================================
! 8970: * Function: dtoa ( dblval, npts )
! 8971: * Purpose: Converts double to ascii, in financial format
! 8972: * (e.g., comma-separated and negatives enclosed in ()'s).
! 8973: * -------------------------------------------------------------------------
! 8974: * Arguments: dblval (I) double containing value to be converted.
! 8975: * npts (I) int containing #places after decimal point
! 8976: * to be displayed in returned string.
! 8977: * Returns: ( char * ) null-terminated string containing
! 8978: * double converted to financial format.
! 8979: * -------------------------------------------------------------------------
! 8980: * Notes: o
! 8981: * ======================================================================= */
! 8982: /* --- entry point --- */
! 8983: char *dtoa ( dblval, npts )
! 8984: double dblval;
! 8985: int npts;
! 8986: {
! 8987: /* -------------------------------------------------------------------------
! 8988: Allocations and Declarations
! 8989: ------------------------------------------------------------------------- */
! 8990: static char finval[128]; /* buffer returned to caller */
! 8991: static char digittbl[32]="0123456789*"; /* table of ascii decimal digits */
! 8992: char *finptr = finval; /* ptr to next char being converted*/
! 8993: double floor(); /* integer which is glb(double) */
! 8994: double dbldigit; /* to shift out digits from dblval */
! 8995: int digit; /* one digit from dblval */
! 8996: int isneg = 0; /* reset true if dblval negative */
! 8997: int ifrac = 0; /* npts fractional digits of dblval*/
! 8998: char digits[64]; int ndigits=0; /* all the digits [0]=least signif */
! 8999: /* -------------------------------------------------------------------------
! 9000: Check sign
! 9001: ------------------------------------------------------------------------- */
! 9002: if ( dblval < 0.0 ) /* got a negative value to convert */
! 9003: { isneg=1; dblval=(-dblval); } /* set flag and make it positive */
! 9004: /* -------------------------------------------------------------------------
! 9005: Get fractional part of dblval if required
! 9006: ------------------------------------------------------------------------- */
! 9007: if ( npts > 0 )
! 9008: { int ipts = npts; /* loop index */
! 9009: dbldigit = dblval-floor(dblval); /* fractional part as double */
! 9010: digit = 1; /* check if rounded frac > 1 */
! 9011: while ( --ipts >= 0 ) /* count down */
! 9012: { dbldigit *= 10.0; /* shift left one digit at a time */
! 9013: digit *= 10; } /* and keep max up-to-date */
! 9014: ifrac = (int)(dbldigit + 0.5); /* store fractional part as integer*/
! 9015: if ( ifrac >= digit ) /* round to next whole number */
! 9016: { dblval++; ifrac=0; } /* bump val, reset frac to zero */
! 9017: } /* --- end-of-if(npts>0) --- */
! 9018: else dblval += 0.5; /* no frac, round to nearest whole */
! 9019: /* -------------------------------------------------------------------------
! 9020: Get whole digits
! 9021: ------------------------------------------------------------------------- */
! 9022: dblval = floor(dblval); /* get rid of fractional part */
! 9023: while ( dblval > 0.0 ) /* still have data digits remaining*/
! 9024: { dbldigit = floor(dblval/10.0); /* shift out next digit */
! 9025: digit = (int)(dblval - 10.0*dbldigit + 0.01); /* least signif digit */
! 9026: if ( digit<0 || digit>9 ) digit=10; /* index check */
! 9027: digits[ndigits++] = digittbl[digit]; /* store ascii digit */
! 9028: dblval = dbldigit; } /* ready for next digit */
! 9029: if ( ndigits < 1 ) digits[ndigits++] = '0'; /* store a single '0' for 0.0 */
! 9030: /* -------------------------------------------------------------------------
! 9031: Format whole part from digits[] array
! 9032: ------------------------------------------------------------------------- */
! 9033: if ( isneg ) *finptr++ = '('; /* leading paren for negative value*/
! 9034: for ( digit=ndigits-1; digit>=0; digit-- ) /* start with most significant */
! 9035: { *finptr++ = digits[digit]; /* store digit */
! 9036: if ( digit>0 && digit%3==0 ) /* need a comma */
! 9037: *finptr++ = ','; } /* put in separating comma */
! 9038: /* -------------------------------------------------------------------------
! 9039: Format fractional part using ifrac
! 9040: ------------------------------------------------------------------------- */
! 9041: if ( npts > 0 )
! 9042: { *finptr++ = '.'; /* start with decimal point */
! 9043: sprintf(finptr,"%0*d",npts,ifrac); /* convert to string */
! 9044: finptr += npts; } /* bump ptr past fractional digits */
! 9045: /* -------------------------------------------------------------------------
! 9046: End-of-Job
! 9047: ------------------------------------------------------------------------- */
! 9048: if ( isneg ) *finptr++ = ')'; /*trailing paren for negative value*/
! 9049: *finptr = '\000'; /* null-terminate converted double */
! 9050: return ( finval ); /* converted double back to caller */
! 9051: } /* --- end-of-function dtoa() --- */
! 9052:
! 9053:
! 9054: /* ==========================================================================
! 9055: * Function: aalowpass ( rp, bytemap, grayscale )
! 9056: * Purpose: calculates a lowpass anti-aliased bytemap
! 9057: * for rp->bitmap, with each byte 0...grayscale-1
! 9058: * --------------------------------------------------------------------------
! 9059: * Arguments: rp (I) raster * to raster whose bitmap
! 9060: * is to be anti-aliased
! 9061: * bytemap (O) intbyte * to bytemap, calculated
! 9062: * by applying lowpass filter to rp->bitmap,
! 9063: * and returned (as you'd expect) in 1-to-1
! 9064: * addressing correspondence with rp->bitmap
! 9065: * grayscale (I) int containing number of grayscales
! 9066: * to be calculated, 0...grayscale-1
! 9067: * (should typically be given as 256)
! 9068: * --------------------------------------------------------------------------
! 9069: * Returns: ( int ) 1=success, 0=any error
! 9070: * --------------------------------------------------------------------------
! 9071: * Notes: o If the center point of the box being averaged is black,
! 9072: * then the entire "average" is forced black (grayscale-1)
! 9073: * regardless of the surrounding points. This is my attempt
! 9074: * to avoid a "washed-out" appearance of thin (one-pixel-wide)
! 9075: * lines, which would otherwise turn from black to a gray shade.
! 9076: * o Also, while the weights for neighbor points are fixed,
! 9077: * you may adjust the center point weight on the compile line.
! 9078: * A higher weight sharpens the resulting anti-aliased image;
! 9079: * lower weights blur it out more (but keep the "center" black
! 9080: * as per the preceding note).
! 9081: * ======================================================================= */
! 9082: /* --- entry point --- */
! 9083: int aalowpass (raster *rp, intbyte *bytemap, int grayscale)
! 9084: {
! 9085: /* -------------------------------------------------------------------------
! 9086: Allocations and Declarations
! 9087: -------------------------------------------------------------------------- */
! 9088: int status = 1; /* 1=success, 0=failure to caller */
! 9089: pixbyte *bitmap= (rp==NULL?NULL:rp->pixmap); /*local rp->pixmap ptr*/
! 9090: int irow=0, icol=0; /* rp->height, rp->width indexes */
! 9091: int weights[9] = { 1,3,1, 3,0,3, 1,3,1 }; /* matrix of weights */
! 9092: int adjindex[9]= { 0,1,2, 7,-1,3, 6,5,4 }; /*clockwise from upper-left*/
! 9093: int totwts = 0; /* sum of all weights in matrix */
! 9094: int isforceavg = 1, /*force avg black if center black?*/
! 9095: isminmaxwts = 1, /*use wts or #pts for min/max test */
! 9096: blackscale = 0; /*(grayscale+1)/4;*/ /*force black if wgted avg>bs */
! 9097: /* -------------------------------------------------------------------------
! 9098: Initialization
! 9099: -------------------------------------------------------------------------- */
! 9100: /* --- calculate total weights --- */
! 9101: weights[4]= centerwt; /* weight for center point */
! 9102: weights[1]= weights[3]= weights[5]= weights[7]= adjacentwt; /*adjacent pts*/
! 9103: totwts = centerwt + 4*(1+adjacentwt); /* tot is center plus neighbors */
! 9104: /* -------------------------------------------------------------------------
! 9105: Calculate bytemap as 9-point weighted average over bitmap
! 9106: -------------------------------------------------------------------------- */
! 9107: for ( irow=0; irow<rp->height; irow++ )
! 9108: for ( icol=0; icol<rp->width; icol++ )
! 9109: {
! 9110: int ipixel = icol + irow*(rp->width); /* center pixel index */
! 9111: int jrow=0, jcol=0, /* box around ipixel */
! 9112: bitval = 0, /* value of bit/pixel at jrow,jcol */
! 9113: iscenter = 0, /* set true if center pixel black */
! 9114: nadjacent=0, wadjacent=0, /* #adjacent black pixels, their wts*/
! 9115: ngaps = 0, /* #gaps in 8 pixels around center */
! 9116: iwt=(-1), sumwts=0; /* weights index, sum in-bound wts */
! 9117: char adjmatrix[8]; /* adjacency "matrix" */
! 9118: memset(adjmatrix,0,8); /* zero out adjacency matrix */
! 9119: bytemap[ipixel] = 0; /* init pixel white */
! 9120: /*--- for ipixel at irow,icol, get weighted average of adjacent pixels ---*/
! 9121: for ( jrow=irow-1; jrow<=irow+1; jrow++ ) /* jrow = irow-1...irow+1 */
! 9122: for ( jcol=icol-1; jcol<=icol+1; jcol++ ) /* jcol = icol-1...icol+1 */
! 9123: {
! 9124: int jpixel = jcol + jrow*(rp->width); /* averaging index */
! 9125: iwt++; /*always bump weight index*/
! 9126: if ( jrow<0 || jrow>=rp->height /* if row out pf bounds */
! 9127: || jcol<0 || jcol>=rp->width ) /* or col out of bounds */
! 9128: continue; /* ignore this point */
! 9129: bitval = (int)getlongbit(bitmap,jpixel); /* value of bit at jrow,jcol */
! 9130: if ( bitval ) /* this is a black pixel */
! 9131: { if ( jrow==irow && jcol==icol ) /* and this is center point */
! 9132: iscenter = 1; /* set flag for center point black */
! 9133: else /* adjacent point black */
! 9134: { nadjacent++; /* bump adjacent black count */
! 9135: adjmatrix[adjindex[iwt]] = 1; } /*set "bit" in adjacency matrix*/
! 9136: wadjacent += weights[iwt]; } /* sum weights for black pixels */
! 9137: sumwts += weights[iwt]; /* and sum weights for all pixels */
! 9138: } /* --- end-of-for(jrow,jcol) --- */
! 9139: /* --- count gaps --- */
! 9140: ngaps = (adjmatrix[7]!=adjmatrix[0]?1:0); /* init count */
! 9141: for ( iwt=0; iwt<7; iwt++ ) /* clockwise around adjacency */
! 9142: if ( adjmatrix[iwt] != adjmatrix[iwt+1] ) ngaps++; /* black/white flip */
! 9143: ngaps /= 2; /*each gap has 2 black/white flips*/
! 9144: /* --- anti-alias pixel, but leave it black if it was already black --- */
! 9145: if ( isforceavg && iscenter ) /* force avg if center point black */
! 9146: bytemap[ipixel] = grayscale-1; /* so force grayscale-1=black */
! 9147: else /* center point not black */
! 9148: if ( ngaps <= 2 ) /*don't darken checkerboarded pixel*/
! 9149: { bytemap[ipixel] = /* 0=white ... grayscale-1=black */
! 9150: ((totwts/2 - 1) + (grayscale-1)*wadjacent)/totwts; /* not /sumwts; */
! 9151: if ( blackscale > 0 /* blackscale kludge turned on */
! 9152: && bytemap[ipixel] > blackscale ) /* weighted avg > blackscale */
! 9153: bytemap[ipixel] = grayscale-1; } /* so force it entirely black */
! 9154: /*--- only anti-alias pixels whose adjacent pixels fall within bounds ---*/
! 9155: if ( !iscenter ) /* apply min/maxadjacent test */
! 9156: if ( isminmaxwts ) /* min/max refer to adjacent weights*/
! 9157: { if ( wadjacent < minadjacent /* wts of adjacent points too low */
! 9158: || wadjacent > maxadjacent ) /* or too high */
! 9159: bytemap[ipixel] = 0; } /* so leave point white */
! 9160: else /* min/max refer to #adjacent points*/
! 9161: { if ( nadjacent < minadjacent /* too few adjacent points black */
! 9162: || nadjacent > maxadjacent ) /* or too many */
! 9163: bytemap[ipixel] = 0; } /* so leave point white */
! 9164: } /* --- end-of-for(irow,icol) --- */
! 9165: /* -------------------------------------------------------------------------
! 9166: Back to caller with gray-scale anti-aliased bytemap
! 9167: -------------------------------------------------------------------------- */
! 9168: /*end_of_job:*/
! 9169: return ( status );
! 9170: } /* --- end-of-function aalowpass() --- */
! 9171:
! 9172:
! 9173: /* ==========================================================================
! 9174: * Function: aapnm ( rp, bytemap, grayscale )
! 9175: * Purpose: calculates a lowpass anti-aliased bytemap
! 9176: * for rp->bitmap, with each byte 0...grayscale-1,
! 9177: * based on the pnmalias.c algorithm
! 9178: * --------------------------------------------------------------------------
! 9179: * Arguments: rp (I) raster * to raster whose bitmap
! 9180: * is to be anti-aliased
! 9181: * bytemap (O) intbyte * to bytemap, calculated
! 9182: * by applying pnm-based filter to rp->bitmap,
! 9183: * and returned (as you'd expect) in 1-to-1
! 9184: * addressing correspondence with rp->bitmap
! 9185: * grayscale (I) int containing number of grayscales
! 9186: * to be calculated, 0...grayscale-1
! 9187: * (should typically be given as 256)
! 9188: * --------------------------------------------------------------------------
! 9189: * Returns: ( int ) 1=success, 0=any error
! 9190: * --------------------------------------------------------------------------
! 9191: * Notes: o Based on the pnmalias.c algorithm in the netpbm package
! 9192: * on sourceforge.
! 9193: * ======================================================================= */
! 9194: /* --- entry point --- */
! 9195: int aapnm (raster *rp, intbyte *bytemap, int grayscale)
! 9196: {
! 9197: /* -------------------------------------------------------------------------
! 9198: Allocations and Declarations
! 9199: -------------------------------------------------------------------------- */
! 9200: pixbyte *bitmap = rp->pixmap; /* local rp->pixmap ptr */
! 9201: int width=rp->width, height=rp->height, /* width, height of raster */
! 9202: icol = 0, irow = 0, /* width, height indexes */
! 9203: imap = (-1); /* pixel index = icol + irow*width */
! 9204: int bgbitval=0, fgbitval=1; /* background, foreground bitval */
! 9205: #if 0
! 9206: int totwts=12, wts[9]={1,1,1, 1,4,1, 1,1,1}; /* pnmalias default wts */
! 9207: int totwts=16, wts[9]={1,2,1, 2,4,2, 1,2,1}; /* weights */
! 9208: #endif
! 9209: int totwts=18, wts[9]={1,2,1, 2,6,2, 1,2,1}; /* pnmalias default wts */
! 9210: int isresetparams = 1, /* true to set antialiasing params */
! 9211: isfgalias = 1, /* true to antialias fg bits */
! 9212: isfgonly = 0, /* true to only antialias fg bits */
! 9213: isbgalias = 0, /* true to antialias bg bits */
! 9214: isbgonly = 0; /* true to only antialias bg bits */
! 9215: /* -------------------------------------------------------------------------
! 9216: Initialization
! 9217: -------------------------------------------------------------------------- */
! 9218: /* --- check for bold light --- */
! 9219: if ( 0 )
! 9220: { if ( weightnum > 2 ) { isbgalias=1; } /* simulate bold */
! 9221: if ( weightnum < 1 ) { isbgonly=1; isfgalias=0; } } /* simulate light */
! 9222: /* --- reset wts[], etc, and calculate total weights --- */
! 9223: if ( isresetparams ) /* wts[], etc taken from params */
! 9224: { int iwt=0; /* wts[iwt] index */
! 9225: wts[4]= centerwt; /* weight for center point */
! 9226: wts[1]=wts[3]=wts[5]=wts[7] = adjacentwt; /* and adjacent points */
! 9227: wts[0]=wts[2]=wts[6]=wts[8] = cornerwt; /* and corner points */
! 9228: for ( totwts=0,iwt=0; iwt<9; iwt++ ) totwts += wts[iwt]; /* sum wts */
! 9229: isfgalias = fgalias; /* set isfgalias */
! 9230: isfgonly = fgonly; /* set isfgonly */
! 9231: isbgalias = bgalias; /* set isbgalias */
! 9232: isbgonly = bgonly; } /* set isbgonly */
! 9233: /* -------------------------------------------------------------------------
! 9234: Calculate bytemap as 9-point weighted average over bitmap
! 9235: -------------------------------------------------------------------------- */
! 9236: for ( irow=0; irow<height; irow++ )
! 9237: for ( icol=0; icol<width; icol++ )
! 9238: {
! 9239: /* --- local allocations and declarations --- */
! 9240: int bitval=0, /* value of rp bit at irow,icol */
! 9241: nnbitval=0, nebitval=0, eebitval=0, sebitval=0, /*adjacent vals*/
! 9242: ssbitval=0, swbitval=0, wwbitval=0, nwbitval=0; /*compass pt names*/
! 9243: int isbgedge=0, isfgedge=0; /*does pixel border a bg or fg edge*/
! 9244: int aabyteval=0; /* antialiased (or unchanged) value*/
! 9245: /* --- bump imap index and get center bit value --- */
! 9246: imap++; /* imap = icol + irow*width */
! 9247: bitval = getlongbit(bitmap,imap); /* value of rp input bit at imap */
! 9248: aabyteval = (intbyte)(bitval==bgbitval?0:grayscale-1); /* default aa val */
! 9249: bytemap[imap] = (intbyte)(aabyteval); /* init antialiased pixel */
! 9250: /* --- check if we're antialiasing this pixel --- */
! 9251: if ( (isbgonly && bitval==fgbitval) /* only antialias background bit */
! 9252: || (isfgonly && bitval==bgbitval) ) /* only antialias foreground bit */
! 9253: continue; /* leave default and do next bit */
! 9254: /* --- get surrounding bits --- */
! 9255: if ( irow > 0 ) /* nn (north) bit available */
! 9256: nnbitval = getlongbit(bitmap,imap-width); /* nn bit value */
! 9257: if ( irow < height-1 ) /* ss (south) bit available */
! 9258: ssbitval = getlongbit(bitmap,imap+width); /* ss bit value */
! 9259: if ( icol > 0 ) /* ww (west) bit available */
! 9260: { wwbitval = getlongbit(bitmap,imap-1); /* ww bit value */
! 9261: if ( irow > 0 ) /* nw bit available */
! 9262: nwbitval = getlongbit(bitmap,imap-width-1); /* nw bit value */
! 9263: if ( irow < height-1 ) /* sw bit available */
! 9264: swbitval = getlongbit(bitmap,imap+width-1); } /* sw bit value */
! 9265: if ( icol < width-1 ) /* ee (east) bit available */
! 9266: { eebitval = getlongbit(bitmap,imap+1); /* ee bit value */
! 9267: if ( irow > 0 ) /* ne bit available */
! 9268: nebitval = getlongbit(bitmap,imap-width+1); /* ne bit value */
! 9269: if ( irow < height-1 ) /* se bit available */
! 9270: sebitval = getlongbit(bitmap,imap+width+1); } /* se bit value */
! 9271: /* --- check for edges --- */
! 9272: isbgedge = /* current pixel borders a bg edge */
! 9273: (nnbitval==bgbitval && eebitval==bgbitval) || /*upper-right edge*/
! 9274: (eebitval==bgbitval && ssbitval==bgbitval) || /*lower-right edge*/
! 9275: (ssbitval==bgbitval && wwbitval==bgbitval) || /*lower-left edge*/
! 9276: (wwbitval==bgbitval && nnbitval==bgbitval) ; /*upper-left edge*/
! 9277: isfgedge = /* current pixel borders an fg edge*/
! 9278: (nnbitval==fgbitval && eebitval==fgbitval) || /*upper-right edge*/
! 9279: (eebitval==fgbitval && ssbitval==fgbitval) || /*lower-right edge*/
! 9280: (ssbitval==fgbitval && wwbitval==fgbitval) || /*lower-left edge*/
! 9281: (wwbitval==fgbitval && nnbitval==fgbitval) ; /*upper-left edge*/
! 9282: /* --- antialias if necessary --- */
! 9283: if ( (isbgalias && isbgedge) /* alias pixel surrounding bg */
! 9284: || (isfgalias && isfgedge) /* alias pixel surrounding fg */
! 9285: || (isbgedge && isfgedge) ) /* neighboring fg and bg pixel */
! 9286: {
! 9287: int aasumval = /* sum wts[]*bitmap[] */
! 9288: wts[0]*nwbitval + wts[1]*nnbitval + wts[2]*nebitval +
! 9289: wts[3]*wwbitval + wts[4]*bitval + wts[5]*eebitval +
! 9290: wts[6]*swbitval + wts[7]*ssbitval + wts[8]*sebitval ;
! 9291: double aawtval = ((double)aasumval)/((double)totwts); /* weighted val */
! 9292: aabyteval= (int)(((double)(grayscale-1))*aawtval+0.5); /*0...grayscale-1*/
! 9293: bytemap[imap] = (intbyte)(aabyteval); /* set antialiased pixel */
! 9294: if ( msglevel>=99 && msgfp!=NULL ) fprintf(msgfp, /* debugging */
! 9295: "aapnm> irow,icol,imap=%d,%d,%d aawtval=%.4f aabyteval=%d\n",
! 9296: irow,icol,imap, aawtval,aabyteval);
! 9297: } /* --- end-of-if(isedge) --- */
! 9298: } /* --- end-of-for(irow,icol) --- */
! 9299: /* -------------------------------------------------------------------------
! 9300: Back to caller with gray-scale anti-aliased bytemap
! 9301: -------------------------------------------------------------------------- */
! 9302: /*end_of_job:*/
! 9303: return ( 1 );
! 9304: } /* --- end-of-function aapnm() --- */
! 9305:
! 9306:
! 9307: /* ==========================================================================
! 9308: * Function: aasupsamp ( rp, aa, sf, grayscale )
! 9309: * Purpose: calculates a supersampled anti-aliased bytemap
! 9310: * for rp->bitmap, with each byte 0...grayscale-1
! 9311: * --------------------------------------------------------------------------
! 9312: * Arguments: rp (I) raster * to raster whose bitmap
! 9313: * is to be anti-aliased
! 9314: * aa (O) address of raster * to supersampled bytemap,
! 9315: * calculated by supersampling rp->bitmap
! 9316: * sf (I) int containing supersampling shrinkfactor
! 9317: * grayscale (I) int containing number of grayscales
! 9318: * to be calculated, 0...grayscale-1
! 9319: * (should typically be given as 256)
! 9320: * --------------------------------------------------------------------------
! 9321: * Returns: ( int ) 1=success, 0=any error
! 9322: * --------------------------------------------------------------------------
! 9323: * Notes: o If the center point of the box being averaged is black,
! 9324: * then the entire "average" is forced black (grayscale-1)
! 9325: * regardless of the surrounding points. This is my attempt
! 9326: * to avoid a "washed-out" appearance of thin (one-pixel-wide)
! 9327: * lines, which would otherwise turn from black to a gray shade.
! 9328: * ======================================================================= */
! 9329: /* --- entry point --- */
! 9330: int aasupsamp (raster *rp, raster **aa, int sf, int grayscale)
! 9331: {
! 9332: /* -------------------------------------------------------------------------
! 9333: Allocations and Declarations
! 9334: -------------------------------------------------------------------------- */
! 9335: int status = 0; /* 1=success, 0=failure to caller */
! 9336: int rpheight=rp->height, rpwidth=rp->width, /*bitmap raster dimensions*/
! 9337: heightrem=0, widthrem=0, /* rp+rem is a multiple of shrinkf */
! 9338: aaheight=0, aawidth=0, /* supersampled dimensions */
! 9339: aapixsz=8; /* output pixels are 8-bit bytes */
! 9340: int maxaaval=(-9999), /* max grayscale val set in matrix */
! 9341: isrescalemax=1; /* 1=rescale maxaaval to grayscale */
! 9342: int irp=0,jrp=0, iaa=0,jaa=0, iwt=0,jwt=0; /*indexes, i=width j=height*/
! 9343: raster *aap=NULL, *new_raster(); /* raster for supersampled image */
! 9344: raster *aaweights(); /* get weight matrix applied to rp */
! 9345: static raster *aawts = NULL; /* aaweights() resultant matrix */
! 9346: static int prevshrink = NOVALUE, /* shrinkfactor from previous call */
! 9347: sumwts = 0; /* sum of weights */
! 9348: static int blackfrac = 40, /* force black if this many pts are */
! 9349: /*grayfrac = 20,*/
! 9350: maxwt = 10, /* max weight in weight matrix */
! 9351: minwtfrac=10, maxwtfrac=70; /* force light pts white, dark black*/
! 9352: int type_raster(), type_bytemap(); /* debugging display routines */
! 9353: int delete_raster(); /* delete old rasters */
! 9354: /* -------------------------------------------------------------------------
! 9355: Initialization
! 9356: -------------------------------------------------------------------------- */
! 9357: /* --- check args --- */
! 9358: if ( aa == NULL ) goto end_of_job; /* no ptr for return output arg */
! 9359: *aa = NULL; /* init null ptr for error return */
! 9360: if ( rp == NULL /* no ptr to input arg */
! 9361: || sf < 1 /* invalid shrink factor */
! 9362: || grayscale < 2 ) goto end_of_job; /* invalid grayscale */
! 9363: /* --- get weight matrix (or use current one) --- */
! 9364: if ( sf != prevshrink ) /* have new shrink factor */
! 9365: { if ( aawts != NULL ) /* have unneeded weight matrix */
! 9366: delete_raster(aawts); /* so free it */
! 9367: sumwts = 0; /* reinitialize sum of weights */
! 9368: aawts = aaweights(sf,sf); /* get new weight matrix */
! 9369: if ( aawts != NULL ) /* got weight matrix okay*/
! 9370: for ( jwt=0; jwt<sf; jwt++ ) /* for each row */
! 9371: for ( iwt=0; iwt<sf; iwt++ ) /* and each column */
! 9372: { int wt = (int)(getpixel(aawts,jwt,iwt)); /* weight */
! 9373: if ( wt > maxwt ) /* don't overweight center pts */
! 9374: { wt = maxwt; /* scale it back */
! 9375: setpixel(aawts,jwt,iwt,wt); } /* and replace it in matrix */
! 9376: sumwts += wt; } /* add weight to sum */
! 9377: prevshrink = sf; } /* save new shrink factor */
! 9378: if ( msgfp!=NULL && msglevel>=999 )
! 9379: { fprintf(msgfp,"aasupsamp> sf=%d, sumwts=%d weights=...\n", sf,sumwts);
! 9380: type_bytemap((intbyte *)aawts->pixmap,grayscale,
! 9381: aawts->width,aawts->height,msgfp); }
! 9382: /* --- calculate supersampled height,width and allocate output raster */
! 9383: heightrem = rpheight%sf; /* remainder after division... */
! 9384: widthrem = rpwidth%sf; /* ...by shrinkfactor */
! 9385: aaheight = 1+(rpheight+sf-(heightrem+1))/sf; /* ss height */
! 9386: aawidth = 1+(rpwidth+sf-(widthrem+1))/sf; /* ss width */
! 9387: if ( msgfp!=NULL && msglevel>=999 )
! 9388: { fprintf(msgfp,"aasupsamp> rpwid,ht=%d,%d wd,htrem=%d,%d aawid,ht=%d,%d\n",
! 9389: rpwidth,rpheight, widthrem,heightrem, aawidth,aaheight);
! 9390: fprintf(msgfp,"aasupsamp> dump of original bitmap image...\n");
! 9391: type_raster(rp,msgfp); } /* ascii image of rp raster */
! 9392: if ( (aap = new_raster(aawidth,aaheight,aapixsz)) /* alloc output raster*/
! 9393: == NULL ) goto end_of_job; /* quit if alloc fails */
! 9394: /* -------------------------------------------------------------------------
! 9395: Step through rp->bitmap, applying aawts to each "submatrix" of bitmap
! 9396: -------------------------------------------------------------------------- */
! 9397: for ( jaa=0,jrp=(-(heightrem+1)/2); jrp<rpheight; jrp+=sf ) /* height */
! 9398: {
! 9399: for ( iaa=0,irp=(-(widthrem+1)/2); irp<rpwidth; irp+=sf ) /* width */
! 9400: {
! 9401: int aaval=0; /* weighted rpvals */
! 9402: int nrp=0, mrp=0; /* #rp bits set, #within matrix */
! 9403: for ( jwt=0; jwt<sf; jwt++ )
! 9404: for ( iwt=0; iwt<sf; iwt++ )
! 9405: {
! 9406: int i=irp+iwt, j=jrp+jwt; /* rp->pixmap point */
! 9407: int rpval = 0; /* rp->pixmap value at i,j */
! 9408: if ( i>=0 && i<rpwidth /* i within actual pixmap */
! 9409: && j>=0 && j<rpheight ) /* ditto j */
! 9410: { mrp++; /* count another bit within matrix */
! 9411: rpval = (int)(getpixel(rp,j,i)); } /* get actual pixel value */
! 9412: if ( rpval != 0 )
! 9413: { nrp++; /* count another bit set */
! 9414: aaval += (int)(getpixel(aawts,jwt,iwt)); } /* sum weighted vals */
! 9415: } /* --- end-of-for(iwt,jwt) --- */
! 9416: if ( aaval > 0 ) /*normalize and rescale non-zero val*/
! 9417: { int aafrac = (100*aaval)/sumwts; /* weighted percent of black points */
! 9418: /*if((100*nrp)/mrp >=blackfrac)*/ /* many black interior pts */
! 9419: if( aafrac >= maxwtfrac ) /* high weight of sampledblack pts */
! 9420: aaval = grayscale-1; /* so set supersampled pt black */
! 9421: else if( aafrac <= minwtfrac ) /* low weight of sampledblack pts */
! 9422: aaval = 0; /* so set supersampled pt white */
! 9423: else /* rescale calculated weight */
! 9424: aaval = ((sumwts/2 - 1) + (grayscale-1)*aaval)/sumwts; }
! 9425: maxaaval = max2(maxaaval,aaval); /* largest aaval so far */
! 9426: if ( msgfp!=NULL && msglevel>=999 )
! 9427: fprintf(msgfp,"aasupsamp> jrp,irp=%d,%d jaa,iaa=%d,%d"
! 9428: " mrp,nrp=%d,%d aaval=%d\n",
! 9429: jrp,irp, jaa,iaa, mrp,nrp, aaval);
! 9430: if ( jaa<aaheight && iaa<aawidth ) /* bounds check */
! 9431: setpixel(aap,jaa,iaa,aaval); /*weighted val in supersamp raster*/
! 9432: else if( msgfp!=NULL && msglevel>=9 ) /* emit error if out-of-bounds */
! 9433: fprintf(msgfp,"aasupsamp> Error: aaheight,aawidth=%d,%d jaa,iaa=%d,%d\n",
! 9434: aaheight,aawidth, jaa,iaa);
! 9435: iaa++; /* bump aa col index */
! 9436: } /* --- end-of-for(irp) --- */
! 9437: jaa++; /* bump aa row index */
! 9438: } /* --- end-of-for(jrp) --- */
! 9439: /* --- rescale supersampled image so darkest points become black --- */
! 9440: if ( isrescalemax ) /* flag set to rescale maxaaval */
! 9441: {
! 9442: double scalef = ((double)(grayscale-1))/((double)maxaaval);
! 9443: for ( jaa=0; jaa<aaheight; jaa++ ) /* height */
! 9444: for ( iaa=0; iaa<aawidth; iaa++ ) /* width */
! 9445: { int aafrac, aaval = getpixel(aap,jaa,iaa); /* un-rescaled value */
! 9446: aaval = (int)(0.5+((double)aaval)*scalef); /*multiply by scale factor*/
! 9447: aafrac = (100*aaval)/(grayscale-1); /* fraction of blackness */
! 9448: if( aafrac >= blackfrac ) /* high weight of sampledblack pts */
! 9449: aaval = grayscale-1; /* so set supersampled pt black */
! 9450: else if( 0&&aafrac <= minwtfrac ) /* low weight of sampledblack pts */
! 9451: aaval = 0; /* so set supersampled pt white */
! 9452: setpixel(aap,jaa,iaa,aaval); } /* replace rescaled val in raster */
! 9453: } /* --- end-of-if(isrescalemax) --- */
! 9454: *aa = aap; /* return supersampled image*/
! 9455: status = 1; /* set successful status */
! 9456: if ( msgfp!=NULL && msglevel>=999 )
! 9457: { fprintf(msgfp,"aasupsamp> anti-aliased image...\n");
! 9458: type_bytemap((intbyte *)aap->pixmap,grayscale,
! 9459: aap->width,aap->height,msgfp); fflush(msgfp); }
! 9460: /* -------------------------------------------------------------------------
! 9461: Back to caller with gray-scale anti-aliased bytemap
! 9462: -------------------------------------------------------------------------- */
! 9463: end_of_job:
! 9464: return ( status );
! 9465: } /* --- end-of-function aasupsamp() --- */
! 9466:
! 9467:
! 9468: /* ==========================================================================
! 9469: * Function: aacolormap ( bytemap, nbytes, colors, colormap )
! 9470: * Purpose: searches bytemap, returning a list of its discrete values
! 9471: * in ascending order in colors[], and returning an "image"
! 9472: * of bytemap (where vales are replaced by colors[]
! 9473: * indexes) in colormap[].
! 9474: * --------------------------------------------------------------------------
! 9475: * Arguments: bytemap (I) intbyte * to bytemap containing
! 9476: * grayscale values (usually 0=white
! 9477: * through 255=black) for which colors[]
! 9478: * and colormap[] will be constructed.
! 9479: * nbytes (I) int containing #bytes in bytemap
! 9480: * (usually just #rows * #cols)
! 9481: * colors (O) intbyte * (to be interpreted as ints)
! 9482: * returning a list of the discrete/different
! 9483: * values in bytemap, in ascending value order
! 9484: * colormap (O) intbyte * returning a bytemap "image",
! 9485: * i.e., in one-to-one pixel correspondence
! 9486: * with bytemap, but where the values have been
! 9487: * replaced with corresponding colors[] indexes.
! 9488: * --------------------------------------------------------------------------
! 9489: * Returns: ( int ) #colors in colors[], or 0 for any error
! 9490: * --------------------------------------------------------------------------
! 9491: * Notes: o
! 9492: * ======================================================================= */
! 9493: /* --- entry point --- */
! 9494: int aacolormap ( intbyte *bytemap, int nbytes,
! 9495: intbyte *colors, intbyte *colormap )
! 9496: {
! 9497: /* -------------------------------------------------------------------------
! 9498: Allocations and Declarations
! 9499: -------------------------------------------------------------------------- */
! 9500: int ncolors = 0, /* #different values in bytemap */
! 9501: igray, grayscale = 256; /* bytemap contains intbyte's */
! 9502: intbyte *bytevalues = NULL; /* 1's where bytemap contains value*/
! 9503: int ibyte; /* bytemap/colormap index */
! 9504: int isscale = 0; /* true to scale largest val to 255*/
! 9505: int maxcolors = 0; /* maximum ncolors */
! 9506: /* -------------------------------------------------------------------------
! 9507: Accumulate colors[] from values occurring in bytemap
! 9508: -------------------------------------------------------------------------- */
! 9509: /* --- initialization --- */
! 9510: if ( (bytevalues = (intbyte *)malloc(grayscale)) /*alloc bytevalues*/
! 9511: == NULL ) goto end_of_job; /* signal error if malloc() failed */
! 9512: memset(bytevalues,0,grayscale); /* zero out bytevalues */
! 9513: /* --- now set 1's at offsets corresponding to values found in bytemap --- */
! 9514: for ( ibyte=0; ibyte<nbytes; ibyte++ ) /* for each byte in bytemap */
! 9515: bytevalues[(int)bytemap[ibyte]] = 1; /*use its value to index bytevalues*/
! 9516: /* --- collect the 1's indexes in colors[] --- */
! 9517: for ( igray=0; igray<grayscale; igray++ ) /* check all possible values */
! 9518: if ( (int)bytevalues[igray] ) /*bytemap contains igray somewheres*/
! 9519: { colors[ncolors] = (intbyte)igray; /* so store igray in colors */
! 9520: bytevalues[igray] = (intbyte)ncolors; /* save colors[] index */
! 9521: if ( maxcolors>0 && ncolors>=maxcolors ) /* too many color indexes */
! 9522: bytevalues[igray] = (intbyte)(maxcolors-1); /*so scale back to max*/
! 9523: ncolors++; } /* and bump #colors */
! 9524: /* --- rescale colors so largest, colors[ncolors-1], is black --- */
! 9525: if ( isscale ) /* only rescale if requested */
! 9526: if ( ncolors > 1 ) /* and if not a "blank" raster */
! 9527: if ( colors[ncolors-1] > 0 ) /*and at least one pixel non-white*/
! 9528: {
! 9529: /* --- multiply each colors[] by factor that scales largest to 255 --- */
! 9530: double scalefactor = ((double)(grayscale-1))/((double)colors[ncolors-1]);
! 9531: for ( igray=1; igray<ncolors; igray++ ) /* re-scale each colors[] */
! 9532: { colors[igray] = min2(grayscale-1,(int)(scalefactor*colors[igray]+0.5));
! 9533: if (igray>5) colors[igray] = min2(grayscale-1,colors[igray]+2*igray); }
! 9534: } /* --- end-of-if(isscale) --- */
! 9535: /* -------------------------------------------------------------------------
! 9536: Construct colormap
! 9537: -------------------------------------------------------------------------- */
! 9538: for ( ibyte=0; ibyte<nbytes; ibyte++ ) /* for each byte in bytemap */
! 9539: colormap[ibyte] = bytevalues[(int)bytemap[ibyte]]; /*index for this value*/
! 9540: /* -------------------------------------------------------------------------
! 9541: back to caller with #colors, or 0 for any error
! 9542: -------------------------------------------------------------------------- */
! 9543: end_of_job:
! 9544: if ( bytevalues != NULL ) free(bytevalues); /* free working memory */
! 9545: if ( maxcolors>0 && ncolors>maxcolors ) /* too many color indexes */
! 9546: ncolors = maxcolors; /* return maximum to caller */
! 9547: return ( ncolors ); /* back with #colors, or 0=error */
! 9548: } /* --- end-of-function aacolormap() --- */
! 9549:
! 9550:
! 9551: /* ==========================================================================
! 9552: * Function: aaweights ( width, height )
! 9553: * Builds "canonical" weight matrix, width x height, in a raster
! 9554: * (see Notes below for discussion).
! 9555: * --------------------------------------------------------------------------
! 9556: * Arguments: width (I) int containing width (#cols) of returned
! 9557: * raster/matrix of weights
! 9558: * height (I) int containing height (#rows) of returned
! 9559: * raster/matrix of weights
! 9560: * --------------------------------------------------------------------------
! 9561: * Returns: ( raster * ) ptr to raster containing width x height
! 9562: * weight matrix, or NULL for any error
! 9563: * --------------------------------------------------------------------------
! 9564: * Notes: o For example, given width=7, height=5, builds the matrix
! 9565: * 1 2 3 4 3 2 1
! 9566: * 2 4 6 8 6 4 2
! 9567: * 3 6 9 12 9 6 3
! 9568: * 2 4 6 8 6 4 2
! 9569: * 1 2 3 4 3 2 1
! 9570: * If an even dimension given, the two center numbers stay
! 9571: * the same, e.g., 123321 for the top row if width=6.
! 9572: * o For an odd square n x n matrix, the sum of all n^2
! 9573: * weights will be ((n+1)/2)^4.
! 9574: * o The largest weight (in the allocated pixsz=8 raster) is 255,
! 9575: * so the largest square matrix is 31 x 31. Any weight that
! 9576: * tries to grow beyond 255 is held constant at 255.
! 9577: * o A new_raster(), pixsz=8, is allocated for the caller.
! 9578: * To avoid memory leaks, be sure to delete_raster() when done.
! 9579: * ======================================================================= */
! 9580: /* --- entry point --- */
! 9581: raster *aaweights ( int width, int height )
! 9582: {
! 9583: /* -------------------------------------------------------------------------
! 9584: Allocations and Declarations
! 9585: -------------------------------------------------------------------------- */
! 9586: raster *new_raster(), *weights=NULL; /* raster of weights returned */
! 9587: int irow=0, icol=0, /* height, width indexes */
! 9588: weight = 0; /*running weight, as per Notes above*/
! 9589: /* -------------------------------------------------------------------------
! 9590: Initialization
! 9591: -------------------------------------------------------------------------- */
! 9592: /* --- allocate raster for weights --- */
! 9593: if ( (weights = new_raster(width,height,8)) /* allocate 8-bit byte raster */
! 9594: == NULL ) goto end_of_job; /* return NULL error if failed */
! 9595: /* -------------------------------------------------------------------------
! 9596: Fill weight matrix, as per Notes above
! 9597: -------------------------------------------------------------------------- */
! 9598: for ( irow=0; irow<height; irow++ ) /* outer loop over rows */
! 9599: for ( icol=0; icol<width; icol++ ) /* inner loop over cols */
! 9600: {
! 9601: int jrow = height-irow-1, /* backwards irow, height-1,...,0 */
! 9602: jcol = width-icol-1; /* backwards icol, width-1,...,0 */
! 9603: weight = min2(irow+1,jrow+1) * min2(icol+1,jcol+1); /* weight */
! 9604: if ( aaalgorithm == 1 ) weight=1; /* force equal weights */
! 9605: setpixel(weights,irow,icol,min2(255,weight)); /*store weight in matrix*/
! 9606: } /* --- end-of-for(irow,icol) --- */
! 9607: end_of_job:
! 9608: return ( weights ); /* back with weights or NULL=error */
! 9609: } /* --- end-of-function aaweights() --- */
! 9610:
! 9611:
! 9612: /* ==========================================================================
! 9613: * Function: aawtpixel ( image, ipixel, weights, rotate )
! 9614: * Purpose: Applies matrix of weights to the pixels
! 9615: * surrounding ipixel in image, rotated clockwise
! 9616: * by rotate degrees (typically 0 or 30).
! 9617: * --------------------------------------------------------------------------
! 9618: * Arguments: image (I) raster * to bitmap (though it can be bytemap)
! 9619: * containing image with pixels to be averaged.
! 9620: * ipixel (I) int containing index (irow*width+icol) of
! 9621: * center pixel of image for weighted average.
! 9622: * weights (I) raster * to bytemap of relative weights
! 9623: * (0-255), whose dimensions (usually odd width
! 9624: * and odd height) determine the "subgrid" of
! 9625: * image surrounding ipixel to be averaged.
! 9626: * rotate (I) int containing degrees clockwise rotation
! 9627: * (typically 0 or 30), i.e., imagine weights
! 9628: * rotated clockwise and then averaging the
! 9629: * image pixels "underneath" it now.
! 9630: * --------------------------------------------------------------------------
! 9631: * Returns: ( int ) 0-255 weighted average, or -1 for any error
! 9632: * --------------------------------------------------------------------------
! 9633: * Notes: o The rotation matrix used (when requested) is
! 9634: * / x' \ / cos(theta) sin(theta)/a \ / x \
! 9635: * | | = | | | |
! 9636: * \ y' / \ -a*sin(theta) cos(theta) / \ y /
! 9637: * where a=1 (current default) is the pixel (not screen)
! 9638: * aspect ratio width:height, and theta is rotate (converted
! 9639: * from degrees to radians). Then x=col,y=row are the integer
! 9640: * pixel coords relative to the input center ipixel, and
! 9641: * x',y' are rotated coords which aren't necessarily integer.
! 9642: * The actual pixel used is the one nearest x',y'.
! 9643: * ======================================================================= */
! 9644: /* --- entry point --- */
! 9645: int aawtpixel ( raster *image, int ipixel, raster *weights, int rotate )
! 9646: {
! 9647: /* -------------------------------------------------------------------------
! 9648: Allocations and Declarations
! 9649: -------------------------------------------------------------------------- */
! 9650: int aaimgval = 0, /* weighted avg returned to caller */
! 9651: totwts=0, sumwts=0; /* total of all wts, sum wts used */
! 9652: int pixsz = image->pixsz, /* #bits per image pixel */
! 9653: black1=1, black8=255, /* black for 1-bit, 8-bit pixels */
! 9654: black = (pixsz==1? black1:black8), /* black value for our image */
! 9655: scalefactor = (black1+black8-black), /* only scale 1-bit images */
! 9656: iscenter = 0; /* set true if center pixel black */
! 9657: /* --- grid dimensions and indexes --- */
! 9658: int wtheight = weights->height, /* #rows in weight matrix */
! 9659: wtwidth = weights->width, /* #cols in weight matrix */
! 9660: imgheight = image->height, /* #rows in image */
! 9661: imgwidth = image->width; /* #cols in image */
! 9662: int wtrow, wtrow0 = wtheight/2, /* center row index for weights */
! 9663: wtcol, wtcol0 = wtwidth/2, /* center col index for weights */
! 9664: imgrow, imgrow0= ipixel/imgwidth, /* center row index for ipixel */
! 9665: imgcol, imgcol0= ipixel-(imgrow0*imgwidth); /*center col for ipixel*/
! 9666: /* --- rotated grid variables --- */
! 9667: static int prevrotate = 0; /* rotate from previous call */
! 9668: static double costheta = 1.0, /* cosine for previous rotate */
! 9669: sintheta = 0.0; /* and sine for previous rotate */
! 9670: double a = 1.0; /* default aspect ratio */
! 9671: /* -------------------------------------------------------------------------
! 9672: Initialization
! 9673: -------------------------------------------------------------------------- */
! 9674: /* --- refresh trig functions for rotate when it changes --- */
! 9675: if ( rotate != prevrotate ) /* need new sine/cosine */
! 9676: { costheta = cos(((double)rotate)/57.29578); /*cos of rotate in radians*/
! 9677: sintheta = sin(((double)rotate)/57.29578); /*sin of rotate in radians*/
! 9678: prevrotate = rotate; } /* save current rotate as prev */
! 9679: /* -------------------------------------------------------------------------
! 9680: Calculate aapixel as weighted average over image points around ipixel
! 9681: -------------------------------------------------------------------------- */
! 9682: for ( wtrow=0; wtrow<wtheight; wtrow++ )
! 9683: for ( wtcol=0; wtcol<wtwidth; wtcol++ )
! 9684: {
! 9685: /* --- allocations and declarations --- */
! 9686: int wt = (int)getpixel(weights,wtrow,wtcol); /* weight for irow,icol */
! 9687: int drow = wtrow - wtrow0, /* delta row offset from center */
! 9688: dcol = wtcol - wtcol0; /* delta col offset from center */
! 9689: int iscenter = 0; /* set true if center point black */
! 9690: /* --- initialization --- */
! 9691: totwts += wt; /* sum all weights */
! 9692: /* --- rotate (if requested) --- */
! 9693: if ( rotate != 0 ) /* non-zero rotation */
! 9694: {
! 9695: /* --- apply rotation matrix to (x=dcol,y=drow) --- */
! 9696: double dx=(double)dcol, dy=(double)drow, dtemp; /* need floats */
! 9697: dtemp = dx*costheta + dy*sintheta/a; /* save new dx' */
! 9698: dy = -a*dx*sintheta + dy*costheta; /* dy becomes new dy' */
! 9699: dx = dtemp; /* just for notational convenience */
! 9700: /* --- replace original (drow,dcol) with nearest rotated point --- */
! 9701: drow = (int)(dy+0.5); /* round dy for nearest row */
! 9702: dcol = (int)(dx+0.5); /* round dx for nearest col */
! 9703: } /* --- end-of-if(rotate!=0) --- */
! 9704: /* --- select image pixel to be weighted --- */
! 9705: imgrow = imgrow0 + drow; /*apply displacement to center row*/
! 9706: imgcol = imgcol0 + dcol; /*apply displacement to center col*/
! 9707: /* --- if pixel in bounds, accumulate weighted average --- */
! 9708: if ( imgrow>=0 && imgrow<imgheight ) /* row is in bounds */
! 9709: if ( imgcol>=0 && imgcol<imgwidth ) /* and col is in bounds */
! 9710: {
! 9711: /* --- accumulate weighted average --- */
! 9712: int imgval = (int)getpixel(image,imgrow,imgcol); /* image value */
! 9713: aaimgval += wt*imgval; /* weighted sum of image values */
! 9714: sumwts += wt; /* and also sum weights used */
! 9715: /* --- check if center image pixel black --- */
! 9716: if ( drow==0 && dcol==0 ) /* this is center ipixel */
! 9717: if ( imgval==black ) /* and it's black */
! 9718: iscenter = 1; /* so set black center flag true */
! 9719: } /* --- end-of-if(bounds checks ok) --- */
! 9720: } /* --- end-of-for(irow,icol) --- */
! 9721: if ( 0 && iscenter ) /* center point is black */
! 9722: aaimgval = black8; /* so force average black */
! 9723: else /* center point not black */
! 9724: aaimgval = /* 0=white ... black */
! 9725: ((totwts/2 - 1) + scalefactor*aaimgval)/totwts; /* not /sumwts; */
! 9726: /*end_of_job:*/
! 9727: return ( aaimgval );
! 9728: } /* --- end-of-function aawtpixel() --- */
! 9729: #endif /* PART3 */
! 9730:
! 9731: /* ---
! 9732: * PART1
! 9733: * ------ */
! 9734: #if !defined(PARTS) || defined(PART1)
! 9735: #ifdef DRIVER
! 9736: /* ==========================================================================
! 9737: * Function: main() driver for mimetex.c
! 9738: * Purpose: emits a mime xbitmap or gif image of a LaTeX math expression
! 9739: * entered either as
! 9740: * (1) html query string from a browser (most typical), or
! 9741: * (2) a query string from an html <form method="get">
! 9742: * whose <input name="formdata"> (mostly for demo), or
! 9743: * (3) command-line arguments (mostly to test).
! 9744: * If no input supplied, expression defaults to "f(x)=x^2",
! 9745: * treated as test (input method 3).
! 9746: * If args entered on command-line (or if no input supplied),
! 9747: * output is (usually) human-viewable ascii raster images on
! 9748: * stdout rather than the usual mime xbitmaps or gif images.
! 9749: * --------------------------------------------------------------------------
! 9750: * Command-Line Arguments:
! 9751: * When running mimeTeX from the command-line, rather than
! 9752: * from a browser, syntax is
! 9753: * ./mimetex [-d ] dump gif to stdout
! 9754: * [expression expression, e.g., x^2+y^2,
! 9755: * |-f input_file] or read expression from file
! 9756: * [-m msglevel] verbosity of debugging output
! 9757: * [-s fontsize] default fontsize, 0-5
! 9758: * -d Rather than ascii debugging output, mimeTeX dumps the
! 9759: * actual gif (or xbitmap) to stdout, e.g.,
! 9760: * ./mimetex -d x^2+y^2 > expression.gif
! 9761: * creates a gif file containing an image of x^2+y^2
! 9762: * -f Reads expression from input_file, and automatically
! 9763: * assumes -d switch. The input_file may contain the
! 9764: * expression on one line or spread out over many lines.
! 9765: * MimeTeX will concatanate all lines from input_file
! 9766: * to construct one long expression. Blanks, tabs, and
! 9767: * newlines will just be ignored.
! 9768: * -m 0-99, controls verbosity level for debugging output
! 9769: * (usually used only while testing code).
! 9770: * -s Font size, 0-5. As usual, the font size can
! 9771: * also be specified in the expression by a leading
! 9772: * preamble terminated by $, e.g., 3$f(x)=x^2 displays
! 9773: * f(x)=x^2 at font size 3. Default font size is 2.
! 9774: * --------------------------------------------------------------------------
! 9775: * Exits: 0=success, 1=some error
! 9776: * --------------------------------------------------------------------------
! 9777: * Notes: o For an executable that emits mime xbitmaps, compile as
! 9778: * cc -DXBITMAP mimetex.c -lm -o mimetex.cgi
! 9779: * or, alternatively, for an executable that emits gif images
! 9780: * cc -DGIF mimetex.c gifsave.c -lm -o mimetex.cgi
! 9781: * or for gif images with anti-aliasing
! 9782: * cc -DGIF -DAA mimetex.c gifsave.c -lm -o mimetex.cgi
! 9783: * See Notes at top of file for other compile-line -D options.
! 9784: * o Move executable to your cgi-bin directory and either
! 9785: * point your browser to it directly in the form
! 9786: * http://www.yourdomain.com/cgi-bin/mimetex.cgi?3$f(x)=x^2
! 9787: * or put a tag in your html document of the form
! 9788: * <img src="../cgi-bin/mimetex.cgi?3$f(x)=x^2"
! 9789: * border=0 align=absmiddle>
! 9790: * where f(x)=x^2 (or any other expression) will be displayed
! 9791: * either as a mime xbitmap or gif image (as per -D flag).
! 9792: * ======================================================================= */
! 9793:
! 9794: /* -------------------------------------------------------------------------
! 9795: header files and other data
! 9796: -------------------------------------------------------------------------- */
! 9797: /* --- (additional) standard headers --- */
! 9798: /* --- other data --- */
! 9799: #ifdef DUMPENVIRON
! 9800: extern char **environ; /* environment information */
! 9801: #endif
! 9802:
! 9803: /* -------------------------------------------------------------------------
! 9804: globals for gif and png callback functions
! 9805: -------------------------------------------------------------------------- */
! 9806: GLOBAL(raster,*bitmap_raster,NULL); /* use 0/1 bitmap image or */
! 9807: GLOBAL(intbyte,*colormap_raster,NULL); /* anti-aliased color indexes */
! 9808: /* --- anti-aliasing flags (needed by GetPixel() as well as main()) --- */
! 9809: #ifdef AA /* if anti-aliasing requested */
! 9810: #define ISAAVALUE 1 /* turn flag on */
! 9811: #else
! 9812: #define ISAAVALUE 0 /* else turn flag off */
! 9813: #endif
! 9814: GLOBAL(int,isaa,ISAAVALUE); /* set anti-aliasing flag */
! 9815:
! 9816: /* -------------------------------------------------------------------------
! 9817: logging data structure, and default data to be logged
! 9818: -------------------------------------------------------------------------- */
! 9819: /* --- logging data structure --- */
! 9820: #define logdata struct logdata_struct /* "typedef" for logdata_struct*/
! 9821: logdata
! 9822: {
! 9823: /* -----------------------------------------------------------------------
! 9824: environment variable name, max #chars to display, min msglevel to display
! 9825: ------------------------------------------------------------------------ */
! 9826: char *name; /* environment variable name */
! 9827: int maxlen; /* max #chars to display */
! 9828: int msglevel; /* min msglevel to display data */
! 9829: } ; /* --- end-of-logdata_struct --- */
! 9830: /* --- data logged by mimeTeX --- */
! 9831: STATIC logdata mimelog[]
! 9832: #ifdef INITVALS
! 9833: =
! 9834: {
! 9835: /* ------ variable ------ maxlen msglevel ----- */
! 9836: { "QUERY_STRING", 999, 4 },
! 9837: { "REMOTE_ADDR", 999, 3 },
! 9838: { "HTTP_REFERER", 999, 3 },
! 9839: { "REQUEST_URI", 999, 5 },
! 9840: { "HTTP_USER_AGENT", 999, 3 },
! 9841: { "HTTP_X_FORWARDED_FOR", 999, 3 },
! 9842: { NULL, -1, -1 } /* trailer record */
! 9843: } /* --- end-of-mimelog[] --- */
! 9844: #endif
! 9845: ;
! 9846:
! 9847: /* -------------------------------------------------------------------------
! 9848: messages
! 9849: -------------------------------------------------------------------------- */
! 9850: static char *copyright = /* copyright, gnu/gpl notice */
! 9851: "+-----------------------------------------------------------------------+\n"
! 9852: "|mimeTeX vers 1.61, Copyright(c) 2002-2005, John Forkosh Associates, Inc|\n"
! 9853: "+-----------------------------------------------------------------------+\n"
! 9854: "| mimeTeX is free software, licensed to you under terms of the GNU/GPL, |\n"
! 9855: "| and comes with absolutely no warranty whatsoever. |\n"
! 9856: "+-----------------------------------------------------------------------+";
! 9857: static int maxmsgnum = 2; /* maximum msgtable[] index */
! 9858: static char *msgtable[] = { /* messages referenced by [index] */
! 9859: "\\red\\small\\rm\\fbox{\\array{" /* [0] is invalid_referer_msg */
! 9860: "Please~read~www.forkosh.com/mimetex.html\\\\and~install~mimetex.cgi~"
! 9861: "on~your~own~server.\\\\Thank~you,~John~Forkosh}}",
! 9862: "\\red\\small\\rm\\fbox{\\array{" /* [1] */
! 9863: "Please~provide~your~{\\tiny~HTTP-REFERER}~to~access~the~public\\\\"
! 9864: "mimetex~server.~~Or~please~read~~www.forkosh.com/mimetex.html\\\\"
! 9865: "and~install~mimetex.cgi~on~your~own~server.~~Thank~you,~John~Forkosh}}",
! 9866: "\\red\\small\\rm\\fbox{\\array{" /* [2] */
! 9867: "The~public~mimetex~server~is~for~testing.~~For~production,\\\\"
! 9868: "please~read~~www.forkosh.com/mimetex.html~~and~install\\\\"
! 9869: "mimetex.cgi~on~your~own~server.~~Thank~you,~John~Forkosh}}",
! 9870: NULL } ; /* trailer */
! 9871:
! 9872:
! 9873: /* --- entry point --- */
! 9874: int main ( int argc, char *argv[]
! 9875: #ifdef DUMPENVP
! 9876: , char *envp[]
! 9877: #endif
! 9878: )
! 9879: {
! 9880: /* -------------------------------------------------------------------------
! 9881: Allocations and Declarations
! 9882: -------------------------------------------------------------------------- */
! 9883: /* --- expression to be emitted --- */
! 9884: static char exprbuffer[16385] = "f(x)=x^2"; /* expression to be processed */
! 9885: char *expression = exprbuffer; /* ptr to expression */
! 9886: int size = NORMALSIZE; /* default font size */
! 9887: char *query = getenv("QUERY_STRING"); /* getenv("QUERY_STRING") result */
! 9888: char *mimeprep(); /* preprocess expression */
! 9889: int unescape_url(); /* convert %xx's to ascii chars */
! 9890: int emitcache(); /* emit cached image if it exists */
! 9891: int isquery = 0, /* true if input from QUERY_STRING */
! 9892: isqempty = 0, /* true if query string empty */
! 9893: isqlogging = 0, /* true if logging in query mode */
! 9894: isformdata = 0, /* true if input from html form */
! 9895: isdumpimage = 0; /* true to dump image on stdout */
! 9896: /* --- rasterization --- */
! 9897: subraster *rasterize(), *sp; /* rasterize expression */
! 9898: raster *border_raster(), *bp; /* put a border around raster */
! 9899: int type_raster(), type_bytemap(), /* screen dump function prototypes */
! 9900: xbitmap_raster(); /* mime xbitmap output function */
! 9901: /* --- http_referer --- */
! 9902: char *referer = REFERER; /* http_referer must contain this */
! 9903: struct { char *referer; int msgnum; } /* http_referer can't contain this */
! 9904: denyreferer[] = { /* referer table to deny access to */
! 9905: #ifdef DENYREFERER
! 9906: #include DENYREFERER /* e.g., {"",1}, for no referer */
! 9907: #endif
! 9908: { NULL, -999 } }; /* trailer */
! 9909: char *http_referer = getenv("HTTP_REFERER"); /* referer using mimeTeX */
! 9910: int ishttpreferer = (http_referer==NULL?0:(*http_referer=='\000'?0:1));
! 9911: int isstrstr(); /* search http_referer for referer */
! 9912: int isinvalidreferer = 0; /* true for inavlid referer */
! 9913: int norefmaxlen = NOREFMAXLEN; /*max query_string len if no referer*/
! 9914: /* --- gif --- */
! 9915: #if defined(GIF)
! 9916: int GetPixel(); /* feed pixels to gifsave library */
! 9917: int GIF_Create(),GIF_CompressImage(),GIF_Close(); /* prototypes for... */
! 9918: void GIF_SetColor(),GIF_SetTransparent(); /* ...gifsave enntry points */
! 9919: #endif
! 9920: char *gif_outfile = (char *)NULL, /* gif output defaults to stdout */
! 9921: cachefile[256] = "\000", /* full path and name to cache file*/
! 9922: *md5str(); /* md5 has of expression */
! 9923: int maxage = 7200; /* max-age is two hours */
! 9924: /* --- anti-aliasing --- */
! 9925: intbyte *bytemap_raster = NULL, /* anti-aliased bitmap */
! 9926: colors[256]; /* grayscale vals in bytemap */
! 9927: int aalowpass(), aapnm(), /*lowpass filters for anti-aliasing*/
! 9928: grayscale = 256; /* 0-255 grayscales in 8-bit bytes */
! 9929: int ncolors=2, /* #colors (2=b&w) */
! 9930: aacolormap(); /* build colormap from bytemap */
! 9931: /* --- messages --- */
! 9932: char logfile[256] = LOGFILE, /*log queries if msglevel>=LOGLEVEL*/
! 9933: cachelog[256] = CACHELOG; /* cached image log in cachepath/ */
! 9934: char *timestamp(); /* time stamp for logged messages */
! 9935: int logger(); /* logs environ variables */
! 9936: int ismonth(); /* check argv[0] for current month */
! 9937: char *progname = (argc>0?argv[0]:"noname"); /* name program executed as */
! 9938: char *dashes = /* separates logfile entries */
! 9939: "--------------------------------------------------------------------------";
! 9940: char *invalid_referer_msg = msgtable[0]; /* msg to invalid http_referer */
! 9941: /* -------------------------------------------------------------------------
! 9942: initialization
! 9943: -------------------------------------------------------------------------- */
! 9944: /* --- run optional system command string --- */
! 9945: #ifdef SYSTEM
! 9946: system(SYSTEM);
! 9947: #endif
! 9948: /* --- set global variables --- */
! 9949: msgfp = stdout; /* for comamnd-line mode output */
! 9950: isss = issupersampling; /* set supersampling flag */
! 9951: shrinkfactor = shrinkfactors[NORMALSIZE]; /* set shrinkfactor */
! 9952: /* ---
! 9953: * check QUERY_STRING query for expression overriding command-line arg
! 9954: * ------------------------------------------------------------------- */
! 9955: if ( query != NULL ) /* check query string from environ */
! 9956: if ( strlen(query) >= 1 ) /* caller gave us a query string */
! 9957: { strncpy(expression,query,16384); /* so use it as expression */
! 9958: expression[16384] = '\000'; /* make sure it's null terminated */
! 9959: isquery = 1; } /* and set isquery flag */
! 9960: if ( !isquery ) /* empty query string */
! 9961: { char *host = getenv("HTTP_HOST"), /* additional getenv("") results */
! 9962: *name = getenv("SERVER_NAME"), *addr = getenv("SERVER_ADDR");
! 9963: if ( host!=NULL || name!=NULL || addr!=NULL ) /* assume http query */
! 9964: { isquery = 1; /* set flag to signal query */
! 9965: strcpy(expression,"\\red\\small\\rm~missing~query~string"); }
! 9966: isqempty = 1; /* signal empty query string */
! 9967: } /* --- end-of-if(!isquery) --- */
! 9968: /* ---
! 9969: * process command-line input args (if not a query)
! 9970: * ------------------------------------------------ */
! 9971: if ( !isquery /* don't have an html query string */
! 9972: || ( /*isqempty &&*/ argc>1) ) /* or have command-line args */
! 9973: {
! 9974: char *argsignal = ARGSIGNAL, /* signals start of mimeTeX args */
! 9975: stopsignal[32] = "--"; /* default Unix end-of-args signal */
! 9976: int iarg=0, argnum=0, /*argv[] index for command-line args*/
! 9977: exprarg = 0, /* argv[] index for expression */
! 9978: infilearg = 0, /* argv[] index for infile */
! 9979: nswitches = 0, /* number of -switches */
! 9980: isstopsignal = 0, /* true after stopsignal found */
! 9981: isstrict = 1/*iswindows*/, /* true for strict arg checking */
! 9982: /*nb, windows has apache "x -3" bug*/
! 9983: nargs=0, nbadargs=0, /* number of arguments, bad ones */
! 9984: maxbadargs = (isstrict?0:1), /*assume query if too many bad args*/
! 9985: isgoodargs = 0; /* true to accept command-line args*/
! 9986: if ( argsignal != NULL ) /* if compiled with -DARGSIGNAL */
! 9987: while ( argc > ++iarg ) /* check each argv[] for argsignal */
! 9988: if ( !strcmp(argv[iarg],argsignal) ) /* check for exact match */
! 9989: { argnum = iarg; /* got it, start parsing next arg */
! 9990: break; } /* stop looking for argsignal */
! 9991: while ( argc > ++argnum ) /* check for switches and values, */
! 9992: {
! 9993: nargs++; /* count another command-line arg */
! 9994: if ( strcmp(argv[argnum],stopsignal) == 0 ) /* found stopsignal */
! 9995: { isstopsignal = 1; /* so set stopsignal flag */
! 9996: continue; } /* and get expression after it */
! 9997: if ( !isstopsignal /* haven't seen stopsignal switch */
! 9998: && *argv[argnum] == '-' ) /* and have some '-' switch */
! 9999: {
! 10000: char flag = tolower(*(argv[argnum]+1)); /* single char following '-' */
! 10001: int arglen = strlen(argv[argnum]) - 1; /* #chars following - */
! 10002: argnum++; /* arg following flag/switch is usually its value */
! 10003: nswitches++; /* another switch on command line */
! 10004: if ( isstrict && arglen!=1 ) /* only single-char switch allowed */
! 10005: { nbadargs++; argnum--; } /* so ignore longer -xxx switch */
! 10006: else /* process single-char -x switch */
! 10007: switch ( flag ) { /* see what user wants to tell us */
! 10008: /* --- ignore uninterpreted flag --- */
! 10009: default: nbadargs++; argnum--; break;
! 10010: /* --- adjustable program parameters (not checking input) --- */
! 10011: case 'd': isdumpimage++; argnum--; break;
! 10012: case 'e': isdumpimage++; gif_outfile=argv[argnum]; break;
! 10013: case 'f': isdumpimage++; infilearg=argnum; break;
! 10014: case 'm': msglevel = atoi(argv[argnum]); break;
! 10015: case 'o': istransparent = 0; argnum--; break;
! 10016: case 's': size = atoi(argv[argnum]); break;
! 10017: } /* --- end-of-switch(flag) --- */
! 10018: } /* --- end-of-if(*argv[argnum]=='-') --- */
! 10019: else /* expression if arg not a -flag */
! 10020: if ( infilearg == 0 ) /* no infile arg yet */
! 10021: { if ( exprarg != 0 ) nbadargs++; /* 2nd expression invalid */
! 10022: exprarg = argnum; /* but take last expression */
! 10023: /*infilearg = (-1);*/ } /* and set infilearg */
! 10024: else nbadargs++; /* infile and expression invalid */
! 10025: } /* --- end-of-while(argc>++argnum) --- */
! 10026: if ( msglevel>=999 && msgfp!=NULL ) /* display command-line info */
! 10027: fprintf(msgfp,"argc=%d, progname=%s, #args=%d, #badargs=%d\n",
! 10028: argc,progname,nargs,nbadargs);
! 10029: /* ---
! 10030: * decide whether command-line input overrides query_string
! 10031: * -------------------------------------------------------- */
! 10032: if ( isdumpimage > 2 ) nbadargs++; /* duplicate/conflicting -switch */
! 10033: isgoodargs = ( !isstrict /*good if not doing strict checking*/
! 10034: || !isquery /* or if no query, must use args */
! 10035: || (nbadargs<nargs && nbadargs<=maxbadargs) ); /* bad args imply query */
! 10036: /* ---
! 10037: * take expression from command-line args
! 10038: * -------------------------------------- */
! 10039: if ( isgoodargs && exprarg > 0 /* good expression on command line */
! 10040: && infilearg <= 0 ) /* and not given in input file */
! 10041: if ( !isquery /* no conflict if no query_string */
! 10042: || nswitches > 0 ) /* explicit -switch(es) also given */
! 10043: { strncpy(expression,argv[exprarg],16384); /*expression from command-line*/
! 10044: expression[16384] = '\000'; /* make sure it's null terminated */
! 10045: isquery = 0; } /* and not from a query_string */
! 10046: /* ---
! 10047: * or read expression from input file
! 10048: * ---------------------------------- */
! 10049: if ( isgoodargs && infilearg > 0 ) /* have a good -f arg */
! 10050: {
! 10051: FILE *infile = fopen(argv[infilearg],"r"); /* open input file for read */
! 10052: if ( infile != (FILE *)NULL ) /* opened input file successfully */
! 10053: { char instring[2049]; /* line from file */
! 10054: isquery = 0; /* file input, not a query_string */
! 10055: *expression = '\000'; /* start expresion as empty string */
! 10056: while ( fgets(instring,2048,infile) != (char *)NULL ) /* read till eof*/
! 10057: strcat(expression,instring); /* concat line to end of expression*/
! 10058: fclose ( infile ); } /*close input file after reading expression*/
! 10059: } /* --- end-of-if(infilearg>0) --- */
! 10060: } /* --- end-of-if(!isquery) --- */
! 10061: /* ---
! 10062: * check for <form> input
! 10063: * ---------------------- */
! 10064: if ( isquery ) /* must be <form method="get"> */
! 10065: if ( !memcmp(expression,"formdata",8) ) /*must be <input name="formdata"> */
! 10066: { char *delim=strchr(expression,'='); /* find equal following formdata */
! 10067: if ( delim != (char *)NULL ) /* found unescaped equal sign */
! 10068: strcpy(expression,delim+1); /* so shift name= out of expression*/
! 10069: while ( (delim=strchr(expression,'+')) != NULL ) /*unescaped plus sign*/
! 10070: *delim = ' '; /* is "shorthand" for blank space */
! 10071: /*unescape_url(expression,1);*/ /* convert unescaped %xx's to chars */
! 10072: unescape_url(expression,0); /* convert all %xx's to chars */
! 10073: unescape_url(expression,0); /* repeat */
! 10074: msglevel = FORMLEVEL; /* msglevel for forms */
! 10075: isformdata = 1; } /* set flag to signal form data */
! 10076: else /* --- query, but not <form> input --- */
! 10077: unescape_url(expression,0); /* convert _all_ %xx's to chars */
! 10078: /* ---
! 10079: * check queries for embedded prefixes signalling special processing
! 10080: * ----------------------------------------------------------------- */
! 10081: if ( isquery ) /* only check queries */
! 10082: {
! 10083: /* --- check for msglevel=###$ prefix --- */
! 10084: if ( !memcmp(expression,"msglevel=",9) ) /* query has msglevel prefix */
! 10085: { char *delim=strchr(expression,'$'); /* find $ delim following msglevel*/
! 10086: if ( delim != (char *)NULL ) /* check that we found delim */
! 10087: { *delim = '\000'; /* replace delim with null */
! 10088: if ( seclevel <= 9 ) /* permit msglevel specification */
! 10089: msglevel = atoi(expression+9); /* interpret ### in msglevel###$ */
! 10090: strcpy(expression,delim+1); } } /* shift out prefix and delim */
! 10091: /* --- next check for logfile=xxx$ prefix (must follow msglevel) --- */
! 10092: if ( !memcmp(expression,"logfile=",8) ) /* query has logfile= prefix */
! 10093: { char *delim=strchr(expression,'$'); /* find $ delim following logfile=*/
! 10094: if ( delim != (char *)NULL ) /* check that we found delim */
! 10095: { *delim = '\000'; /* replace delim with null */
! 10096: if ( seclevel <= 3 ) /* permit logfile specification */
! 10097: strcpy(logfile,expression+8); /* interpret xxx in logfile=xxx$ */
! 10098: strcpy(expression,delim+1); } } /* shift out prefix and delim */
! 10099: } /* --- end-of-if(isquery) --- */
! 10100: /* ---
! 10101: * log query (e.g., for debugging)
! 10102: * ------------------------------- */
! 10103: if ( isquery ) /* only log query_string's */
! 10104: if ( msglevel >= LOGLEVEL /* check if logging */
! 10105: && seclevel <= 5 ) /* and if logging permitted */
! 10106: if ( logfile != NULL ) /* if a logfile is given */
! 10107: if ( *logfile != '\000' ) /*and if it's not an empty string*/
! 10108: if ( (msgfp=fopen(logfile,"a")) /* open logfile for append */
! 10109: != NULL ) /* ignore logging if can't open */
! 10110: {
! 10111: /* --- default logging --- */
! 10112: logger(msgfp,msglevel,expression,mimelog); /* log query */
! 10113: /* --- additional debug logging (argv and environment) --- */
! 10114: if ( msglevel >= 9 ) /* log environment */
! 10115: { int i; /*char name[999],*value;*/
! 10116: fprintf(msgfp,"Command-line arguments...\n");
! 10117: if ( argc < 1 ) /* no command-line args */
! 10118: fprintf(msgfp," ...argc=%d, no argv[] variables\n",argc);
! 10119: else
! 10120: for ( i=0; i<argc; i++ ) /* display all argv[]'s */
! 10121: fprintf(msgfp," argv[%d] = \"%s\"\n",i,argv[i]);
! 10122: #ifdef DUMPENVP /* char *envp[] available for dump */
! 10123: fprintf(msgfp,"Environment variables (using envp[])...\n");
! 10124: if ( envp == (char **)NULL ) /* envp not provided */
! 10125: fprintf(msgfp," ...envp[] environment variables not available\n");
! 10126: else
! 10127: for ( i=0; ; i++ ) /* display all envp[]'s */
! 10128: if ( envp[i] == (char *)NULL ) break;
! 10129: else fprintf(msgfp," envp[%d] = \"%s\"\n",i,envp[i]);
! 10130: #endif /* --- DUMPENVP ---*/
! 10131: #ifdef DUMPENVIRON /* skip what should be redundant output */
! 10132: fprintf(msgfp,"Environment variables (using environ)...\n");
! 10133: if ( environ == (char **)NULL ) /* environ not provided */
! 10134: fprintf(msgfp," ...extern environ variables not available\n");
! 10135: else
! 10136: for ( i=0; ; i++ ) /*display environ[] and getenv()'s*/
! 10137: if ( environ[i] == (char *)NULL ) break;
! 10138: else {
! 10139: strcpy(name,environ[i]); /* set up name for getenv() arg */
! 10140: if ( (value=strchr(name,'=')) != NULL ) /* = delimits name */
! 10141: { *value = '\000'; /* got it, so null-terminate name */
! 10142: value = getenv(name); } /* and look up name using getenv() */
! 10143: else strcpy(name,"NULL"); /* missing = delim in environ[i] */
! 10144: fprintf(msgfp,"environ[%d]: \"%s\"\n\tgetenv(%s) = \"%s\"\n",
! 10145: i,environ[i],name,(value==NULL?"NULL":value));
! 10146: } /* --- end-of-if/else --- */
! 10147: #endif /* --- DUMPENVIRON ---*/
! 10148: } /* --- end-of-if(msglevel>=9) --- */
! 10149: /* --- close log file if no longer needed --- */
! 10150: if ( msglevel < DBGLEVEL ) /* logging, but not debugging */
! 10151: { fprintf(msgfp,"%s\n",dashes); /* so log separator line, */
! 10152: fclose(msgfp); /* close logfile immediately, */
! 10153: msgfp = NULL; } /* and reset msgfp pointer */
! 10154: else
! 10155: isqlogging = 1; /* set query logging flag */
! 10156: } /* --- end-of-if(msglevel>=LOGLEVEL) --- */
! 10157: else /* couldn't open logfile */
! 10158: msglevel = 0; /* can't emit messages */
! 10159: /* ---
! 10160: * prepend prefix to submitted expression
! 10161: * -------------------------------------- */
! 10162: if ( 1 || isquery ) /* queries or command-line */
! 10163: if ( *exprprefix != '\000' ) /* we have a prefix string */
! 10164: { int npref = strlen(exprprefix); /* #chars in prefix */
! 10165: memmove(expression+npref+1,expression,strlen(expression)+1); /*make room*/
! 10166: memcpy(expression,exprprefix,npref); /* copy prefix into expression */
! 10167: expression[npref] = '{'; /* followed by { */
! 10168: strcat(expression,"}"); } /* and terminating } to balance { */
! 10169: /* ---
! 10170: * check if http_referer is allowed to use this image
! 10171: * -------------------------------------------------- */
! 10172: if ( isquery ) /* not relevant if "interactive" */
! 10173: if ( referer != NULL ) /* nor if compiled w/o -DREFERER= */
! 10174: if ( strcmp(referer,"month") != 0 ) /* nor if it's *only* "month" */
! 10175: if ( http_referer != NULL ) /* nor if called "standalone" */
! 10176: if ( !isstrstr(http_referer,referer,0) ) /* invalid http_referer */
! 10177: { expression = invalid_referer_msg; /* so give user error message */
! 10178: isinvalidreferer = 1; } /* and signal invalid referer */
! 10179: /* ---
! 10180: * check if referer contains "month" signal
! 10181: * ---------------------------------------- */
! 10182: if ( isquery ) /* not relevant if "interactive" */
! 10183: if ( referer != NULL ) /* nor if compiled w/o -DREFERER= */
! 10184: if ( !isinvalidreferer ) /* nor if already invalid referer */
! 10185: if ( strstr(referer,"month") != NULL ) /* month check requested */
! 10186: if ( !ismonth(progname) ) /* not executed as mimetexJan-Dec */
! 10187: { expression = invalid_referer_msg; /* so give user error message */
! 10188: isinvalidreferer = 1; } /* and signal invalid referer */
! 10189: /* ---
! 10190: * check if http_referer is to be denied access
! 10191: * -------------------------------------------- */
! 10192: if ( isquery ) /* not relevant if "interactive" */
! 10193: if ( !isinvalidreferer ) /* nor if already invalid referer */
! 10194: { int iref=0, msgnum=(-999); /* denyreferer index, message# */
! 10195: for ( iref=0; msgnum<0; iref++ ) { /* run through denyreferer[] table */
! 10196: char *deny = denyreferer[iref].referer; /* referer to be denied */
! 10197: if ( deny == NULL ) break; /* null signals end-of-table */
! 10198: if ( msglevel>=999 && msgfp!=NULL ) /* debugging */
! 10199: {fprintf(msgfp,"main> invalid iref=%d: deny=%s http_referer=%s\n",
! 10200: iref,deny,(http_referer==NULL?"null":http_referer)); fflush(msgfp);}
! 10201: if ( *deny == '\000' ) /* signal to check for no referer */
! 10202: { if ( http_referer == NULL ) /* http_referer not supplied */
! 10203: msgnum = denyreferer[iref].msgnum; } /* so set message# */
! 10204: else /* have referer to check for */
! 10205: if ( http_referer != NULL ) /* and have referer to be checked */
! 10206: if ( isstrstr(http_referer,deny,0) ) /* invalid http_referer */
! 10207: msgnum = denyreferer[iref].msgnum; /* so set message# */
! 10208: } /* --- end-of-for(iref) --- */
! 10209: if ( msgnum >= 0 ) /* deny access to this referer */
! 10210: { if ( msgnum > maxmsgnum ) msgnum = 0; /* keep index within bounds */
! 10211: expression = msgtable[msgnum]; /* set user error message */
! 10212: isinvalidreferer = 1; } /* and signal invalid referer */
! 10213: } /* --- end-of-if(!isinvalidreferer) --- */
! 10214: /* --- also check maximum query_string length if no http_referer given --- */
! 10215: if ( isquery ) /* not relevant if "interactive" */
! 10216: if ( !isinvalidreferer ) /* nor if already invalid referer */
! 10217: if ( !ishttpreferer ) /* no http_referer supplied */
! 10218: if ( strlen(expression) > norefmaxlen ) /* query_string too long */
! 10219: { expression = invalid_referer_msg; /* set invalid http_referer message*/
! 10220: isinvalidreferer = 1; } /* and signal invalid referer */
! 10221: /* ---
! 10222: * check for image caching
! 10223: * ----------------------- */
! 10224: if ( strstr(expression,"\\counter") != NULL /* can't cache \counter{} */
! 10225: || strstr(expression,"\\input") != NULL /* can't cache \input{} */
! 10226: || strstr(expression,"\\nocach") != NULL /* no caching requested */
! 10227: ) { iscaching = 0; /* so turn caching off */
! 10228: maxage = 2; } /* and set max-age to two seconds */
! 10229: if ( isquery ) /* don't cache command-line images */
! 10230: if ( iscaching ) /* image caching enabled */
! 10231: {
! 10232: /* --- set up path to cached image file --- */
! 10233: char *md5hash = md5str(expression); /* md5 hash of expression */
! 10234: if ( md5hash == NULL ) /* failed for some reason */
! 10235: iscaching = 0; /* so turn off caching */
! 10236: else
! 10237: {
! 10238: strcpy(cachefile,cachepath); /* start with (relative) path */
! 10239: strcat(cachefile,md5hash); /* add md5 hash of expression */
! 10240: strcat(cachefile,".gif"); /* finish with .gif extension */
! 10241: gif_outfile = cachefile; /* signal GIF_Create() to cache */
! 10242: /* --- (always) emit mime content-type line --- */
! 10243: fprintf( stdout, "Cache-Control: max-age=%d\n",maxage );
! 10244: fprintf( stdout, "Content-type: image/gif\n\n" );
! 10245: /* --- emit cached image if it already exists --- */
! 10246: if ( emitcache(cachefile) > 0 ) /* cached image emitted */
! 10247: goto end_of_job; /* so nothing else to do */
! 10248: /* --- log caching request --- */
! 10249: if ( msglevel >= 1 /* check if logging */
! 10250: /*&& seclevel <= 5*/ ) /* and if logging permitted */
! 10251: if ( cachelog != NULL ) /* if a logfile is given */
! 10252: if ( *cachelog != '\000' ) /*and if it's not an empty string*/
! 10253: { char filename[256]; /* construct cachepath/cachelog */
! 10254: FILE *filefp=NULL; /* fopen(filename) */
! 10255: strcpy(filename,cachepath); /* start with (relative) path */
! 10256: strcat(filename,cachelog); /* add cache log filename */
! 10257: if ( (filefp=fopen(filename,"a")) /* open cache logfile for append */
! 10258: != NULL ) /* ignore logging if can't open */
! 10259: { int isreflogged = 0; /* set true if http_referer logged */
! 10260: fprintf(filefp,"%s %s\n", /* timestamp, md5 file */
! 10261: timestamp(),cachefile+strlen(cachepath)); /* (path not shown) */
! 10262: fprintf(filefp,"%s\n",expression); /* expression in filename */
! 10263: if ( http_referer != NULL ) /* show referer if we have one */
! 10264: if ( *http_referer != '\000' ) /* and if not an empty string*/
! 10265: { int loglen = strlen(dashes); /* #chars on line in log file*/
! 10266: char *refp = http_referer; /* line to be printed */
! 10267: isreflogged = 1; /* signal http_referer logged*/
! 10268: while ( 1 ) { /* printed in parts if needed*/
! 10269: fprintf(filefp,"%.*s\n",loglen,refp); /* print a part */
! 10270: if ( strlen(refp) <= loglen ) break; /* no more parts */
! 10271: refp += loglen; } } /* bump ptr to next part */
! 10272: if ( !isreflogged ) /* http_referer not logged */
! 10273: fprintf(filefp,"http://none\n"); /* so log dummy referer line */
! 10274: fprintf(filefp,"%s\n",dashes); /* separator line */
! 10275: fclose(filefp); } /* close logfile immediately */
! 10276: } /* --- end-of-if(cachelog!=NULL) --- */
! 10277: } /* --- end-of-if/else(md5hash==NULL) --- */
! 10278: } /* --- end-of-if(iscaching) --- */
! 10279: /* ---
! 10280: * emit copyright, gnu/gpl notice (if "interactive")
! 10281: * ------------------------------------------------- */
! 10282: if ( !isdumpimage ) /* don't mix ascii with image dump */
! 10283: if ( (!isquery||isqlogging) && msgfp!=NULL ) /* called from command line */
! 10284: fprintf(msgfp,"%s\n",copyright); /* display copyright, gnu/gpl info */
! 10285: /* -------------------------------------------------------------------------
! 10286: rasterize expression and put a border around it
! 10287: -------------------------------------------------------------------------- */
! 10288: /* --- preprocess expression, converting LaTeX constructs for mimeTeX --- */
! 10289: expression = mimeprep(expression); /* preprocess expression */
! 10290: /* --- double-check that we actually have an expression to rasterize --- */
! 10291: if ( expression == NULL ) /* nothing to rasterize */
! 10292: { if ( (!isquery||isqlogging) && msgfp!=NULL ) /*emit error if not a query*/
! 10293: fprintf(msgfp,"No expression to rasterize\n");
! 10294: goto end_of_job; } /* and then quit */
! 10295: /* --- rasterize expression --- */
! 10296: if ( (sp = rasterize(expression,size)) == NULL ) /* failed to rasterize */
! 10297: { if ( (!isquery||isqlogging) && msgfp!=NULL ) /*emit error if not a query*/
! 10298: fprintf(msgfp,"Failed to rasterize %s\n",expression);
! 10299: if ( isquery ) sp = rasterize( /* or emit error raster if query */
! 10300: "\\red\\rm~\\fbox{mimeTeX~failed~to~render\\\\your~expression}",1);
! 10301: if ( sp == NULL ) goto end_of_job; } /* re-check for failure */
! 10302: /* ---no border requested, but this adjusts width to multiple of 8 bits--- */
! 10303: if ( issupersampling ) /* no border needed for gifs */
! 10304: bp = sp->image; /* so just extract pixel map */
! 10305: else /* for mime xbitmaps must have... */
! 10306: bp = border_raster(sp->image,0,0,0,1); /* image width multiple of 8 bits */
! 10307: sp->image = bitmap_raster = bp; /* global copy for gif,png output */
! 10308: /* -------------------------------------------------------------------------
! 10309: generate anti-aliased bytemap from (bordered) bitmap
! 10310: -------------------------------------------------------------------------- */
! 10311: if ( isaa ) /* we want anti-aliased bitmap */
! 10312: {
! 10313: /* ---
! 10314: * allocate bytemap and colormap as per width*height of bitmap
! 10315: * ----------------------------------------------------------- */
! 10316: int nbytes = (bp->width)*(bp->height); /*#bytes needed in byte,colormap*/
! 10317: if ( isss ) /* anti-aliasing by supersampling */
! 10318: bytemap_raster = (intbyte *)(bitmap_raster->pixmap); /*bytemap in raster*/
! 10319: else /* need to allocate bytemap */
! 10320: if ( aaalgorithm == 0 ) /* anti-aliasing not wanted */
! 10321: isaa = 0; /* so signal no anti-aliasing */
! 10322: else /* anti-aliasing wanted */
! 10323: if ( (bytemap_raster = (intbyte *)malloc(nbytes)) /* malloc bytemap */
! 10324: == NULL ) isaa = 0; /* reset flag if malloc failed */
! 10325: if ( isaa ) /* have bytemap, so... */
! 10326: if ( (colormap_raster = (intbyte *)malloc(nbytes)) /* malloc colormap */
! 10327: == NULL ) isaa = 0; /* reset flag if malloc failed */
! 10328: /* ---
! 10329: * now generate anti-aliased bytemap and colormap from bitmap
! 10330: * ---------------------------------------------------------- */
! 10331: if ( isaa ) /*re-check that we're anti-aliasing*/
! 10332: {
! 10333: /* ---
! 10334: * select anti-aliasing algorithm
! 10335: * ------------------------------ */
! 10336: if ( !isss ) /* generate bytemap for lowpass */
! 10337: if ( aaalgorithm == 1 ) /* 1 for aalowpass() */
! 10338: { if ( aalowpass(bp,bytemap_raster,grayscale) /* my lowpass filter */
! 10339: == 0 ) isaa = 0; } /*failed, so turn off anti-aliasing*/
! 10340: else /* or 2 for aapnm() */
! 10341: if ( aaalgorithm == 2 ) /*2 for netpbm pnmalias.c algorithm*/
! 10342: { if ( aapnm(bp,bytemap_raster,grayscale) /* pnmalias.c filter */
! 10343: == 0 ) isaa = 0; } /*failed, so turn off anti-aliasing*/
! 10344: else isaa = 0; /* unrecognized algorithm */
! 10345: /* ---
! 10346: * finally, generate colors and colormap
! 10347: * ------------------------------------- */
! 10348: if ( isaa ) { /* we have bytemap_raster */
! 10349: ncolors = aacolormap(bytemap_raster,nbytes,colors,colormap_raster);
! 10350: if ( ncolors < 2 ) /* failed */
! 10351: { isaa = 0; /* so turn off anti-aliasing */
! 10352: ncolors = 2; } /* and reset for black&white */
! 10353: } /* --- end-of-if(isaa) --- */
! 10354: } /* --- end-of-if(isaa) --- */
! 10355: } /* --- end-of-if(isaa) --- */
! 10356: /* -------------------------------------------------------------------------
! 10357: display results on msgfp if called from command line (usually for testing)
! 10358: -------------------------------------------------------------------------- */
! 10359: if ( (!isquery||isqlogging) || msglevel >= 99 ) /*command line or debuging*/
! 10360: if ( !isdumpimage ) /* don't mix ascii with image dump */
! 10361: {
! 10362: /* ---
! 10363: * display ascii image of rasterize()'s rasterized bitmap
! 10364: * ------------------------------------------------------ */
! 10365: if ( !isss ) /* no bitmap for supersampling */
! 10366: { fprintf(msgfp,"\nAscii dump of bitmap image...\n");
! 10367: type_raster(bp,msgfp); } /* emit ascii image of raster */
! 10368: /* ---
! 10369: * display anti-aliasing results applied to rasterized bitmap
! 10370: * ---------------------------------------------------------- */
! 10371: if ( isaa ) /* if anti-aliasing applied */
! 10372: {
! 10373: int igray; /* colors[] index */
! 10374: /* --- anti-aliased bytemap image --- */
! 10375: if ( msgfp!=NULL && msglevel>=9 ) /* don't usually emit raw bytemap */
! 10376: { fprintf(msgfp,"\nHex dump of anti-aliased bytemap, " /*emit bytemap*/
! 10377: "asterisks denote \"black\" bytes (value=%d)...\n",grayscale-1);
! 10378: type_bytemap(bytemap_raster,grayscale,bp->width,bp->height,msgfp); }
! 10379: /* --- colormap image --- */
! 10380: fprintf(msgfp,"\nHex dump of colormap indexes, " /* emit colormap */
! 10381: "asterisks denote \"black\" bytes (index=%d)...\n",ncolors-1);
! 10382: type_bytemap(colormap_raster,ncolors,bp->width,bp->height,msgfp);
! 10383: /* --- rgb values corresponding to colormap indexes */
! 10384: fprintf(msgfp,"\nThe %d colormap indexes denote rgb values...",ncolors);
! 10385: for ( igray=0; igray<ncolors; igray++ ) /* show colors[] values */
! 10386: fprintf(msgfp,"%s%2x-->%3d", (igray%5?" ":"\n"),
! 10387: igray,(int)(colors[ncolors-1]-colors[igray]));
! 10388: fprintf(msgfp,"\n"); /* always needs a final newline */
! 10389: } /* --- end-of-if(isaa) --- */
! 10390: } /* --- end-of-if(!isquery||msglevel>=9) --- */
! 10391: /* -------------------------------------------------------------------------
! 10392: emit xbitmap or gif image, and exit
! 10393: -------------------------------------------------------------------------- */
! 10394: if ( isquery /* called from browser (usual) */
! 10395: || isdumpimage /* or to emit dump of image */
! 10396: || msglevel >= 99 ) /* or for debugging */
! 10397: {
! 10398: int igray = 0; /* grayscale index */
! 10399: #if defined(GIF) /* compiled to emit gif */
! 10400: /* ------------------------------------------------------------------------
! 10401: emit GIF image
! 10402: ------------------------------------------------------------------------- */
! 10403: /* --- emit mime content-type line --- */
! 10404: if ( !isdumpimage /* don't mix ascii with image dump */
! 10405: && !iscaching ) /* already emitted if caching */
! 10406: { fprintf( stdout, "Cache-Control: max-age=%d\n",maxage );
! 10407: /*fprintf( stdout, "Expires: Fri, 31 Oct 2003 23:59:59 GMT\n" );*/
! 10408: /*fprintf( stdout, "Last-Modified: Wed, 15 Oct 2003 01:01:01 GMT\n" );*/
! 10409: fprintf( stdout, "Content-type: image/gif\n\n" ); }
! 10410: /* --- initialize gifsave library and colors --- */
! 10411: if ( msgfp!=NULL && msglevel>=999 )
! 10412: fprintf(msgfp,"main> calling GIF_Create(*,%d,%d,%d,8)\n",
! 10413: bp->width,bp->height,ncolors);
! 10414: while ( 1 ) /* init gifsave lib, and retry if caching fails */
! 10415: { int status = GIF_Create(gif_outfile, bp->width,bp->height, ncolors, 8);
! 10416: if ( status == 0 ) break; /* continue if succeeded */
! 10417: if ( iscaching == 0 ) goto end_of_job; /* quit if failed */
! 10418: iscaching = 0; /* retry without cache file */
! 10419: gif_outfile = (char *)NULL; } /* emit images to stdout */
! 10420: GIF_SetColor(0,bgred,bggreen,bgblue); /* background white if all 255 */
! 10421: if ( !isaa ) /* just b&w if not anti-aliased */
! 10422: { GIF_SetColor(1,fgred,fggreen,fgblue); /* foreground black if all 0 */
! 10423: colors[0]='\000'; colors[1]='\001'; } /* and set 2 b&w color indexes */
! 10424: else /* set grayscales for anti-aliasing */
! 10425: /* --- anti-aliased, so call GIF_SetColor() for each colors[] --- */
! 10426: for ( igray=1; igray<ncolors; igray++ ) /* for colors[] values */
! 10427: {
! 10428: /*--- gfrac goes from 0 to 1.0, as igray goes from 0 to ncolors-1 ---*/
! 10429: double gfrac = ((double)colors[igray])/((double)colors[ncolors-1]);
! 10430: /* --- r,g,b components go from background to foreground color --- */
! 10431: int red = iround(((double)bgred) +gfrac*((double)(fgred-bgred))),
! 10432: green= iround(((double)bggreen)+gfrac*((double)(fggreen-bggreen))),
! 10433: blue = iround(((double)bgblue) +gfrac*((double)(fgblue-bgblue)));
! 10434: /* --- set color index number igray to rgb values gray,gray,gray --- */
! 10435: GIF_SetColor(igray, red,green,blue); /*set gray,grayer,...,0=black*/
! 10436: } /* --- end-of-for(igray) --- */
! 10437: /* --- set gif color#0 (background) transparent --- */
! 10438: if ( istransparent ) /* transparent background wanted */
! 10439: GIF_SetTransparent(0); /* set transparent background */
! 10440: if (msgfp!=NULL && msglevel>=9) fflush(msgfp); /*flush debugging output*/
! 10441: /* --- emit compressed gif image (to stdout or cache file) --- */
! 10442: GIF_CompressImage(0, 0, -1, -1, GetPixel); /* emit gif */
! 10443: GIF_Close(); /* close file */
! 10444: /* --- may need to emit image from cached file --- */
! 10445: if ( isquery && iscaching ) /* caching enabled */
! 10446: emitcache(cachefile); /* cached image (hopefully) emitted*/
! 10447: #else
! 10448: /* ------------------------------------------------------------------------
! 10449: emit mime XBITMAP image
! 10450: ------------------------------------------------------------------------- */
! 10451: xbitmap_raster(bp,stdout); /* default emits mime xbitmap */
! 10452: #endif
! 10453: } /* --- end-of-if(isquery) --- */
! 10454: /* --- exit --- */
! 10455: end_of_job:
! 10456: if ( bytemap_raster != NULL ) free(bytemap_raster); /*free bytemap_raster*/
! 10457: if (colormap_raster != NULL )free(colormap_raster); /*and colormap_raster*/
! 10458: if ( msgfp != NULL /* have message/log file open */
! 10459: && msgfp != stdout ) /* and it's not stdout */
! 10460: { fprintf(msgfp,"mimeTeX> successful end-of-job at %s\n",timestamp());
! 10461: fprintf(msgfp,"%s\n",dashes); /* so log separator line */
! 10462: fclose(msgfp); } /* and close logfile */
! 10463: exit ( 0 );
! 10464: } /* --- end-of-function main() --- */
! 10465:
! 10466: /* ==========================================================================
! 10467: * Function: isstrstr ( char *string, char *snippets, int iscase )
! 10468: * Purpose: determine whether any substring of 'string'
! 10469: * matches any of the comma-separated list of 'snippets',
! 10470: * ignoring case if iscase=0.
! 10471: * --------------------------------------------------------------------------
! 10472: * Arguments: string (I) char * containing null-terminated
! 10473: * string that will be searched for
! 10474: * any one of the specified snippets
! 10475: * snippets (I) char * containing null-terminated,
! 10476: * comma-separated list of snippets
! 10477: * to be searched for in string
! 10478: * iscase (I) int containing 0 for case-insensitive
! 10479: * comparisons, or 1 for case-sensitive
! 10480: * --------------------------------------------------------------------------
! 10481: * Returns: ( int ) 1 if any snippet is a substring of
! 10482: * string, 0 if not
! 10483: * --------------------------------------------------------------------------
! 10484: * Notes: o
! 10485: * ======================================================================= */
! 10486: /* --- entry point --- */
! 10487: int isstrstr ( char *string, char *snippets, int iscase )
! 10488: {
! 10489: /* -------------------------------------------------------------------------
! 10490: Allocations and Declarations
! 10491: -------------------------------------------------------------------------- */
! 10492: int status = 0; /*1 if any snippet found in string*/
! 10493: char snip[99], *snipptr = snippets, /* munge through each snippet */
! 10494: delim = ',', *delimptr = NULL; /* separated by delim's */
! 10495: char stringcp[999], *cp = stringcp; /*maybe lowercased copy of string*/
! 10496: /* -------------------------------------------------------------------------
! 10497: initialization
! 10498: -------------------------------------------------------------------------- */
! 10499: /* --- arg check --- */
! 10500: if ( string==NULL || snippets==NULL ) goto end_of_job; /* missing arg */
! 10501: if ( *string=='\000' || *snippets=='\000' ) goto end_of_job; /* empty arg */
! 10502: /* --- copy string and lowercase it if case-insensitive --- */
! 10503: strcpy(stringcp,string); /* local copy of string */
! 10504: if ( !iscase ) /* want case-insensitive compares */
! 10505: for ( cp=stringcp; *cp != '\000'; cp++ ) /* so for each string char */
! 10506: if ( isupper(*cp) ) *cp = tolower(*cp); /*lowercase any uppercase chars*/
! 10507: /* -------------------------------------------------------------------------
! 10508: extract each snippet and see if it's a substring of string
! 10509: -------------------------------------------------------------------------- */
! 10510: while ( snipptr != NULL ) /* while we still have snippets */
! 10511: {
! 10512: /* --- extract next snippet --- */
! 10513: if ( (delimptr = strchr(snipptr,delim)) /* locate next comma delim */
! 10514: == NULL ) /*not found following last snippet*/
! 10515: { strcpy(snip,snipptr); /* local copy of last snippet */
! 10516: snipptr = NULL; } /* signal end-of-string */
! 10517: else /* snippet ends just before delim */
! 10518: { int sniplen = (int)(delimptr-snipptr) - 1; /* #chars in snippet */
! 10519: memcpy(snip,snipptr,sniplen); /* local copy of snippet chars */
! 10520: snip[sniplen] = '\000'; /* null-terminated snippet */
! 10521: snipptr = delimptr + 1; } /* next snippet starts after delim */
! 10522: /* --- lowercase snippet if case-insensitive --- */
! 10523: if ( !iscase ) /* want case-insensitive compares */
! 10524: for ( cp=snip; *cp != '\000'; cp++ ) /* so for each snippet char */
! 10525: if ( isupper(*cp) ) *cp=tolower(*cp); /*lowercase any uppercase chars*/
! 10526: /* --- check if snippet in string --- */
! 10527: if ( strstr(stringcp,snip) != NULL ) /* found snippet in string */
! 10528: { status = 1; /* so reset return status */
! 10529: break; } /* no need to check any further */
! 10530: } /* --- end-of-while(*snipptr!=0) --- */
! 10531: end_of_job: return ( status ); /*1 if snippet found in list, else 0*/
! 10532: } /* --- end-of-function isstrstr() --- */
! 10533:
! 10534: /* ==========================================================================
! 10535: * Function: ismonth ( char *month )
! 10536: * Purpose: returns 1 if month contains current month "jan"..."dec".
! 10537: * --------------------------------------------------------------------------
! 10538: * Arguments: month (I) char * containing null-terminated string
! 10539: * in which "jan"..."dec" is (putatively)
! 10540: * contained as a substring.
! 10541: * --------------------------------------------------------------------------
! 10542: * Returns: ( int ) 1 if month contains current month,
! 10543: * 0 otherwise
! 10544: * --------------------------------------------------------------------------
! 10545: * Notes: o There's a three day "grace period", e.g., Dec 3 mtaches Nov.
! 10546: * ======================================================================= */
! 10547: /* --- entry point --- */
! 10548: int ismonth ( char *month )
! 10549: {
! 10550: /* -------------------------------------------------------------------------
! 10551: Allocations and Declarations
! 10552: -------------------------------------------------------------------------- */
! 10553: int isokay = 0; /*1 if month contains current month*/
! 10554: /*long time_val = 0L;*/ /* binary value returned by time() */
! 10555: time_t time_val = (time_t)(0); /* binary value returned by time() */
! 10556: struct tm *tmstruct=(struct tm *)NULL, *localtime(); /* interpret time_val */
! 10557: int imonth, mday; /* current month 1-12 and day 1-31 */
! 10558: int ngrace = 3; /* grace period */
! 10559: char lcmonth[128]="\000"; int i=0; /* lowercase month */
! 10560: static char *months[] = /* month must contain current one */
! 10561: {"dec","jan","feb","mar","apr","may","jun",
! 10562: "jul","aug","sep","oct","nov","dec","jan"};
! 10563: /* -------------------------------------------------------------------------
! 10564: get current date:time info, and check month
! 10565: -------------------------------------------------------------------------- */
! 10566: /* --- lowercase input month --- */
! 10567: if ( month != NULL ) /* check that we got input */
! 10568: for ( i=0; i<120 && *month!='\000'; i++,month++ ) /* go thru month chars */
! 10569: lcmonth[i] = tolower(*month); /* lowerase each char in month */
! 10570: if ( i < 2 ) goto end_of_job; /* must be invalid input */
! 10571: lcmonth[i] = '\000'; /* null-terminate lcmonth[] */
! 10572: /* --- get current date:time --- */
! 10573: time((time_t *)(&time_val)); /* get date and time */
! 10574: tmstruct = localtime((time_t *)(&time_val)); /* interpret time_val */
! 10575: /* --- month and day --- */
! 10576: imonth = 1 + (int)(tmstruct->tm_mon); /* 1=jan ... 12=dec */
! 10577: mday = (int)(tmstruct->tm_mday); /* 1-31 */
! 10578: if ( imonth<1 || imonth>12 /* quit if month out-of-range */
! 10579: || mday<0 || mday>31 ) goto end_of_job; /* or date out of range */
! 10580: /* --- check input month against current date --- */
! 10581: if ( strstr(lcmonth,months[imonth]) != NULL ) isokay = 1; /* current month */
! 10582: if ( mday <= ngrace ) /* 1-3 within grace period */
! 10583: if ( strstr(lcmonth,months[imonth-1]) != NULL ) isokay = 1; /* last month */
! 10584: if ( mday >= 31-ngrace ) /* 28-31 within grace period */
! 10585: if ( strstr(lcmonth,months[imonth+1]) != NULL ) isokay = 1; /* next month */
! 10586: end_of_job:
! 10587: return ( isokay ); /*1 if month contains current month*/
! 10588: } /* --- end-of-function ismonth() --- */
! 10589:
! 10590: /* ==========================================================================
! 10591: * Functions: int unescape_url ( char *url, int isescape )
! 10592: * char x2c ( char *what )
! 10593: * Purpose: unescape_url replaces 3-character sequences %xx in url
! 10594: * with the single character represented by hex xx.
! 10595: * x2c returns the single character represented by hex xx
! 10596: * passed as a 2-character sequence in what.
! 10597: * --------------------------------------------------------------------------
! 10598: * Arguments: url (I) char * containing null-terminated
! 10599: * string with embedded %xx sequences
! 10600: * to be converted.
! 10601: * isescape (I) int containing 1 to _not_ unescape
! 10602: * \% sequences (0 would be NCSA default)
! 10603: * what (I) char * whose first 2 characters are
! 10604: * interpreted as ascii representations
! 10605: * of hex digits.
! 10606: * --------------------------------------------------------------------------
! 10607: * Returns: ( int ) unescape_url always returns 0.
! 10608: * ( char ) x2c returns the single char
! 10609: * corresponding to hex xx passed in what.
! 10610: * --------------------------------------------------------------------------
! 10611: * Notes: o These two functions were taken verbatim from util.c in
! 10612: * ftp://ftp.ncsa.uiuc.edu/Web/httpd/Unix/ncsa_httpd/cgi/ncsa-default.tar.Z
! 10613: * o Not quite "verbatim" -- I added the "isescape logic" 4-Dec-03
! 10614: * so unescape_url() can be safely applied to input which may or
! 10615: * may not have been url-encoded.
! 10616: * ======================================================================= */
! 10617: /* --- entry point --- */
! 10618: int unescape_url(char *url, int isescape) {
! 10619: int x=0,y=0,prevescape=0,gotescape=0;
! 10620: char x2c();
! 10621: static char *hex="0123456789ABCDEFabcdef";
! 10622: for(;url[y];++x,++y) {
! 10623: gotescape = prevescape;
! 10624: prevescape = (url[x]=='\\');
! 10625: if((url[x] = url[y]) == '%')
! 10626: if(!isescape || !gotescape)
! 10627: if(isthischar(url[y+1],hex)
! 10628: && isthischar(url[y+2],hex))
! 10629: { url[x] = x2c(&url[y+1]);
! 10630: y+=2; }
! 10631: }
! 10632: url[x] = '\0';
! 10633: return 0;
! 10634: } /* --- end-of-function unescape_url() --- */
! 10635: /* --- entry point --- */
! 10636: char x2c(char *what) {
! 10637: char digit;
! 10638: digit = (what[0] >= 'A' ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
! 10639: digit *= 16;
! 10640: digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A')+10 : (what[1] - '0'));
! 10641: return(digit);
! 10642: } /* --- end-of-function x2c() --- */
! 10643:
! 10644: /* ==========================================================================
! 10645: * Function: logger ( fp, msglevel, message, logvars )
! 10646: * Purpose: Logs the environment variables specified in logvars
! 10647: * to fp if their msglevel is >= the passed msglevel.
! 10648: * --------------------------------------------------------------------------
! 10649: * Arguments: fp (I) FILE * to file containing log
! 10650: * msglevel (I) int containing logging message level
! 10651: * message (I) char * to optional message, or NULL
! 10652: * logvars (I) logdata * to array of environment variables
! 10653: * to be logged
! 10654: * --------------------------------------------------------------------------
! 10655: * Returns: ( int ) number of variables from logvars
! 10656: * that were actually logged
! 10657: * --------------------------------------------------------------------------
! 10658: * Notes: o
! 10659: * ======================================================================= */
! 10660: /* --- entry point --- */
! 10661: int logger ( FILE *fp, int msglevel, char *message, logdata *logvars )
! 10662: {
! 10663: /* -------------------------------------------------------------------------
! 10664: Allocations and Declarations
! 10665: -------------------------------------------------------------------------- */
! 10666: int ilog=0, nlogged=0; /* logvars[] index, #vars logged */
! 10667: char *timestamp(); /* timestamp logged */
! 10668: char *value = NULL; /* getenv(name) to be logged */
! 10669: /* -------------------------------------------------------------------------
! 10670: Log each variable
! 10671: -------------------------------------------------------------------------- */
! 10672: fprintf(fp,"%s\n",timestamp()); /* emit timestamp before first var */
! 10673: if ( message != NULL ) /* optional message supplied */
! 10674: fprintf(fp," MESSAGE = %s\n",message); /* emit caller-supplied message */
! 10675: if ( logvars != (logdata *)NULL ) /* have logvars */
! 10676: for ( ilog=0; logvars[ilog].name != NULL; ilog++ ) /* till end-of-table */
! 10677: if ( msglevel >= logvars[ilog].msglevel ) /* check msglevel for this var */
! 10678: if ( (value=getenv(logvars[ilog].name)) /* getenv(name) to be logged */
! 10679: != NULL ) /* check that name exists */
! 10680: {
! 10681: fprintf(fp," %s = %.*s\n", /* emit variable name = value */
! 10682: logvars[ilog].name,logvars[ilog].maxlen,value);
! 10683: nlogged++; /* bump #vars logged */
! 10684: } /* --- end-of-for(ilog) --- */
! 10685: return ( nlogged ); /* back to caller */
! 10686: } /* --- end-of-function logger() --- */
! 10687:
! 10688: /* ==========================================================================
! 10689: * Function: emitcache ( cachefile )
! 10690: * Purpose: dumps bytes from cachefile to stdout
! 10691: * --------------------------------------------------------------------------
! 10692: * Arguments: cachefile (I) pointer to null-terminated char string
! 10693: * containing full path to file to be dumped
! 10694: * --------------------------------------------------------------------------
! 10695: * Returns: ( int ) #bytes dumped (0 signals error)
! 10696: * --------------------------------------------------------------------------
! 10697: * Notes: o
! 10698: * ======================================================================= */
! 10699: /* --- entry point --- */
! 10700: int emitcache ( char *cachefile )
! 10701: {
! 10702: /* -------------------------------------------------------------------------
! 10703: Allocations and Declarations
! 10704: -------------------------------------------------------------------------- */
! 10705: FILE *cacheptr = fopen(cachefile,"rb"), /*open cachefile for binary read*/
! 10706: *emitptr = stdout; /* emit cachefile to stdout */
! 10707: unsigned char buffer[64]; /* characters from cachefile */
! 10708: int buflen = 32, /* #bytes we try to read from cache*/
! 10709: nread = 0, /* #bytes actually read */
! 10710: nbytes = 0; /* total #bytes emitted */
! 10711: /* -------------------------------------------------------------------------
! 10712: initialization
! 10713: -------------------------------------------------------------------------- */
! 10714: /* --- check that files opened okay --- */
! 10715: if ( cacheptr == (FILE *)NULL /* failed to open cachefile */
! 10716: || emitptr == (FILE *)NULL ) /* or failed to open emit file */
! 10717: goto end_of_job; /* so return 0 bytes to caller */
! 10718: /* --- set stdout to binary mode (for Windows) --- */
! 10719: /* emitptr = fdopen(STDOUT_FILENO,"wb"); */ /* doesn't work portably, */
! 10720: #ifdef WINDOWS /* so instead... */
! 10721: #ifdef HAVE_SETMODE /* prefer (non-portable) setmode() */
! 10722: if ( setmode ( fileno (stdout), O_BINARY) /* windows specific call */
! 10723: == -1 ) ; /* handle error */ /* sets stdout to binary mode */
! 10724: #else /* setmode() not available */
! 10725: #if 1
! 10726: freopen ("CON", "wb", stdout); /* freopen() stdout binary */
! 10727: #else
! 10728: stdout = fdopen (STDOUT_FILENO, "wb"); /* fdopen() stdout binary */
! 10729: #endif
! 10730: #endif
! 10731: #endif
! 10732: /* -------------------------------------------------------------------------
! 10733: emit bytes from cachefile
! 10734: -------------------------------------------------------------------------- */
! 10735: while ( 1 )
! 10736: {
! 10737: /* --- read bytes from cachefile --- */
! 10738: nread = fread(buffer,sizeof(unsigned char),buflen,cacheptr); /* read */
! 10739: if ( nread < 1 ) break; /* no bytes left in cachefile */
! 10740: /* --- write bytes to stdout --- */
! 10741: if ( fwrite(buffer,sizeof(unsigned char),nread,emitptr) /* write buffer */
! 10742: < nread) /* failed to write all bytes */
! 10743: { nbytes = 0; /* reset total count to 0 */
! 10744: goto end_of_job; } /* and signal error to caller */
! 10745: nbytes += nread; /* bump total #bytes emitted */
! 10746: if ( nread < buflen ) break; /* no bytes left in cachefile */
! 10747: } /* --- end-of-while(1) --- */
! 10748: end_of_job:
! 10749: if ( cacheptr != NULL ) fclose(cacheptr); /* close file if opened */
! 10750: return ( nbytes ); /* back with #bytes emitted */
! 10751: } /* --- end-of-function emitcache() --- */
! 10752:
! 10753: /* ==========================================================================
! 10754: * Function: md5str ( instr )
! 10755: * Purpose: returns null-terminated character string containing
! 10756: * md5 hash of instr (input string)
! 10757: * --------------------------------------------------------------------------
! 10758: * Arguments: instr (I) pointer to null-terminated char string
! 10759: * containing input string whose md5 hash
! 10760: * is desired
! 10761: * --------------------------------------------------------------------------
! 10762: * Returns: ( char * ) ptr to null-terminated 32-character
! 10763: * md5 hash of instr
! 10764: * --------------------------------------------------------------------------
! 10765: * Notes: o Other md5 library functions are included below.
! 10766: * They're all taken from Christophe Devine's code,
! 10767: * which (as of 04-Aug-2004) is available from
! 10768: * http://www.cr0.net:8040/code/crypto/md5/
! 10769: * o The P,F,S macros in the original code are replaced
! 10770: * by four functions P1()...P4() to accommodate a problem
! 10771: * with Compaq's vax/vms C compiler.
! 10772: * ======================================================================= */
! 10773: /* --- #include "md5.h" --- */
! 10774: #ifndef uint8
! 10775: #define uint8 unsigned char
! 10776: #endif
! 10777: #ifndef uint32
! 10778: #define uint32 unsigned long int
! 10779: #endif
! 10780: typedef struct
! 10781: { uint32 total[2];
! 10782: uint32 state[4];
! 10783: uint8 buffer[64];
! 10784: } md5_context;
! 10785: void md5_starts( md5_context *ctx );
! 10786: void md5_update( md5_context *ctx, uint8 *input, uint32 length );
! 10787: void md5_finish( md5_context *ctx, uint8 digest[16] );
! 10788: /* --- md5.h --- */
! 10789: #define GET_UINT32(n,b,i) \
! 10790: { (n) = ( (uint32) (b)[(i) ] ) \
! 10791: | ( (uint32) (b)[(i) + 1] << 8 ) \
! 10792: | ( (uint32) (b)[(i) + 2] << 16 ) \
! 10793: | ( (uint32) (b)[(i) + 3] << 24 ); }
! 10794: #define PUT_UINT32(n,b,i) \
! 10795: { (b)[(i) ] = (uint8) ( (n) ); \
! 10796: (b)[(i) + 1] = (uint8) ( (n) >> 8 ); \
! 10797: (b)[(i) + 2] = (uint8) ( (n) >> 16 ); \
! 10798: (b)[(i) + 3] = (uint8) ( (n) >> 24 ); }
! 10799: /* --- P,S,F macros defined as functions --- */
! 10800: void P1(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
! 10801: { *a += (uint32)(d ^ (b & (c ^ d))) + X[k] + t;
! 10802: *a = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
! 10803: return; }
! 10804: void P2(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
! 10805: { *a += (uint32)(c ^ (d & (b ^ c))) + X[k] + t;
! 10806: *a = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
! 10807: return; }
! 10808: void P3(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
! 10809: { *a += (uint32)(b ^ c ^ d) + X[k] + t;
! 10810: *a = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
! 10811: return; }
! 10812: void P4(uint32 *X,uint32 *a,uint32 b,uint32 c,uint32 d,int k,int s,uint32 t)
! 10813: { *a += (uint32)(c ^ (b | ~d)) + X[k] + t;
! 10814: *a = ((*a<<s) | ((*a & 0xFFFFFFFF) >> (32-s))) + b;
! 10815: return; }
! 10816:
! 10817: /* --- entry point (this one little stub written by me)--- */
! 10818: char *md5str( char *instr )
! 10819: { static char outstr[64];
! 10820: unsigned char md5sum[16];
! 10821: md5_context ctx;
! 10822: int j;
! 10823: md5_starts( &ctx );
! 10824: md5_update( &ctx, (uint8 *)instr, strlen(instr) );
! 10825: md5_finish( &ctx, md5sum );
! 10826: for( j=0; j<16; j++ )
! 10827: sprintf( outstr + j*2, "%02x", md5sum[j] );
! 10828: outstr[32] = '\000';
! 10829: return ( outstr ); }
! 10830:
! 10831: /* --- entry point (all md5 functions below by Christophe Devine) --- */
! 10832: void md5_starts( md5_context *ctx )
! 10833: { ctx->total[0] = 0;
! 10834: ctx->total[1] = 0;
! 10835: ctx->state[0] = 0x67452301;
! 10836: ctx->state[1] = 0xEFCDAB89;
! 10837: ctx->state[2] = 0x98BADCFE;
! 10838: ctx->state[3] = 0x10325476; }
! 10839:
! 10840: void md5_process( md5_context *ctx, uint8 data[64] )
! 10841: { uint32 X[16], A, B, C, D;
! 10842: GET_UINT32( X[0], data, 0 );
! 10843: GET_UINT32( X[1], data, 4 );
! 10844: GET_UINT32( X[2], data, 8 );
! 10845: GET_UINT32( X[3], data, 12 );
! 10846: GET_UINT32( X[4], data, 16 );
! 10847: GET_UINT32( X[5], data, 20 );
! 10848: GET_UINT32( X[6], data, 24 );
! 10849: GET_UINT32( X[7], data, 28 );
! 10850: GET_UINT32( X[8], data, 32 );
! 10851: GET_UINT32( X[9], data, 36 );
! 10852: GET_UINT32( X[10], data, 40 );
! 10853: GET_UINT32( X[11], data, 44 );
! 10854: GET_UINT32( X[12], data, 48 );
! 10855: GET_UINT32( X[13], data, 52 );
! 10856: GET_UINT32( X[14], data, 56 );
! 10857: GET_UINT32( X[15], data, 60 );
! 10858: A = ctx->state[0];
! 10859: B = ctx->state[1];
! 10860: C = ctx->state[2];
! 10861: D = ctx->state[3];
! 10862: P1( X, &A, B, C, D, 0, 7, 0xD76AA478 );
! 10863: P1( X, &D, A, B, C, 1, 12, 0xE8C7B756 );
! 10864: P1( X, &C, D, A, B, 2, 17, 0x242070DB );
! 10865: P1( X, &B, C, D, A, 3, 22, 0xC1BDCEEE );
! 10866: P1( X, &A, B, C, D, 4, 7, 0xF57C0FAF );
! 10867: P1( X, &D, A, B, C, 5, 12, 0x4787C62A );
! 10868: P1( X, &C, D, A, B, 6, 17, 0xA8304613 );
! 10869: P1( X, &B, C, D, A, 7, 22, 0xFD469501 );
! 10870: P1( X, &A, B, C, D, 8, 7, 0x698098D8 );
! 10871: P1( X, &D, A, B, C, 9, 12, 0x8B44F7AF );
! 10872: P1( X, &C, D, A, B, 10, 17, 0xFFFF5BB1 );
! 10873: P1( X, &B, C, D, A, 11, 22, 0x895CD7BE );
! 10874: P1( X, &A, B, C, D, 12, 7, 0x6B901122 );
! 10875: P1( X, &D, A, B, C, 13, 12, 0xFD987193 );
! 10876: P1( X, &C, D, A, B, 14, 17, 0xA679438E );
! 10877: P1( X, &B, C, D, A, 15, 22, 0x49B40821 );
! 10878: P2( X, &A, B, C, D, 1, 5, 0xF61E2562 );
! 10879: P2( X, &D, A, B, C, 6, 9, 0xC040B340 );
! 10880: P2( X, &C, D, A, B, 11, 14, 0x265E5A51 );
! 10881: P2( X, &B, C, D, A, 0, 20, 0xE9B6C7AA );
! 10882: P2( X, &A, B, C, D, 5, 5, 0xD62F105D );
! 10883: P2( X, &D, A, B, C, 10, 9, 0x02441453 );
! 10884: P2( X, &C, D, A, B, 15, 14, 0xD8A1E681 );
! 10885: P2( X, &B, C, D, A, 4, 20, 0xE7D3FBC8 );
! 10886: P2( X, &A, B, C, D, 9, 5, 0x21E1CDE6 );
! 10887: P2( X, &D, A, B, C, 14, 9, 0xC33707D6 );
! 10888: P2( X, &C, D, A, B, 3, 14, 0xF4D50D87 );
! 10889: P2( X, &B, C, D, A, 8, 20, 0x455A14ED );
! 10890: P2( X, &A, B, C, D, 13, 5, 0xA9E3E905 );
! 10891: P2( X, &D, A, B, C, 2, 9, 0xFCEFA3F8 );
! 10892: P2( X, &C, D, A, B, 7, 14, 0x676F02D9 );
! 10893: P2( X, &B, C, D, A, 12, 20, 0x8D2A4C8A );
! 10894: P3( X, &A, B, C, D, 5, 4, 0xFFFA3942 );
! 10895: P3( X, &D, A, B, C, 8, 11, 0x8771F681 );
! 10896: P3( X, &C, D, A, B, 11, 16, 0x6D9D6122 );
! 10897: P3( X, &B, C, D, A, 14, 23, 0xFDE5380C );
! 10898: P3( X, &A, B, C, D, 1, 4, 0xA4BEEA44 );
! 10899: P3( X, &D, A, B, C, 4, 11, 0x4BDECFA9 );
! 10900: P3( X, &C, D, A, B, 7, 16, 0xF6BB4B60 );
! 10901: P3( X, &B, C, D, A, 10, 23, 0xBEBFBC70 );
! 10902: P3( X, &A, B, C, D, 13, 4, 0x289B7EC6 );
! 10903: P3( X, &D, A, B, C, 0, 11, 0xEAA127FA );
! 10904: P3( X, &C, D, A, B, 3, 16, 0xD4EF3085 );
! 10905: P3( X, &B, C, D, A, 6, 23, 0x04881D05 );
! 10906: P3( X, &A, B, C, D, 9, 4, 0xD9D4D039 );
! 10907: P3( X, &D, A, B, C, 12, 11, 0xE6DB99E5 );
! 10908: P3( X, &C, D, A, B, 15, 16, 0x1FA27CF8 );
! 10909: P3( X, &B, C, D, A, 2, 23, 0xC4AC5665 );
! 10910: P4( X, &A, B, C, D, 0, 6, 0xF4292244 );
! 10911: P4( X, &D, A, B, C, 7, 10, 0x432AFF97 );
! 10912: P4( X, &C, D, A, B, 14, 15, 0xAB9423A7 );
! 10913: P4( X, &B, C, D, A, 5, 21, 0xFC93A039 );
! 10914: P4( X, &A, B, C, D, 12, 6, 0x655B59C3 );
! 10915: P4( X, &D, A, B, C, 3, 10, 0x8F0CCC92 );
! 10916: P4( X, &C, D, A, B, 10, 15, 0xFFEFF47D );
! 10917: P4( X, &B, C, D, A, 1, 21, 0x85845DD1 );
! 10918: P4( X, &A, B, C, D, 8, 6, 0x6FA87E4F );
! 10919: P4( X, &D, A, B, C, 15, 10, 0xFE2CE6E0 );
! 10920: P4( X, &C, D, A, B, 6, 15, 0xA3014314 );
! 10921: P4( X, &B, C, D, A, 13, 21, 0x4E0811A1 );
! 10922: P4( X, &A, B, C, D, 4, 6, 0xF7537E82 );
! 10923: P4( X, &D, A, B, C, 11, 10, 0xBD3AF235 );
! 10924: P4( X, &C, D, A, B, 2, 15, 0x2AD7D2BB );
! 10925: P4( X, &B, C, D, A, 9, 21, 0xEB86D391 );
! 10926: ctx->state[0] += A;
! 10927: ctx->state[1] += B;
! 10928: ctx->state[2] += C;
! 10929: ctx->state[3] += D; }
! 10930:
! 10931: void md5_update( md5_context *ctx, uint8 *input, uint32 length )
! 10932: { uint32 left, fill;
! 10933: if( length < 1 ) return;
! 10934: left = ctx->total[0] & 0x3F;
! 10935: fill = 64 - left;
! 10936: ctx->total[0] += length;
! 10937: ctx->total[0] &= 0xFFFFFFFF;
! 10938: if( ctx->total[0] < length )
! 10939: ctx->total[1]++;
! 10940: if( left && length >= fill )
! 10941: { memcpy( (void *) (ctx->buffer + left),
! 10942: (void *) input, fill );
! 10943: md5_process( ctx, ctx->buffer );
! 10944: length -= fill;
! 10945: input += fill;
! 10946: left = 0; }
! 10947: while( length >= 64 )
! 10948: { md5_process( ctx, input );
! 10949: length -= 64;
! 10950: input += 64; }
! 10951: if( length >= 1 )
! 10952: memcpy( (void *) (ctx->buffer + left),
! 10953: (void *) input, length ); }
! 10954:
! 10955: void md5_finish( md5_context *ctx, uint8 digest[16] )
! 10956: { static uint8 md5_padding[64] =
! 10957: { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 10958: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 10959: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
! 10960: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
! 10961: uint32 last, padn;
! 10962: uint32 high, low;
! 10963: uint8 msglen[8];
! 10964: high = ( ctx->total[0] >> 29 )
! 10965: | ( ctx->total[1] << 3 );
! 10966: low = ( ctx->total[0] << 3 );
! 10967: PUT_UINT32( low, msglen, 0 );
! 10968: PUT_UINT32( high, msglen, 4 );
! 10969: last = ctx->total[0] & 0x3F;
! 10970: padn = ( last < 56 ) ? ( 56 - last ) : ( 120 - last );
! 10971: md5_update( ctx, md5_padding, padn );
! 10972: md5_update( ctx, msglen, 8 );
! 10973: PUT_UINT32( ctx->state[0], digest, 0 );
! 10974: PUT_UINT32( ctx->state[1], digest, 4 );
! 10975: PUT_UINT32( ctx->state[2], digest, 8 );
! 10976: PUT_UINT32( ctx->state[3], digest, 12 ); }
! 10977: /* --- end-of-function md5str() and "friends" --- */
! 10978:
! 10979: #if defined(GIF)
! 10980: /* ==========================================================================
! 10981: * Function: GetPixel ( int x, int y )
! 10982: * Purpose: callback for GIF_CompressImage() returning the
! 10983: * pixel at column x, row y
! 10984: * --------------------------------------------------------------------------
! 10985: * Arguments: x (I) int containing column=0...width-1
! 10986: * of desired pixel
! 10987: * y (I) int containing row=0...height-1
! 10988: * of desired pixel
! 10989: * --------------------------------------------------------------------------
! 10990: * Returns: ( int ) 0 or 1, if pixel at x,y is off or on
! 10991: * --------------------------------------------------------------------------
! 10992: * Notes: o
! 10993: * ======================================================================= */
! 10994: /* --- entry point --- */
! 10995: int GetPixel ( int x, int y )
! 10996: {
! 10997: int ipixel = y*bitmap_raster->width + x; /* pixel index for x,y-coords*/
! 10998: int pixval =0; /* value of pixel */
! 10999: if ( !isaa ) /* use bitmap if not anti-aliased */
! 11000: pixval = (int)getlongbit(bitmap_raster->pixmap,ipixel); /*pixel = 0 or 1*/
! 11001: else /* else use anti-aliased grayscale*/
! 11002: pixval = (int)(colormap_raster[ipixel]); /* colors[] index number */
! 11003: if ( msgfp!=NULL && msglevel>=9999 ) /* dump pixel */
! 11004: { fprintf(msgfp,"GetPixel> x=%d, y=%d pixel=%d\n",x,y,pixval);
! 11005: fflush(msgfp); }
! 11006: return pixval;
! 11007: } /* --- end-of-function GetPixel() --- */
! 11008: #endif /* gif */
! 11009: #endif /* driver */
! 11010: #endif /* PART1 */
! 11011: /* ======================= END-OF-FILE MIMETEX.C ========================= */
! 11012:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>