/* * ratPrint.c -- * * This file contains the code for a simple prettyprinter. * Unfortunately it is currently limited to iso8859-1 characters. * * TkRat software and its included text is Copyright 1996-2002 by * Martin Forssén * * The full text of the legal notice is contained in the file called * COPYRIGHT, included with this distribution. */ #include "ratFolder.h" #include typedef enum { FONT_SMALL, FONT_NORMAL, FONT_BOLD, FONT_BIG } RatFont; /* * Misc defines and variables describing the size of the page and * other related data */ #define PS_LEFT_MARGIN 50 #define PS_RIGHT_MARGIN 25 #define PS_TOP_MARGIN 25 #define PS_BOTTOM_MARGIN 25 static int ps_xsize, ps_ysize; static int portrait; static int fontsize; static int resolution; static char *font, *boldfont; static int *font_wx, *boldfont_wx; static int yPos; static int pagenum; #define DATEWIDTH fontsize*6 #define PAGENUMWIDTH fontsize*4 #define SPACE 5 #define HINDENT 20 #define CHECK_NEWPAGE(x, y) {if (yPos < SPACE) Newpage(x, y, NULL, NULL);} /* * PostScript prolog, partly stolen from the tk 8.2b1 one */ static char *prolog = "\n\ %%BeginProlog\n\ % Define the array ISOLatin1Encoding (which specifies how characters are\n\ % encoded for ISO-8859-1 fonts), if it isn't already present (Postscript\n\ % level 2 is supposed to define it, but level 1 doesn't).\n\ \n\ systemdict /ISOLatin1Encoding known not {\n\ /ISOLatin1Encoding [\n\ /space /space /space /space /space /space /space /space\n\ /space /space /space /space /space /space /space /space\n\ /space /space /space /space /space /space /space /space\n\ /space /space /space /space /space /space /space /space\n\ /space /exclam /quotedbl /numbersign /dollar /percent /ampersand\n\ /quoteright\n\ /parenleft /parenright /asterisk /plus /comma /minus /period /slash\n\ /zero /one /two /three /four /five /six /seven\n\ /eight /nine /colon /semicolon /less /equal /greater /question\n\ /at /A /B /C /D /E /F /G\n\ /H /I /J /K /L /M /N /O\n\ /P /Q /R /S /T /U /V /W\n\ /X /Y /Z /bracketleft /backslash /bracketright /asciicircum \ /underscore\n\ /quoteleft /a /b /c /d /e /f /g\n\ /h /i /j /k /l /m /n /o \n\ /p /q /r /s /t /u /v /w\n\ /x /y /z /braceleft /bar /braceright /asciitilde /space\n\ /space /space /space /space /space /space /space /space\n\ /space /space /space /space /space /space /space /space\n\ /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent\n\ /dieresis /space /ring /cedilla /space /hungarumlaut /ogonek /caron\n\ /space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n\ /dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen\n\ /registered /macron\n\ /degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph\n\ /periodcentered\n\ /cedillar /onesuperior /ordmasculine /guillemotright /onequarter\n\ /onehalf /threequarters /questiondown\n\ /Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n\ /Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex\n\ /Idieresis\n\ /Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis \ /multiply\n\ /Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn\n\ /germandbls\n\ /agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n\ /egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex\n\ /idieresis\n\ /eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n\ /oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn\n\ /ydieresis\n\ ] def\n\ } if\n\ \n\ % font ISOEncode font \n\ % This procedure changes the encoding of a font from the default\n\ % Postscript encoding to ISOLatin1. It's typically invoked just\n\ % before invoking \"setfont\". The body of this procedure comes from\n\ % Section 5.6.1 of the Postscript book.\n\ \n\ /ISOEncode {\n\ dup length dict begin\n\ {1 index /FID ne {def} {pop pop} ifelse} forall\n\ /Encoding ISOLatin1Encoding def\n\ currentdict\n\ end \n\ \n\ % I'm not sure why it's necessary to use \"definefont\" on this new\n\ % font, but it seems to be important; just use the name \"Temporary\"\n\ % for the font. \n\ \n\ /Temporary exch definefont \n\ } bind def \n\ "; /* * Width table for Times-Roman with the iso8859-1 encoding */ static int tir_wx[256] = { 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 408, 500, 500, 833, 778, 333, 333, 333, 500, 564, 250, 564, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 278, 333, 333, 333, 333, 333, 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500 }; /* * Width table for Times-Bold with the iso8859-1 encoding */ static int tib_wx[256] = { 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 333, 555, 500, 500, 1000, 833, 333, 333, 333, 500, 570, 250, 570, 250, 278, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 250, 278, 333, 333, 333, 333, 333, 333, 333, 333, 250, 333, 333, 250, 333, 333, 333, 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500 }; /* * Width table for Helvetica with the iso8859-1 encoding */ static int hv_wx[256] = { 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584, 278, 584, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556, 222, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 333, 333, 333, 333, 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500 }; /* * Width table for Helvetica-Bold with the iso8859-1 encoding */ static int hvb_wx[256] = { 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584, 278, 584, 278, 278, 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556, 278, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 333, 333, 333, 333, 333, 333, 333, 333, 278, 333, 333, 278, 333, 333, 333, 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556 }; /* * Width table for Courier with the iso8859-1 encoding */ static int co_wx[256] = { 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 }; /* * Width table for Courier-Bold with the iso8859-1 encoding */ static int cob_wx[256] = { 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600 }; /* * Local functions */ static void InitPrintData(Tcl_Interp *interp); static float GetStringLength(RatFont font, const char *string, int length); static void Newpage(Tcl_Interp *interp, Tcl_Channel channel, const char *subjectArg, MESSAGECACHE *elt); static void Startpage(Tcl_Interp *interp, Tcl_Channel channel, const char *subject, MESSAGECACHE *elt, int pagenum); static void Endpage(Tcl_Channel channel); static void PsPrintString(Tcl_Interp *interp, Tcl_Channel channel, RatFont font, Tcl_Encoding enc, float lm, float hm, const char *string, int length); static void PrintHeaders(Tcl_Interp *interp, Tcl_Channel channel, Tcl_Encoding enc, char *hs, MessageInfo *msgPtr); static void PrintBody(Tcl_Interp *interp, Tcl_Channel channel, Tcl_Encoding enc, BodyInfo *bodyInfoPtr); static int PrintBodyText(Tcl_Interp *interp, Tcl_Channel channel, Tcl_Encoding enc, BodyInfo *bodyInfoPtr); static int PrintBodyImage(Tcl_Interp *interp, Tcl_Channel channel, BodyInfo *bodyInfoPtr); /* *---------------------------------------------------------------------- * * RatPrettyPrintMsg -- * * Print a message prettily * * Results: * A standard tcl result * * Side effects: * Adds data to the passed channel * *---------------------------------------------------------------------- */ int RatPrettyPrintMsg(ClientData dummy, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { MESSAGECACHE *elt; Tcl_Channel channel; Tcl_CmdInfo cmdInfo; MessageInfo *msgPtr; char *subject, *hs, buf[1024]; Tcl_Obj *oPtr, **bv; int bc, i; if (5 != objc) { Tcl_AppendResult(interp, "wrong # args: should be \"", Tcl_GetString(objv[0]), " channel header_set msg bodys\"", (char *) NULL); return TCL_ERROR; } /* * Get data from options */ channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), NULL); hs = Tcl_GetString(objv[2]); Tcl_GetCommandInfo(interp, Tcl_GetString(objv[3]), &cmdInfo); msgPtr = (MessageInfo*)cmdInfo.objClientData; oPtr = RatMsgInfo(interp, msgPtr, RAT_FOLDER_SUBJECT); subject = Tcl_GetString(oPtr); elt = RatMessageInternalDate(interp, msgPtr); /* * Init print data */ InitPrintData(interp); pagenum = 0; /* Print prelude & prolog */ Tcl_WriteChars(channel, "%!PS-Adobe-3.0\n" "%%Createor: TkRat\n" "%%Pages: (atend)\n" "%%DOcumentData: Clean7Bit\n", -1); snprintf(buf, sizeof(buf), "%%%%Orientation: %s\n" "%%%%DocumentNeededResources: font %s\n%%%%+ font %s\n", (portrait ? "Portrait" : "Landscape"), font, boldfont); Tcl_WriteChars(channel, buf, -1); Tcl_WriteChars(channel, "%%EndComments\n", -1); Tcl_WriteChars(channel, prolog, -1); snprintf(buf, sizeof(buf), "/smallfont /%s findfont %.2f scalefont ISOEncode def\n", font, fontsize/2.0); Tcl_WriteChars(channel, buf, -1); snprintf(buf, sizeof(buf), "/textfont /%s findfont %d scalefont ISOEncode def\n", font, fontsize); Tcl_WriteChars(channel, buf, -1); snprintf(buf, sizeof(buf), "/boldfont /%s findfont %d scalefont ISOEncode def\n", boldfont, fontsize); Tcl_WriteChars(channel, buf, -1); snprintf(buf,sizeof(buf), "/bigfont /%s findfont %d scalefont ISOEncode def\n", boldfont, fontsize*2); Tcl_WriteChars(channel, buf, -1); Tcl_WriteChars(channel, "%%EndProlog\n", -1); /* Print page borders etc */ Newpage(interp, channel, subject, elt); /* Print headers */ PrintHeaders(interp, channel, NULL, hs, msgPtr); /* Print bodyparts */ Tcl_ListObjGetElements(interp, objv[4], &bc, &bv); for (i=0; i= 0; i--) { Tcl_ListObjIndex(interp, oPtr, i, &o2Ptr); Tcl_ListObjIndex(interp, o2Ptr, 0, &o3Ptr); if (!strcmp(s, Tcl_GetString(o3Ptr))) { break; } } Tcl_ListObjIndex(interp, o2Ptr, 1, &o3Ptr); Tcl_ListObjIndex(interp, o3Ptr, 0, &o2Ptr); Tcl_GetIntFromObj(interp, o2Ptr, &ps_xsize); Tcl_ListObjIndex(interp, o3Ptr, 1, &o2Ptr); Tcl_GetIntFromObj(interp, o2Ptr, &ps_ysize); ps_xsize -= PS_LEFT_MARGIN + PS_RIGHT_MARGIN; ps_ysize -= PS_TOP_MARGIN + PS_BOTTOM_MARGIN; /* * Orientation */ s = Tcl_GetVar2(interp, "option", "print_orientation", TCL_GLOBAL_ONLY); if (!strcmp("portrait", s)) { portrait = 1; } else { portrait = 0; i = ps_xsize; ps_xsize = ps_ysize; ps_ysize = i; } /* * Fonts */ f = Tcl_GetVar2(interp, "option", "print_fontfamily", TCL_GLOBAL_ONLY); if (!strcasecmp("helvetica", f)) { font = "Helvetica"; boldfont = "Helvetica-Bold"; font_wx = hv_wx; boldfont_wx = hvb_wx; } else if (!strcasecmp("courier", f)) { font = "Courier"; boldfont = "Courier-Bold"; font_wx = co_wx; boldfont_wx = cob_wx; } else { font = "Times-Roman"; boldfont = "Times-Bold"; font_wx = tir_wx; boldfont_wx = tib_wx; } /* * Rest of the variables */ oPtr = Tcl_GetVar2Ex(interp, "option", "print_fontsize", TCL_GLOBAL_ONLY); Tcl_GetIntFromObj(interp, oPtr, &fontsize); oPtr = Tcl_GetVar2Ex(interp, "option", "print_resolution",TCL_GLOBAL_ONLY); Tcl_GetIntFromObj(interp, oPtr, &resolution); } /* *---------------------------------------------------------------------- * * GetStringLength -- * * Get the length of a given string in poscript points * * Results: * the length of the string * * Side effects: * None * *---------------------------------------------------------------------- */ static float GetStringLength(RatFont font, const char *string, int length) { int *wx = tir_wx, i; float l, size = fontsize; if (-1 == length) { length = strlen((char*)string); } switch(font) { case FONT_SMALL: wx = font_wx; size /= 2; break; case FONT_NORMAL: wx = font_wx; break; case FONT_BOLD: wx = boldfont_wx; break; case FONT_BIG: wx = boldfont_wx; size *= 2; break; } for (i=l=0; i 0) { Endpage(channel); } Startpage(interp, channel, subject, elt, ++pagenum); } /* *---------------------------------------------------------------------- * * Startpage -- * * Writes start of page data * * Results: * None * * Side effects: * Adds data to the passed channel * *---------------------------------------------------------------------- */ static void Startpage(Tcl_Interp *interp, Tcl_Channel channel, const char *subject, MESSAGECACHE *elt, int pagenum) { char buf[1024]; const unsigned char *cPtr; CONST84 char *s; float x, y, w, h, l; int objc; Tcl_Obj **objv, *oPtr; Tcl_DString ds; /* * prepare */ snprintf(buf, sizeof(buf), "%%%%Page: %d %d\n" "save\n" "%d %d translate\n", pagenum, pagenum, PS_LEFT_MARGIN, PS_BOTTOM_MARGIN); Tcl_WriteChars(channel, buf, -1); /* * Background */ x = SPACE/2; y = ps_ysize+SPACE/2; w = ps_xsize-SPACE; h=fontsize*2.6+SPACE; snprintf(buf, sizeof(buf), ".8 setgray %.2f %.2f %.2f %.2f rectfill\n" "0 setgray %.2f %.2f %.2f %.2f rectstroke\n", x, y-h, w, h, x, y-h, w, h); Tcl_WriteChars(channel, buf, -1); /* * Date */ x = SPACE; y = ps_ysize; w = fontsize*2.4; h = fontsize*2.6; snprintf(buf, sizeof(buf), "%.2f %.2f moveto %.2f 0 rlineto 0 -%.2f " "rlineto -%.2f 0 rlineto closepath stroke\n", x, y, w, h, w); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d", elt->day); l = GetStringLength(FONT_BOLD, buf, -1); sprintf(buf, "%.2f %.2f moveto boldfont setfont (%d) show\n", x+w/2-l/2, y-fontsize*1.1, elt->day); Tcl_WriteChars(channel, buf, -1); oPtr = Tcl_GetVar2Ex(interp, "t", "months", TCL_GLOBAL_ONLY), Tcl_ListObjGetElements(interp, oPtr, &objc, &objv); s = Tcl_GetString(objv[elt->month-1]); l = GetStringLength(FONT_SMALL, s, -1); snprintf(buf, sizeof(buf),"%.2f %.2f moveto smallfont setfont (%s) show\n", x+w/2-l/2, y-fontsize*1.7, s); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d", elt->year+BASEYEAR); l = GetStringLength(FONT_SMALL, buf, -1); sprintf(buf, "%.2f %.2f moveto smallfont setfont (%d) show\n", x+w/2-l/2, y-fontsize*2.3, elt->year+BASEYEAR); Tcl_WriteChars(channel, buf, -1); x += fontsize*3; y -= fontsize/2; s = Tcl_GetVar2(interp, "t", "received", TCL_GLOBAL_ONLY); snprintf(buf, sizeof(buf),"%.2f %.2f moveto smallfont setfont (%s) show\n", x, y, s); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%.2f %.2f moveto textfont setfont (%02d:%02d) show\n", x, y-fontsize*1.2, elt->hours, elt->minutes); Tcl_WriteChars(channel, buf, -1); /* * Subject */ x = SPACE+DATEWIDTH; y = ps_ysize-1.7*fontsize; yPos = ps_ysize-fontsize*4; Tcl_WriteChars(channel, buf, -1); s = Tcl_GetVar2(interp, "t", "mail_regarding", TCL_GLOBAL_ONLY); snprintf(buf, sizeof(buf),"boldfont setfont %.2f %.2f moveto\n(%s) show\n", x, y, s); Tcl_WriteChars(channel, buf, -1); x += GetStringLength(FONT_BOLD, s, -1); snprintf(buf, sizeof(buf),"textfont setfont %.2f %.2f moveto\n(", x+2, y); Tcl_WriteChars(channel, buf, -1); Tcl_UtfToExternalDString(NULL, subject, -1, &ds); for (cPtr = Tcl_DStringValue(&ds); *cPtr; cPtr++) { if ('(' == *cPtr || ')' == *cPtr || '\\' == *cPtr) { Tcl_WriteChars(channel, "\\", 1); } if (*cPtr >= 32 && *cPtr < 127) { Tcl_WriteChars(channel, cPtr, 1); } else { snprintf(buf, sizeof(buf), "\\%o", *cPtr); Tcl_WriteChars(channel, buf, -1); } } Tcl_DStringFree(&ds); Tcl_WriteChars(channel, ") show\n", -1); /* * Page number */ s = Tcl_GetVar2(interp, "t", "page", TCL_GLOBAL_ONLY); x = ps_xsize - PAGENUMWIDTH - GetStringLength(FONT_SMALL, s, -1); y = ps_ysize-fontsize; snprintf(buf, sizeof(buf),"%.2f %.2f moveto smallfont setfont (%s) show\n", x, y, s); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d", pagenum); x = ps_xsize-PAGENUMWIDTH/2 - GetStringLength(FONT_BIG, buf, -1)/2; y = ps_ysize-2*fontsize; sprintf(buf, "bigfont setfont %.2f %.2f moveto (%d) show\n", x, y,pagenum); Tcl_WriteChars(channel, buf, -1); } /* *---------------------------------------------------------------------- * * Endpage -- * * Writes end of page data * * Results: * None * * Side effects: * Adds data to the passed channel * *---------------------------------------------------------------------- */ static void Endpage(Tcl_Channel channel) { Tcl_WriteChars(channel, "restore\nshowpage\n", -1); } /* *---------------------------------------------------------------------- * * PsPrintString -- * * Prints the given string with the given margins. May break the * line if it does not fit, in that case yPos is updated to point at * the last line. * * Results: * None * * Side effects: * Adds data to the passed channel and may modify yPos and * initialize a new page. * *---------------------------------------------------------------------- */ static void PsPrintString(Tcl_Interp *interp, Tcl_Channel channel, RatFont font, Tcl_Encoding enc, float lm, float hm, const char *string, int length) { char buf[1024], *fn = ""; const unsigned char *cPtr; float ll, l; Tcl_DString ds; switch (font) { case FONT_SMALL: fn = "smallfont"; break; case FONT_NORMAL: fn = "textfont"; break; case FONT_BOLD: fn = "boldfont"; break; case FONT_BIG: fn = "bigfont"; break; } Tcl_UtfToExternalDString(enc, string, length, &ds); snprintf(buf, sizeof(buf), "%s setfont %.2f %d moveto\n(", fn, lm, yPos); Tcl_WriteChars(channel, buf, -1); for (cPtr = Tcl_DStringValue(&ds), ll=lm; *cPtr; cPtr++) { ll += (l = GetStringLength(font, cPtr, 1)); if (ll > ps_xsize-hm) { Tcl_WriteChars(channel, ") show\n", -1); yPos -= fontsize*1.1; CHECK_NEWPAGE(interp, channel); snprintf(buf, sizeof(buf), "%s setfont %.2f %d moveto\n(", fn, lm, yPos); Tcl_WriteChars(channel, buf, -1); ll = lm; } if ('(' == *cPtr || ')' == *cPtr || '\\' == *cPtr) { Tcl_WriteChars(channel, "\\", 1); } if (*cPtr >= 32 && *cPtr < 127) { Tcl_WriteChars(channel, cPtr, 1); } else { snprintf(buf, sizeof(buf), "\\%o", *cPtr); Tcl_WriteChars(channel, buf, -1); } } Tcl_WriteChars(channel, ") show\n", -1); Tcl_DStringFree(&ds); } /* *---------------------------------------------------------------------- * * PrintHeaders -- * * Prints the selected message headers * * Results: * None * * Side effects: * Adds data to the passed channel * *---------------------------------------------------------------------- */ static void PrintHeaders(Tcl_Interp *interp, Tcl_Channel channel, Tcl_Encoding enc, char *hs, MessageInfo *msgPtr) { Tcl_Obj **fhv, **phv, *oPtr, *o2Ptr; char buf[1024], *s; int i, j, l, fhc, phc; float maxX, *lengths; if (!strcmp("none", hs)) { return; } /* * Get headers to print */ snprintf(buf, sizeof(buf), "%s headers", msgPtr->name); Tcl_Eval(interp, buf); Tcl_ListObjGetElements(interp, Tcl_GetObjResult(interp), &fhc, &fhv); if (!strcmp("selected", hs)) { oPtr = Tcl_GetVar2Ex(interp, "option", "show_header_selection", TCL_GLOBAL_ONLY); Tcl_ListObjLength(interp, oPtr, &l); phv = (Tcl_Obj**)ckalloc(sizeof(Tcl_Obj*)*l); for (i=phc=0; i maxX) { maxX = lengths[i]; } } maxX += GetStringLength(FONT_BOLD, ": ", 2); /* * Print headers */ for (i=0; i=0; i--) { Tcl_DecrRefCount(objv[i]); } if (TCL_OK != r) { return TCL_ERROR; } namePtr = Tcl_GetObjResult(interp); Tcl_IncrRefCount(namePtr); ph = Tk_FindPhoto(interp, Tcl_GetString(namePtr)); Tk_PhotoGetImage(ph, &block); /* * Print it */ psw = (block.width*72)/resolution; psh = (block.height*72)/resolution; if (yPos < psh+SPACE) { Newpage(interp, channel, NULL, NULL); } yPos -= psh; sprintf(buf, "gsave\n/picstr %d string def\n", block.width*3); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d %d translate\n", ps_xsize/2-psw/2, yPos); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d %d scale\n", psw, psh); Tcl_WriteChars(channel, buf, -1); sprintf(buf, "%d %d 8 [%d 0 0 -%d 0 %d]\n", block.width, block.height, block.width, block.height, block.height); Tcl_WriteChars(channel, buf, -1); Tcl_WriteChars(channel, "{currentfile picstr readhexstring pop} false 3 colorimage\n", -1); for (l=y=0, p = block.pixelPtr; y < block.height; y++, p = bp+block.pitch) { bp = p; for (x=0; x=0; i--) { Tcl_DecrRefCount(objv[i]); } return TCL_OK; }