#!/bin/sh # This is `snmp2.25' (part 25 of snmp2). # Do not concatenate these parts, unpack them in order with `/bin/sh'. # File `snmp2/snmptcl/graph.c' is being continued... # touch -am 1231235999 $$.touch >/dev/null 2>&1 if test ! -f 1231235999 && test -f $$.touch; then shar_touch=touch else shar_touch=: echo echo 'WARNING: not restoring timestamps. Consider getting and' echo "installing GNU \`touch', distributed in GNU File Utilities..." echo fi rm -f 1231235999 $$.touch # if test ! -r _sharseq.tmp; then echo 'Please unpack part 1 first!' exit 1 fi shar_sequence=`cat _sharseq.tmp` if test "$shar_sequence" != 25; then echo "Please unpack part $shar_sequence next!" exit 1 fi if test ! -f _sharnew.tmp; then echo 'x - still skipping snmp2/snmptcl/graph.c' else echo 'x - continuing file snmp2/snmptcl/graph.c' sed 's/^X//' << 'SHAR_EOF' >> 'snmp2/snmptcl/graph.c' && X subValue = axisPtr->minor.low; X for (j = 1; j < axisPtr->minor.numSteps; j++) { X if (subValue >= axisPtr->major.low) X break; X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X segArr[segCnt++] = X Gr_Segment(graphPtr, 0.0, y, -MINOR_TICK, y); X subValue += axisPtr->minor.stepSize; X } X } X x = GX(graphPtr, -LABEL_TICK); X value = axisPtr->major.low; X for (i = 0; i < axisPtr->major.numSteps; i++) { X value = ROUND(value, axisPtr->major.stepSize); X X /* Scale the tick value [0..1] */ X y = ((value - axisPtr->minLimit) / axisPtr->range); X segArr[segCnt++] = Gr_Segment(graphPtr, 0.0, y, -MAJOR_TICK, y); X X /* Draw tick label at each major tick */ X FormatLabel(axisPtr->logScale, value, tickLabel); X DrawText(graphPtr, graphPtr->numberFontPtr, graphPtr->numberGC, X tickLabel, x, GY(graphPtr, y), TK_ANCHOR_E); X /* Minor ticks */ X if (axisPtr->minor.numSteps > 0 && value < axisPtr->maxLimit) { X if (axisPtr->logScale) { X for (j = 1; j < 9; j++) { X subValue = value + logTable[j]; X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X segArr[segCnt++] = Gr_Segment(graphPtr, 0.0, y, X -MAJOR_TICK * logTable[j], y); X } X } else { X subValue = value + axisPtr->minor.stepSize; X for (j = 1; (j < axisPtr->minor.numSteps) && X (subValue <= axisPtr->maxLimit); j++) { X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X segArr[segCnt++] = X Gr_Segment(graphPtr, 0.0, y, -MINOR_TICK, y); X subValue += axisPtr->minor.stepSize; X } X } X } X value += axisPtr->major.stepSize; X } X } X XDrawSegments(Tk_Display(graphPtr->tkwin), (Drawable) graphPtr->output, X graphPtr->numberGC, segArr, segCnt); X X if (segCnt > need) X fprintf(stderr, "Number allocated = %d, used = %d\n", need, segCnt); #ifdef NO_ALLOCA X ckfree((char *)segArr); #endif } X /* X * ----------------------------------------------------------------- X * X * DrawXYGraph -- X * X * ----------------------------------------------------------------- X */ static int DrawXYGraph(graphPtr) X register Graph *graphPtr; { X register int n; X register double x, y; X register Line *linePtr; X XPoint *ptArr; X register int numPoints; X int numValues; X register double *xvaluePtr, *yvaluePtr; X double lastx; X ListEntry *searchId; X Tk_Window tkwin = graphPtr->tkwin; X Drawable draw = (Drawable) graphPtr->output; X X DrawXAxis(graphPtr); X DrawYAxis(graphPtr); X #ifdef NO_ALLOCA X ptArr = (XPoint *) ckalloc(graphPtr->maxValues * sizeof(XPoint)); #else X ptArr = (XPoint *) alloca(graphPtr->maxValues * sizeof(XPoint)); #endif X if (ptArr == NULL) { X Tcl_AppendResult(graphPtr->interp, "alloc:", sys_errlist[errno], X ": Can't allocate array of points", NULL); X return TCL_ERROR; X } X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId)) { X /* Must have both X and Y values */ X numValues = MIN(linePtr->x.numValues, linePtr->y.numValues); X if (numValues < 1) X continue; X xvaluePtr = linePtr->x.valueArr, yvaluePtr = linePtr->y.valueArr; X lastx = 0.0; /* Suppress compiler warning */ X numPoints = 0; X for (n = 0; n < numValues; n++, xvaluePtr++, yvaluePtr++) { X X /* Ignore points out of range (range is [0,1] after scaling) */ X x = ScaleX(graphPtr, *xvaluePtr); X if (x < 0.0 || x > 1.0) X continue; X y = ScaleY(graphPtr, *yvaluePtr); X if (y < 0.0 || y > 1.0) X continue; X X if (LINESTYLE(linePtr->symbol)) { X if (!(graphPtr->showRetrace || linePtr->showRetrace) && X (numPoints > 0) && (x < lastx)) { X XDrawLines(Tk_Display(tkwin), draw, linePtr->gc, X ptArr, numPoints, CoordModeOrigin); X numPoints = 0; X } X ptArr[numPoints++] = Gr_Point(graphPtr, x, y); X lastx = x; X } else if (linePtr->symbol == POINT_SYMBOL) { X ptArr[numPoints++] = Gr_Point(graphPtr, x, y); X } else { X DrawSymbol(linePtr, GX(graphPtr, x), GY(graphPtr, y)); X } X } X if (numPoints > 0) { X if (LINESTYLE(linePtr->symbol)) X XDrawLines(Tk_Display(tkwin), draw, linePtr->gc, X ptArr, numPoints, CoordModeOrigin); X else if (linePtr->symbol == POINT_SYMBOL) X XDrawPoints(Tk_Display(tkwin), draw, linePtr->gc, X ptArr, numPoints, CoordModeOrigin); X } X } #ifdef NO_ALLOCA X ckfree((char *)ptArr); #endif X return TCL_OK; } X /* X * ----------------------------------------------------------------- X * X * DrawBarchart -- X * X * ----------------------------------------------------------------- X */ static int DrawBarchart(graphPtr) X register Graph *graphPtr; { X register double x, y, baseLine; X register Line *linePtr; X int w; X ListEntry *searchId; X int y0; X Drawable draw = (Drawable) graphPtr->output; X X DrawYAxis(graphPtr); X DrawXAxis(graphPtr); X baseLine = MAX(graphPtr->Y.minLimit, 0.0); /* Determine baseline */ X /* Calculate the width of each bar */ X w = (int)rint(graphPtr->X.scale * graphPtr->barWidthPct * .01 * X ((1.0 + LABEL_TICK) / (graphPtr->drawnLines.numEntries + 1))); X y0 = GY(graphPtr, ScaleY(graphPtr, baseLine)); X x = 1.0; X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId), x++) { X if (linePtr->y.numValues > 0) {/* Make sure data exists for the line */ X int h; X XPoint pt; X X y = ScaleY(graphPtr, linePtr->y.valueArr[0]); X if (y < 0.0) X y = 0.0; X else if (y > 1.0) X y = 1.0; X pt = Gr_Point(graphPtr, ScaleX(graphPtr, x), y); X h = y0 - pt.y; X if (h < 0) { X h = -h; X pt = GetBoxCoords(pt.x, pt.y, w, h, TK_ANCHOR_S); X } else { X pt = GetBoxCoords(pt.x, pt.y, w, h, TK_ANCHOR_N); X } X if (linePtr->y.valueArr[0] < 0.0) X pt.y = y0; X XFillRectangle(Tk_Display(graphPtr->tkwin), draw, linePtr->gc, X pt.x, pt.y, w, h); X } X } X return TCL_OK; } X /* X * ----------------------------------------------------------------- X * X * PostScript routines to print the graph X * X * ----------------------------------------------------------------- X */ static char lineProc[]= "/Line { % Draw solid line\n\ X % Stack: x1 y1 x2 y2\n\ X /y2 exch def\n\ X /x2 exch def\n\ X /y1 exch def\n\ X /x1 exch def\n\ X newpath\n\ X x1 y1 moveto\n\ X x2 y2 lineto\n\ X closepath\n\ X stroke\n\ } def\n"; X static char dashedStyleProc[]= "/dashedLineStyle { % Set dashed line style\n\ X [5 2] 0 setdash\n\ } def\n"; static char dottedStyleProc[]= "/dottedLineStyle { % Set dotted line style\n\ X [1 1] 0 setdash\n\ } def\n"; static char solidStyleProc[]= "/solidLineStyle { % Set solid line style\n\ X [] 0 setdash\n\ } def\n"; X static char fgColorProc[]= "/SetFgColor { % Set foreground color\n\ X % Stack: r g b\n\ X isMonochrome 1 eq { \n\ X 0 0 0 pop pop pop\n\ X } if\n\ X setrgbcolor\n\ } def\n"; static char bgColorProc[]= "/SetBgColor { % Set background color\n\ X % Stack: r g b\n\ X isMonochrome 1 eq { \n\ X 1 1 1 pop pop pop\n\ X } if\n\ X setrgbcolor\n\ } def\n"; X /* PS procedure to draw rotated text */ static char rotTextProc[]= "/RText { % Draw rotated text\n\ X % Stack: s x y r\n\ X gsave\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X /s exch def\n\ X x y translate\n\ X 0 0 moveto\n\ X 1 -1 scale\n\ X r 90 mul rotate\n\ X s show\n\ X grestore\n\ } def\n"; X /* PS procedure to create filled rectangle */ static char rectProc[]= "/Box { % Create filled rectangle\n\ X % Stack: x y w h\n\ X gsave\n\ X /h exch def\n\ X /w exch def\n\ X /y exch def\n\ X /x exch def\n\ X newpath\n\ X x y moveto\n\ X w 0 rlineto\n\ X 0 h rlineto\n\ X w neg 0 rlineto\n\ X closepath\n\ X fill\n\ X grestore\n\ } def\n"; X /* PS procedure to draw (non-rotated) text */ static char textProc[]= "/Text { % Draw text\n\ X % Stack: s x y\n\ X gsave\n\ X /y exch def\n\ X /x exch def\n\ X /s exch def\n\ X newpath\n\ X x y moveto\n\ X 1 -1 scale\n\ X closepath\n\ X s show\n\ X grestore\n\ } def\n"; X static char dottedSymProc[]= "/dotted { % Draw dotted line\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X [1 1] 0 setdash\n\ X x r sub y moveto\n\ X x r add y lineto\n\ X stroke\n\ } def\n"; X static char dashedSymProc[]= "/dashed { % Draw dashed line\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X [5 2] 0 setdash\n\ X x r sub y moveto\n\ X x r add y lineto\n\ X stroke\n\ } def\n"; X static char solidSymProc[]= "/solid { % Draw solid line\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X [] 0 setdash\n\ X x r sub y moveto\n\ X x r add y lineto\n\ X stroke\n\ } def\n"; X static char crossSymProc[]= "/cross { % Draw cross\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X x r sub y r sub moveto\n\ X x r add y r add lineto\n\ X stroke\n\ X x r sub y r add moveto\n\ X x r add y r sub lineto\n\ X stroke\n\ } def\n"; X static char plusSymProc[]= "/plus { % Draw plus\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X x r sub y moveto\n\ X x r add y lineto\n\ X stroke\n\ X x y r sub moveto\n\ X x y r add lineto\n\ X stroke\n\ } def\n"; X static char circleSymProc[]= "/circle { % Draw filled circle\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X x y moveto\n\ X newpath\n\ X x y r 0 360 arc\n\ X closepath\n\ X fill\n\ } def\n"; X static char squareSymProc[]= "/square { % Draw filled square\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X x r sub y r sub moveto\n\ X x y r r Box\n\ } def\n"; X static char diamondSymProc[]= "/diamond { % Draw filled diamond\n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X newpath\n\ X x r sub y moveto\n\ X x y r sub lineto\n\ X x r add y lineto\n\ X x y r add lineto\n\ X x r sub y lineto\n\ X closepath\n\ X fill\n\ } def\n"; X static char pointSymProc[]= "/point { % Draw filled point \n\ X % Stack: x y r\n\ X /r exch def\n\ X /y exch def\n\ X /x exch def\n\ X x 0.5 sub y 0.5 sub moveto\n\ X x y 0.5 0.5 Box\n\ } def\n"; X static char *PSRoutines[]= { X lineProc, rectProc, rotTextProc, textProc, solidStyleProc, X dashedStyleProc, dottedStyleProc, solidSymProc, dashedSymProc, X dottedSymProc, crossSymProc, plusSymProc, squareSymProc, X circleSymProc, diamondSymProc, pointSymProc, fgColorProc, bgColorProc, }; static int numRoutines = sizeof(PSRoutines) / sizeof(char *); X #define PSSETFG(f,c) \ X fprintf (f, "%g %g %g SetFgColor\n", \ X (c)->red / 65536.0, (c)->green / 65536.0, (c)->blue / 65536.0) #define PSSETBG(f,c) \ X fprintf (f, "%g %g %g SetBgColor\n", \ X (c)->red / 65536.0, (c)->green / 65536.0, (c)->blue / 65536.0) X #define PSATTR(f,t,s) \ X fprintf (f, "%d setlinewidth\n%sLineStyle\n", t, s) X #define PSRECT(f,x,y,w,h) \ X fprintf (f, "%d %d %d %d Box\n", x, y, w, h) X X /* X * ----------------------------------------------------------------- X * X * PSFont -- X * X * ----------------------------------------------------------------- X */ static void PSFont(f, dpy, fontPtr) X FILE *f; /* File to write postscript commands */ X Display *dpy; /* X display to query about atoms */ X XFontStruct *fontPtr; /* X font to query about */ { X Atom atom; X Atom foundryAtom; X register char *namePtr; X char *foundry; X int ptSize; X char *fontAtom; X X namePtr = foundry = NULL; X foundryAtom = XInternAtom(dpy, "FOUNDRY", True); X if (XGetFontProperty(fontPtr, foundryAtom, &atom)) { X foundry = XGetAtomName(dpy, atom); X } X if (XGetFontProperty(fontPtr, XA_POINT_SIZE, &ptSize) == False) { X ptSize = 120; /* Default point size */ X } X fontAtom = NULL; X namePtr = "Helvetica"; /* Default font */ X /* Handle font mappings only if foundry is Adobe */ X if (!NULLSTR(foundry) && strcmp(foundry, "Adobe") == 0) { X if (XGetFontProperty(fontPtr, XA_FAMILY_NAME, &atom)) { X fontAtom = XGetAtomName(dpy, atom); X } X if (fontAtom != NULL) { X namePtr = fontAtom; X /* Kludge for font mappings */ X if (*namePtr == 'T' && strcmp(namePtr, "Times") == 0) { X namePtr = "Times-Roman"; X } else if (*namePtr == 'N' && X strcmp(namePtr, "New Century Schoolbook") == 0) { X namePtr = "NewCenturySchlbk-Roman"; X } X } X } X fprintf(f, "/%s findfont %d scalefont setfont\n", namePtr, ptSize / 10); X /* Free atom strings */ X if (foundry != NULL) X XFree(foundry); X if (fontAtom != NULL) X XFree(fontAtom); } X /* X * -------------------------------------------------------------------------- X * X * PSPreamble X * X * The postscript preamble does a translation and scaling to make the X * units compatible. X * X * +-----------------------+ X * | 1" = 72pica | 1" left, right, top, and bottom margin X * | ------------------ur | leaving a 6.5" x 9" area. X * | | O---> | | X * | | | | | X * | | | 6.5" = 468 pica | X * | | v | | X * | | | | 468 pica X * | | 9" = 648 pica | | scaleX = --------------------------- X * | | | | Width of window X * 11" | | | | X * | ll------------------ | X * | bounding box | 648 pica X * | | scaleY = --------------------------- X * | | Height of window X * | | X * | | To retain the aspect ratio, we use only X * | | the smaller of the two scales. The Y scale X * | | is negative since the X11 Y origin is at X * +-----------------------+ the top instead of the bottom. X * 8.5" X * X * --------------------------------------------------------------------- X */ X /* Postscript coordinate mappings. */ #define PS_WIDTH_INCHES 6.5 #define PS_WIDTH_PICA 468.0 #define PS_WIDTH_MM 165.1 #define PS_HEIGHT_INCHES 9.0 #define PS_HEIGHT_PICA 648.0 #define PS_HEIGHT_MM 228.6 #define MM_PER_INCH 25.4 X #define MM_PER_INCH 25.4 X #include #include X static void PSPreamble(graphPtr, options) X Graph *graphPtr; X PSOption *options; { X int i; X double scale; X double scaleByHeight, scaleByWidth; X FILE *f = (FILE *) graphPtr->output; X long date; X char *versionID; X X scaleByHeight = PS_HEIGHT_PICA / graphPtr->psHeight; X scaleByWidth = PS_WIDTH_PICA / graphPtr->psWidth; X scale = MIN(scaleByHeight, scaleByWidth); X X fputs("%!PS-Adobe-3.0 EPSF-3.0\n", f); X fprintf(f, "%%%%Title: (%s)\n", options->fileName); X fputs("%%Pages: 1\n", f); X fputs("%%DocumentNeededResources: font Helvetica Courier\n", f); X /* Compute Landscape/Portrait sizes */ X fprintf(f, "%%%%BoundingBox: %d %d %d %d\n", X 72, /* Lower left x */ X 720 - (int)rint(graphPtr->psHeight * scale), /* Lower left y */ X 72 + (int)rint(graphPtr->psWidth * scale), /* Upper right x */ X 720); /* Upper right y */ X X versionID = Tcl_GetVar(graphPtr->interp, "tk_version", TCL_GLOBAL_ONLY); X if (versionID == NULL) X versionID = "unknown"; X fprintf(f, "%%%%Creator: %s (Tk version %s)\n", X Tk_PathName(graphPtr->tkwin), versionID); X date = time(NULL); X fprintf(f, "%%%%CreationDate: %s", ctime(&date)); X fputs("%%EndComments\n", f); X fputs("%%BeginSetup\n", f); X for (i = 0; i < numRoutines; i++) X fputs(PSRoutines[i], f); X fprintf(f, "/isMonochrome %d def\n", options->isMonochrome); X fputs("0 setlinewidth\n1 setlinecap\nsolidLineStyle\n", f); X PSFont(f, Tk_Display(graphPtr->tkwin), graphPtr->fontPtr); X if (options->isLandscape) { X fputs("540 720 translate\n-90 rotate\n", f); X } else { X fputs("72 720 translate\n", f); X } X fprintf(f, "%g -%g scale\n\n", scale, scale); X fputs("%%EndSetup\n", f); X if (!options->isMonochrome) { /* Draw background */ X PSSETBG(f, Tk_3DBorderColor(graphPtr->border)); X PSRECT(f, 0, 0, graphPtr->psWidth, graphPtr->psHeight); X } X PSSETFG(f, graphPtr->fgColor); } X /* X * ----------------------------------------------------------------- X * X * PSSymbol -- X * X * ----------------------------------------------------------------- X */ static void PSSymbol(f, linePtr, x, y) X FILE *f; X Line *linePtr; X int x; X int y; { X register double radius = linePtr->symbolSize / 2.0; X char *symbolName; X X symbolName = NameOfSymbol(linePtr->symbol); X fprintf(f, "%d %d %g %s\n", x, y, radius, symbolName); } X /* X * ----------------------------------------------------------------- X * X * PSText -- X * X * ----------------------------------------------------------------- X */ static void PSText(graphPtr, fontPtr, text, x, y, anchor) X Graph *graphPtr; X XFontStruct *fontPtr; X char *text; X int x; X int y; X Tk_Anchor anchor; { X if (!NULLSTR(text)) { X XPoint newPt; X FILE *f = (FILE *) graphPtr->output; X X PSFont(f, Tk_Display(graphPtr->tkwin), fontPtr); X newPt = GetTextCoords(fontPtr, text, x, y, anchor, ROTATE_0); X fprintf(f, "(%s) %d %d Text\n", text, newPt.x, newPt.y); X } } X /* X * ----------------------------------------------------------------- X * X * PSRotatedText -- X * X * ----------------------------------------------------------------- X */ static void PSRotatedText(graphPtr, fontPtr, fgColor, bgColor, X text, x, y, rotation, anchor) X Graph *graphPtr; X XFontStruct *fontPtr; X XColor *fgColor, *bgColor; X char *text; X int x; X int y; X int rotation; X Tk_Anchor anchor; { X if (!NULLSTR(text)) { X int quadrant; X FILE *f = (FILE *) graphPtr->output; X XPoint newPt; X X quadrant = Quadrant(rotation); /* Compute quadrant */ X newPt = GetTextCoords(fontPtr, text, x, y, anchor, quadrant); X PSFont(f, Tk_Display(graphPtr->tkwin), fontPtr); X PSSETFG(f, fgColor); /* Set text color */ X fprintf(f, "(%s) %d %d %d RText\n", text, newPt.x, newPt.y, quadrant); X } } X /* X * ----------------------------------------------------------------- X * X * PSLine-- X * X * ----------------------------------------------------------------- X */ static void PSLine(graphPtr, x1, y1, x2, y2) X Graph *graphPtr; X double x1, y1, x2, y2; { X XSegment seg; X FILE *f = (FILE *) graphPtr->output; X X seg = Gr_Segment(graphPtr, x1, y1, x2, y2); X fprintf(f, "%d %d %d %d Line\n", seg.x1, seg.y1, seg.x2, seg.y2); } X /* X * ----------------------------------------------------------------- X * X * PSTags -- X * X * ----------------------------------------------------------------- X */ static void PSTags(graphPtr) X Graph *graphPtr; { X ListEntry *searchID; X register Tag *tagPtr; X FILE *f = (FILE *) graphPtr->output; X X for (tagPtr = (Tag *) FirstListEntry(&(graphPtr->tags), &searchID); X tagPtr != NULL; tagPtr = (Tag *) NextListEntry(&searchID)) { X if (!NULLSTR(tagPtr->text) || (tagPtr->bitmap == None)) { X double x, y; X X /* X * If tag is associated with a particular line, see if that line X * is to be plotted. If not, skip drawing the tag. X */ X if (!NULLSTR(tagPtr->lineName) && X (FindListEntry(&(graphPtr->drawnLines), X tagPtr->lineName) == NULL)) X continue; X x = ScaleX(graphPtr, tagPtr->x), y = ScaleY(graphPtr, tagPtr->y); X PSSETFG(f, tagPtr->fgColor); X PSRotatedText(graphPtr, tagPtr->fontPtr, X tagPtr->fgColor, tagPtr->bgColor, tagPtr->text, X GX(graphPtr, x), GY(graphPtr, y), X tagPtr->rotation, tagPtr->anchor); X } X } } X /* X * ----------------------------------------------------------------- X * X * PSLegend -- X * X * ----------------------------------------------------------------- X */ static void PSLegend(graphPtr) X Graph *graphPtr; { X FILE *f = (FILE *) graphPtr->output; X register int x, y; X register Line *linePtr; X Legend *legendPtr; X XPoint pt; X Tk_Anchor anchor; X ListEntry *searchId; X int fontHeight; X char *symbolName; X X legendPtr = &(graphPtr->legend); X if (!legendPtr->isVisible || legendPtr->numEntries == 0) X return; X if (legendPtr->usePosition) { X X /* X * Legend position was given in screen coordinates, so we have to X * scale it into postscript coordinates X */ X x = (int)rint(legendPtr->x * X ((double)graphPtr->psWidth / graphPtr->width)); X y = (int)rint(legendPtr->y * X ((double)graphPtr->psHeight / graphPtr->height)); X if (x < 0) X x += graphPtr->psWidth - legendPtr->width; X if (y < 0) X y += graphPtr->psHeight - legendPtr->height; X anchor = TK_ANCHOR_NW; X } else { X x = graphPtr->psWidth - (legendPtr->borderWidth + 3 * PADX); X y = GY(graphPtr, 0.95); X anchor = TK_ANCHOR_NE; X } X pt = GetBoxCoords(x, y, legendPtr->width, legendPtr->height, anchor); X if (legendPtr->borderWidth > 0) { X PSSETBG(f, Tk_3DBorderColor(legendPtr->border)); X PSRECT(f, pt.x, pt.y, legendPtr->width, legendPtr->height); X } X fontHeight = FONTHEIGHT(graphPtr->fontPtr); X y = pt.y + PADY + fontHeight / 2 + legendPtr->borderWidth; X x = pt.x + PADX + legendPtr->borderWidth; X X /* Print the symbol and label associated with the line */ X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId)) { X if (!NULLSTR(linePtr->label)) { X /* Set the line color, type and thickness */ X symbolName = "solid"; X if (LINESTYLE(linePtr->symbol)) { X symbolName = NameOfSymbol(linePtr->symbol); X } X PSSETFG(f, linePtr->fgColor); X PSSymbol(f, linePtr, x + legendPtr->maxSymSize / 2, y); X PSSETFG(f, graphPtr->fgColor); X PSText(graphPtr, graphPtr->fontPtr, linePtr->label, X x + legendPtr->maxSymSize + 2 * PADX, y, TK_ANCHOR_W); X y += fontHeight; X } X } } X /* X * ----------------------------------------------------------------- X * X * PSXAxis -- X * X * ----------------------------------------------------------------- X */ static void PSXAxis(graphPtr) X Graph *graphPtr; { X FILE *f = (FILE *) graphPtr->output; X Axis *axisPtr = &(graphPtr->X); X register int i, j; X double x; X int y; X char tickLabel[80]; X X /* Set the line color, type and thickness */ X PSSETFG(f, graphPtr->numberFg); X PSATTR(f, graphPtr->axisThickness, "solid"); X /* Axis without ticks */ X PSLine(graphPtr, 0.0, 0.0, 1.0, 0.0); X X /* Draw the X label */ X if (!NULLSTR(axisPtr->label)) { X y = graphPtr->psHeight; X y -= (PADY + graphPtr->borderWidth + FONTHEIGHT(graphPtr->fontPtr) / 2); X PSText(graphPtr, graphPtr->fontPtr, axisPtr->label, X GX(graphPtr, 0.5), y, TK_ANCHOR_CENTER); X } X if ((axisPtr->major.numSteps > 0) && (axisPtr->major.stepSize > 0.0)) { X double subValue; X double value; X Line *linePtr; X ListEntry *searchId; X X if (!(axisPtr->logScale) && (axisPtr->minor.numSteps > 0)) { X subValue = axisPtr->minor.low; X for (j = 1; j < axisPtr->minor.numSteps; j++) { X if (subValue >= axisPtr->major.low) X break; X x = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, x, 0.0, x, -MINOR_TICK); X subValue += axisPtr->minor.stepSize; X } X } X if (graphPtr->type == BARCHART_TYPE) { X y = graphPtr->height - (graphPtr->borderWidth + X FONTHEIGHT(graphPtr->fontPtr) + 2 * PADY); X } else { X y = GY(graphPtr, -LABEL_TICK); X } X value = axisPtr->major.low; X linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X for (i = 0; i < axisPtr->major.numSteps; i++) { X /* Clean up labels */ X value = ROUND(value, axisPtr->major.stepSize); X /* Scale the tick value [0..1] */ X x = ((value - axisPtr->minLimit) / axisPtr->range); X X if (graphPtr->type == BARCHART_TYPE) { X if (!NULLSTR(linePtr->label)) { X PSRotatedText(graphPtr, graphPtr->fontPtr, X graphPtr->fgColor, linePtr->bgColor, X linePtr->label, GX(graphPtr, x), y, X graphPtr->xrotation, TK_ANCHOR_S); X } X linePtr = (Line *) NextListEntry(&searchId); X } else { X /* Draw numeric value string at each major tick */ X FormatLabel(axisPtr->logScale, value, tickLabel); X PSText(graphPtr, graphPtr->numberFontPtr, tickLabel, X GX(graphPtr, x), y, TK_ANCHOR_N); X } X PSSETFG(f, graphPtr->numberFg); X PSLine(graphPtr, x, 0.0, x, -MAJOR_TICK); X X if ((axisPtr->minor.numSteps > 0) && (value < axisPtr->maxLimit)) { X if (axisPtr->logScale) { X subValue = value; X for (j = 1; j < 9; j++) { X subValue = value + logTable[j]; X x = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, x, 0.0, x, -MAJOR_TICK * logTable[j]); X } X } else { X subValue = value + axisPtr->minor.stepSize; X for (j = 1; (j < axisPtr->minor.numSteps) && X (subValue <= axisPtr->maxLimit); j++) { X x = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, x, 0.0, x, -MINOR_TICK); X subValue += axisPtr->minor.stepSize; X } X } X } X value += axisPtr->major.stepSize; X } X } } X /* X * ----------------------------------------------------------------- X * X * PSYAxis -- X * X * ----------------------------------------------------------------- X */ static void PSYAxis(graphPtr) X Graph *graphPtr; { X FILE *f = (FILE *) graphPtr->output; X Axis *axisPtr = &(graphPtr->Y); X register int i, j; X double y; X int x; X char tickLabel[80]; X X /* Set the line color, type and thickness */ X PSSETFG(f, graphPtr->numberFg); X PSATTR(f, graphPtr->axisThickness, "solid"); X /* Axis without ticks */ X PSLine(graphPtr, 0.0, 0.0, 0.0, 1.0); X X /* Y Axis label */ X if (!NULLSTR(axisPtr->label)) { X x = PADX + graphPtr->borderWidth + FONTHEIGHT(graphPtr->fontPtr) / 2; X PSRotatedText(graphPtr, graphPtr->fontPtr, graphPtr->numberFg, X Tk_3DBorderColor(graphPtr->border), axisPtr->label, X x, GY(graphPtr, 0.5), 90, TK_ANCHOR_CENTER); X } X /* Major and minor ticks, including tick labels */ X if ((axisPtr->major.numSteps > 0) && (axisPtr->major.stepSize > 0.0)) { X double subValue; X double value; X X if (!(axisPtr->logScale) && (axisPtr->minor.numSteps > 0)) { X subValue = axisPtr->minor.low; X for (j = 1; j < axisPtr->minor.numSteps; j++) { X if (subValue >= axisPtr->major.low) X break; X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, 0.0, y, -MINOR_TICK, y); X subValue += axisPtr->minor.stepSize; X } X } X x = GX(graphPtr, -LABEL_TICK); X value = axisPtr->major.low; X for (i = 0; i < axisPtr->major.numSteps; i++) { X /* Clean up labels */ X value = ROUND(value, axisPtr->major.stepSize); X /* Scale the tick value [0..1] */ X y = ((value - axisPtr->minLimit) / axisPtr->range); X FormatLabel(axisPtr->logScale, value, tickLabel); X PSText(graphPtr, graphPtr->numberFontPtr, tickLabel, X x, GY(graphPtr, y), TK_ANCHOR_E); X PSLine(graphPtr, 0.0, y, -MAJOR_TICK, y); X X /* Minor ticks */ X if ((axisPtr->minor.numSteps > 0) && (value < axisPtr->maxLimit)) { X if (axisPtr->logScale) { X for (j = 1; j < 9; j++) { X subValue = value + logTable[j]; X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, 0.0, y, -MAJOR_TICK * logTable[j], y); X } X } else { X subValue = value + axisPtr->minor.stepSize; X for (j = 1; (j < axisPtr->minor.numSteps) && X (subValue <= axisPtr->maxLimit); j++) { X y = ((subValue - axisPtr->minLimit) / axisPtr->range); X PSLine(graphPtr, 0.0, y, -MINOR_TICK, y); X subValue += axisPtr->minor.stepSize; X } X } X } X value += axisPtr->major.stepSize; X } X } } X /* X *---------------------------------------------------------------------- X * X * PSGraph -- X * X * This procedure is invoked to print the graph in a file. X * X * Results: X * None. X * X * Side effects: X * Commands are output in PostScript to the file. X * X *---------------------------------------------------------------------- X */ static int PSGraph(graphPtr) X Graph *graphPtr; { X int n; X register double x, y; X int x1, y1; X register Line *linePtr; X ListEntry *searchId; X FILE *f = (FILE *) graphPtr->output; X X PSXAxis(graphPtr); X PSYAxis(graphPtr); X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId)) { X register int numPoints = 0; X int numValues; X register double *xvaluePtr, *yvaluePtr; X double lastx; X char *symbolName; X X xvaluePtr = linePtr->x.valueArr, yvaluePtr = linePtr->y.valueArr; X X lastx = 0.0; /* Suppress compiler warning */ X numValues = MIN(linePtr->x.numValues, linePtr->y.numValues); X X /* Set the line color, type and thickness */ X symbolName = "solid"; X if (LINESTYLE(linePtr->symbol)) { X symbolName = NameOfSymbol(linePtr->symbol); X } X PSSETFG(f, linePtr->fgColor); X PSATTR(f, linePtr->lineWidth, symbolName); X /* fprintf (f, "newpath\n"); */ X for (n = 0; n < numValues; n++, xvaluePtr++, yvaluePtr++) { X /* Ignore points out of range (range is [0,1] after scaling) */ X x = ScaleX(graphPtr, *xvaluePtr); X if (x < 0.0 || x > 1.0) X continue; X y = ScaleY(graphPtr, *yvaluePtr); X if (y < 0.0 || y > 1.0) X continue; X x1 = GX(graphPtr, x), y1 = GY(graphPtr, y); X if (LINESTYLE(linePtr->symbol)) { X if (!(graphPtr->showRetrace || linePtr->showRetrace) && X (numPoints > 0) && (x < lastx)) { X numPoints = 0; X fprintf(f, "stroke\n%d %d moveto\n", x1, y1); X } else { X if (numPoints == 0) X fprintf(f, "%d %d moveto\n", x1, y1); X fprintf(f, "%d %d lineto\n", x1, y1); X numPoints++; X } X lastx = x; X } else { X PSSymbol(f, linePtr, x1, y1); X } X } X fputs("stroke\n", f); X } X return TCL_OK; } X /* X * PSBargraph X * X * Each bar is calculated as X * - X axis is centered names X */ static int PSBarchart(graphPtr) X register Graph *graphPtr; { X register double x, y, baseLine; X register Line *linePtr; X int w; X ListEntry *searchId; X int y0; X FILE *f = (FILE *) graphPtr->output; X X PSYAxis(graphPtr); X PSXAxis(graphPtr); X baseLine = MAX(graphPtr->Y.minLimit, 0.0); /* Determine baseline */ X /* Calculate the width of each bar */ X w = (int)rint(graphPtr->X.scale * graphPtr->barWidthPct * .01 * X ((1.0 + LABEL_TICK) / (graphPtr->drawnLines.numEntries + 1))); X y0 = GY(graphPtr, ScaleY(graphPtr, baseLine)); X x = 1.0; X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId), x++) { X if (linePtr->y.numValues > 0) {/* Make sure data exists for the line */ X int h; X XPoint newPt; X X y = ScaleY(graphPtr, linePtr->y.valueArr[0]); X if (y > 1.0) X y = 1.0; X else if (y < 0.0) X y = 0.0; X newPt = Gr_Point(graphPtr, ScaleX(graphPtr, x), y); X h = y0 - newPt.y; X if (h < 0) { X h = -h; X newPt = GetBoxCoords(newPt.x, newPt.y, w, h, TK_ANCHOR_S); X } else { X newPt = GetBoxCoords(newPt.x, newPt.y, w, h, TK_ANCHOR_N); X } X if (linePtr->y.valueArr[0] < 0.0) X newPt.y = y0; X PSSETFG(f, linePtr->fgColor); X fprintf(f, "%d %d %d %d Box\n", newPt.x, newPt.y, w, h); X } X } X return TCL_OK; } X /* X * ----------------------------------------------------------------- X * X * ComputeLayout -- X * X * Calculate the layout of the graph. Based upon the data, axis X * limits, X and Y labels, and title height, determine the cavity X * left which is the plotting surface. The first step get the data X * and axis limits for calculating the the space needed for the top, X * bottom, left, and right margins. X * X * 1) The LEFT margin is the area from the left border to the Y axis X * (not including ticks). It composes the border width, the width X * an optional Y axis label and its padding, and the tick numeric labels. X * The Y axis label is rotated 90 degrees so that the width is the X * font height. X * X * 2) The RIGHT margin is the area from the end of the graph to the X * right window border. It composes the border width, some padding, X * the font height (this may be dubious. It appears to provide a more X * even border), the max of the legend width and 1/2 max X tick number. X * This last part is so that the last tick label is not clipped. X * X * Area Width X * _____________________________________________________ X * _______________________________________________________ X * | | | | X * | | TOP height of title | | A X * |_________|_______________________________|___________| r X * | | | | e X * | LEFT | | RIGHT | a X * | | | | X * | Y | | | H X * | | PLOTTING SURFACE 105% | | e X * | l | 100 + 5% tick length | | i X * | a | | | g X * | b | | legend | h X * | e | | width | t X * | l | | | X * | | | | X * | width of| | | X * | widest | | | X * | number | | | X * | | | | X * | | | | X * | | | | X * | | origin (xoffset, yoffset) | | X * |_________|_______________________________|___________| X * | | height of number 1/2 width of | X * | | max tick number | X * | | BOTTOM height of X label | | X * |_________|_______________________________|___________| X * X * 3) The TOP margin is the area from the top window border to the top X * of the graph. It composes the border width, twice the height of X * the title font (if one is given) and some padding between the X * title. X * X * 4) The BOTTOM margin is area from the bottom window border to the X * X axis (not including ticks). It composes the border width, the height X * an optional X axis label and its padding, the height of the font X * of the tick labels. X * X * The plotting area is between the margins which includes the X and Y axes X * including the ticks but not the tick numeric labels. The length of X * the ticks and its padding is 5% of the entire plotting area. Hence the X * entire plotting area is scaled as 105% of the width and height of the X * area. X * X * The axis labels, ticks labels, title, and legend may or may not be X * displayed which must be taken into account. X * X * X * ----------------------------------------------------------------- X */ static int ComputeLayout(graphPtr, width, height) X Graph *graphPtr; X int width; /* Width of window/plot area */ X int height; /* Height of window/plot area */ { X int reqMargin = 0; X int leftMargin, rightMargin; X int topMargin, bottomMargin; X int maxTickWidth = 0; X int maxLabelWidth = 0; X int range; X int fontHeight = FONTHEIGHT(graphPtr->fontPtr); X X GetDataExtents(graphPtr); X ConfigureXAxis(graphPtr); X ConfigureYAxis(graphPtr); X X topMargin = PADY; X if (!NULLSTR(graphPtr->title)) X topMargin += ((fontHeight * 2) + PADY); X X leftMargin = PADX; X if (!NULLSTR(graphPtr->Y.label)) X leftMargin += (fontHeight + 3 * PADX); X X if (graphPtr->Y.major.numSteps > 0) { X /* Get the width of the widest Y tick label */ X leftMargin += GetTickWidth(&(graphPtr->Y), graphPtr->numberFontPtr); X } X bottomMargin = PADY; X if (!NULLSTR(graphPtr->X.label)) X bottomMargin += (fontHeight + 2 * PADY); X X rightMargin = PADX + fontHeight; /* dubious using fontHeight here */ X graphPtr->legend.width = 0; X maxLabelWidth = GetLegendExtents(graphPtr, width, height); X if (graphPtr->X.major.numSteps > 0) { X maxTickWidth = X GetTickWidth(&(graphPtr->X), graphPtr->numberFontPtr) / 2; X if (graphPtr->type == BARCHART_TYPE) { X int quadrant; X X quadrant = Quadrant(graphPtr->xrotation); /* Compute quadrant */ X bottomMargin += ((quadrant == ROTATE_270 || quadrant == ROTATE_90) X ? maxLabelWidth : fontHeight); X } else { X bottomMargin += FONTHEIGHT(graphPtr->numberFontPtr); X } X } X /* Override calculated values if user specified margins */ X if (graphPtr->leftMargin > 0) X leftMargin = graphPtr->leftMargin; X if (graphPtr->topMargin > 0) X topMargin = graphPtr->topMargin; X if (graphPtr->bottomMargin > 0) X bottomMargin = graphPtr->bottomMargin; X X reqMargin = graphPtr->rightMargin; X if ((reqMargin <= 0) && X graphPtr->legend.isVisible && !graphPtr->legend.usePosition) { X reqMargin = graphPtr->legend.width; X } X rightMargin += MAX(reqMargin, maxTickWidth); X X /* Based upon the margins, calculate the space left for the graph. */ X graphPtr->X.offset = leftMargin + graphPtr->borderWidth; X graphPtr->Y.offset = (height - (graphPtr->borderWidth + bottomMargin)); X range = width - (leftMargin + rightMargin + (2 * graphPtr->borderWidth)); X if (range < 0) { X return TCL_ERROR; X } X graphPtr->X.scale = range / (1.0 + LABEL_TICK); /* Pixels per X unit */ X range = height - (topMargin + bottomMargin + (2 * graphPtr->borderWidth)); X if (range < 0) { X return TCL_ERROR; X } X graphPtr->Y.scale = range / (1.0 + LABEL_TICK); /* Pixels per Y unit */ X X /* Add tick distance to center graph */ X graphPtr->X.offset += (int)rint(LABEL_TICK * graphPtr->X.scale); X graphPtr->Y.offset -= (int)rint(LABEL_TICK * graphPtr->Y.scale); X return TCL_OK; } X /* X *-------------------------------------------------------------- X * X * GraphLimits -- X * X * This procedure returns a list of the axis limits for X * the graph. The format is { xmin xmax ymin ymax}. X * X * Results: X * Always returns TCL_OK. The interp->result field is X * a list of the graph axis limits. X * X *-------------------------------------------------------------- X */ static int GraphLimits(interp, graphPtr) X Tcl_Interp *interp; X Graph *graphPtr; { X char *fmt; X char buf[80]; X X /* Until there is global OFMT variable */ X fmt = "%.10g"; X if (graphPtr->type == XYGRAPH_TYPE) { X sprintf(buf, fmt, graphPtr->X.minLimit); /* X min */ X Tcl_AppendElement(interp, buf, FALSE); X sprintf(buf, fmt, graphPtr->X.maxLimit); /* X max */ X Tcl_AppendElement(interp, buf, FALSE); X } X sprintf(buf, fmt, graphPtr->Y.minLimit); /* Y min */ X Tcl_AppendElement(interp, buf, FALSE); X sprintf(buf, fmt, graphPtr->Y.maxLimit); /* Y max */ X Tcl_AppendElement(interp, buf, FALSE); X return TCL_OK; } X /* X *-------------------------------------------------------------- X * X * GraphLocate -- X * X * This procedure returns a list of the graph coordinate X * values corresponding with the given screen X and Y X * coordinate positions. X * X * Results: X * Returns a standard Tcl result. The interp->result field is X * a Tcl list of the corresponding graph X and Y coordinates. X * If an error occured while parsing the screen positions, X * TCL_ERROR is returned, and interp->result will contain X * the error message. X * X *-------------------------------------------------------------- X */ static int GraphLocate(interp, graphPtr, screenX, screenY) X Tcl_Interp *interp; /* Interpreter to report results back to */ X Graph *graphPtr; /* Graph widget record */ X char *screenX; /* String representing screen x coordinate */ X char *screenY; /* String representing Screen y coordinate */ { X int sx, sy; /* Convert integer screen coordinates */ X double x, y; /* Resulting graph coordinate values */ X char buf[80]; X X if (Tcl_GetInt(interp, screenX, &sx) != TCL_OK || X Tcl_GetInt(interp, screenY, &sy) != TCL_OK) { X return TCL_ERROR; X } X /* Perform the reverse transformation from screen coordinates to data */ X x = (sx - graphPtr->X.offset) / graphPtr->X.scale; X x = UnscaleX(graphPtr, x); X y = (graphPtr->Y.offset - sy) / graphPtr->Y.scale; X y = UnscaleY(graphPtr, y); X sprintf(buf, "%.15g %.15g", x, y); X Tcl_SetResult(interp, buf, TCL_VOLATILE); X return TCL_OK; } X /* X *---------------------------------------------------------------------- X * X * GraphLineNames -- X * X * Given an Tcl list of line names, this procedure rebuilds the X * visibleLine list, ignoring invalid line names. The visible X * line list contains not only which lines are to be drawn, but X * the order in which to draw them. This is really only important X * for bar and pie charts. X * X * Results: X * The return value is a standard Tcl result. Only if the X * Tcl list cannot be split, a TCL_ERROR is returned and X * interp->result contains an error message. X * X * Side effects: X * The graph is eventually redrawn using the new list of visible lines. X * X *---------------------------------------------------------------------- X */ static int GraphLineNames(interp, graphPtr, newList) X Tcl_Interp *interp; /* Interpreter to report results back to */ X Graph *graphPtr; /* Graph widget record */ X char *newList; /* Tcl list of line names */ { X int numNames; /* Number of names found in Tcl name list */ X char **nameArr; /* Broken out array of line names */ X ListEntry *searchId; /* Search token for list operations */ X register int cnt; /* */ X Line *linePtr; /* Line information record */ X X if (Tcl_SplitList(interp, newList, &numNames, &nameArr) != TCL_OK) { X Tcl_AppendResult(interp, "Can't split name list \"", newList, "\"", X NULL); X return TCL_ERROR; X } X /* X * Delete the current list of visible lines and mark each line as not X * drawn. X */ X for (linePtr = (Line *) FirstListEntry(&(graphPtr->drawnLines), &searchId); X linePtr != NULL; linePtr = (Line *) NextListEntry(&searchId)) { X linePtr->isVisible = FALSE; X DeleteListEntry(&(graphPtr->drawnLines), linePtr->name); X } X X /* X * Rebuild the list of visible lines, checking each name to make sure the X * line exists. Currently ignoring invalid names. X */ X for (cnt = 0; cnt < numNames; cnt++) { X linePtr = (Line *) FindListEntry(&(graphPtr->allLines), nameArr[cnt]); X if (linePtr != NULL) { X linePtr->isVisible = TRUE; X CreateListEntry(&(graphPtr->drawnLines), linePtr->name, linePtr); X } X } X ckfree((char *)nameArr); X return TCL_OK; } X /* X *---------------------------------------------------------------------- X * X * GraphInsert -- X * X * Add a new line to the graph. X * X * Results: X * The return value is a standard Tcl result. X * X *---------------------------------------------------------------------- X */ static int GraphInsert(interp, graphPtr, argc, argv, flags, redrawFlag) X Tcl_Interp *interp; X Graph *graphPtr; X int argc; X char **argv; X int flags; X int *redrawFlag; { X Line *linePtr; X int result; X X if (argc < 3) { X Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], X " ", argv[1], " name ?options?\"", NULL); X return TCL_ERROR; X } X linePtr = CreateLine(graphPtr, argv[2]); X if (linePtr == NULL) { X Tcl_AppendResult(interp, "Can't create \"", argv[2], "\"", NULL); X return TCL_ERROR; X } X result = ConfigureLine(interp, linePtr, argc - 3, argv + 3, flags); X if (result != TCL_OK) { X DeleteLine(interp, graphPtr, linePtr->name, redrawFlag); X return TCL_ERROR; X } X *redrawFlag = TRUE; X return TCL_OK; } X /* X *---------------------------------------------------------------------- X * X * GraphNewTag -- X * X * Add a new tag to the graph. X * X * Results: X * The return value is a standard Tcl result. X * X * Side effects: X * The graph is eventually redrawn with the new tag. X * X *---------------------------------------------------------------------- X */ static int GraphNewTag(interp, graphPtr, argc, argv, flags, redrawFlag) X Tcl_Interp *interp; X Graph *graphPtr; X int argc; X char **argv; X int flags; X int *redrawFlag; { X Tag *tagPtr; X int result; X double x, y; X X if (argc < 5) { X Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], X " ", argv[1], " name x y ?options?\"", NULL); X return TCL_ERROR; X } X /* Get X and Y coordinates */ X if (GetExprValue (interp, argv[3], &x) != TCL_OK || X GetExprValue (interp, argv[4], &y) != TCL_OK) { X return TCL_ERROR; X } X tagPtr = CreateTag(graphPtr, argv[2], x, y); X if (tagPtr == NULL) X return TCL_ERROR; X result = ConfigureTag(interp, graphPtr, tagPtr, argc - 5, argv + 5, flags); X if (result != TCL_OK) { X DeleteTag(interp, graphPtr, tagPtr->name, redrawFlag); X return TCL_ERROR; X } X *redrawFlag = TRUE; X return TCL_OK; } X /* X *---------------------------------------------------------------------- X * X * GraphPrint -- X * X * This procedure is invoked to print the graph in a file. X * X * Results: X * None. X * X * Side effects: X * A new postscript file is created. X * X *---------------------------------------------------------------------- X */ static int GraphPrint(interp, tkwin, graphPtr, argc, argv) X Tcl_Interp *interp; /* Interpreter to report results back to */ X Tk_Window tkwin; /* Window to use */ X Graph *graphPtr; /* Graph widget record */ X int argc; /* Number of options in argv vector */ X char **argv; /* Option vector */ { X FILE *f; X PSOption options; X int width, height; X register int i; X register char *p; X int length; X X width = height = 0; X options.isLandscape = options.isCentered = options.isMonochrome = FALSE; X if (graphPtr->drawnLines.numEntries <= 0) { X Tcl_AppendResult(interp, "No lines are visible in ", X Tk_PathName(tkwin), (char *)NULL); X return TCL_ERROR; X } X options.geometry = NULL; X /* Process arguments */ X f = fopen(argv[1], "w"); X if (f == NULL) { X Tcl_AppendResult(interp, "Can't open \"", argv[1], "\"", NULL); X Tcl_SetErrorCode(interp, "UNIX", "fopen", sys_errlist[errno], NULL); X return TCL_ERROR; X } X graphPtr->output = (ClientData) f; X options.fileName = argv[1]; X for (i = 2; i < argc; i++) { X p = argv[i]; X length = strlen(argv[i]) - 1; X if (*p++ == '-') { X if (*p == 'm' && strncmp(p, "monochrome", length) == 0) X options.isMonochrome = TRUE; X else if (*p == 'c' && strncmp(p, "centered", length) == 0) X options.isCentered = TRUE; X else if (*p == 'l' && strncmp(p, "landscape", length) == 0) X options.isLandscape = TRUE; X else if (*p == 'g' && strncmp(p, "geometry", length) == 0) { X if (++i < argc) { X p = strchr(argv[i], 'x'); X if (p == NULL) { X Tcl_AppendResult(interp, "Bad geometry: should be \"", X argv[i - 1], " widthxheight\"", (char *)NULL); SHAR_EOF : || echo 'restore of snmp2/snmptcl/graph.c failed' fi echo 'End of snmp2 part 25' echo 'File snmp2/snmptcl/graph.c is continued in part 26' echo 26 > _sharseq.tmp exit 0