v03i073: xgraph -- graph points and functions, Part04/06
Dan Heller
argv at island.uu.net
Tue Apr 11 10:43:44 AEST 1989
Submitted-by: David Harrison <davidh at ic.berkeley.edu>
Posting-number: Volume 3, Issue 73
Archive-name: xgraph/part04
#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./xgraph-11`
then
mkdir ./xgraph-11
echo "mkdir ./xgraph-11"
fi
if `test ! -s ./xgraph-11/xgraph.c`
then
echo "writing ./xgraph-11/xgraph.c"
cat > ./xgraph-11/xgraph.c << '\End\Of\Shar\'
/*
* xgraph - A Simple Plotter for X
*
* David Harrison
* University of California, Berkeley
* 1986, 1987, 1988, 1989
*
* Please see copyright.h concerning the formal reproduction rights
* of this software.
*/
#include "copyright.h"
#include <stdio.h>
#include <math.h>
#include <pwd.h>
#include <ctype.h>
#include "xgout.h"
#include "xgraph.h"
#include "xtb.h"
#include "hard_devices.h"
#include <X11/Xutil.h>
#define ZOOM
#define TOOLBOX
#ifndef MAXFLOAT
#define MAXFLOAT HUGE
#endif
#define BIGINT 0xfffffff
#define GRIDPOWER 10
#define INITSIZE 128
#define CONTROL_D '\004'
#define CONTROL_C '\003'
#define TILDE '~'
#define BTNPAD 1
#define BTNINTER 3
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define ABS(x) ((x) < 0 ? -(x) : (x))
#define ZERO_THRES 1.0E-07
/* To get around an inaccurate log */
#define nlog10(x) (x == 0.0 ? 0.0 : log10(x) + 1e-15)
#define ISCOLOR (wi->dev_info.dev_flags & D_COLOR)
#define PIXVALUE(set) ((set) % MAXATTR)
#define LINESTYLE(set) \
(ISCOLOR ? ((set)/MAXATTR) : ((set) % MAXATTR))
#define MARKSTYLE(set) \
(colorMark ? COLMARK(set) : BWMARK(set))
#define COLMARK(set) \
((set) / MAXATTR)
#define BWMARK(set) \
((set) % MAXATTR)
extern void init_X();
#ifdef TOOLBOX
extern void do_error();
#endif
static char *tildeExpand();
AttrSet AllAttrs[MAXATTR];
typedef struct data_set {
char *setName; /* Name of set */
int numPoints; /* How many points */
int allocSize; /* Allocated size */
double *xvec; /* X values */
double *yvec; /* Y values */
} DataSet;
static DataSet AllSets[MAXSETS];
static XSegment *Xsegs; /* Point space for X */
/* Basic transformation stuff */
static double llx, lly, urx, ury; /* Bounding box of all data */
typedef struct local_win {
double loX, loY, hiX, hiY; /* Local bounding box of window */
int XOrgX, XOrgY; /* Origin of bounding box on screen */
int XOppX, XOppY; /* Other point defining bounding box */
double UsrOrgX, UsrOrgY; /* Origin of bounding box in user space */
double UsrOppX, UsrOppY; /* Other point of bounding box */
double XUnitsPerPixel; /* X Axis scale factor */
double YUnitsPerPixel; /* Y Axis scale factor */
xgOut dev_info; /* Device information */
Window close, hardcopy; /* Buttons for closing and hardcopy */
} LocalWin;
#define SCREENX(ws, userX) \
(((int) (((userX) - ws->UsrOrgX)/ws->XUnitsPerPixel + 0.5)) + ws->XOrgX)
#define SCREENY(ws, userY) \
(ws->XOppY - ((int) (((userY) - ws->UsrOrgY)/ws->YUnitsPerPixel + 0.5)))
static XContext win_context = (XContext) 0;
/* Other globally set defaults */
Display *disp; /* Open display */
Visual *vis; /* Standard visual */
Colormap cmap; /* Standard colormap */
int screen; /* Screen number */
int depth; /* Depth of screen */
int install_flag; /* Install colormaps */
Pixel black_pixel; /* Actual black pixel */
Pixel white_pixel; /* Actual white pixel */
Pixel bgPixel; /* Background color */
int bdrSize; /* Width of border */
Pixel bdrPixel; /* Border color */
Pixel zeroPixel; /* Zero grid color */
int zeroWidth; /* Width of zero line */
char zeroLS[MAXLS]; /* Line style spec */
int zeroLSLen; /* Length of zero LS spec */
Pixel normPixel; /* Norm grid color */
int axisWidth; /* Width of axis line */
char axisLS[MAXLS]; /* Axis line style spec */
int axisLSLen; /* Length of axis line style */
Pixel echoPix; /* Echo pixel value */
XFontStruct *axisFont; /* Font for axis labels */
XFontStruct *titleFont; /* Font for title labels */
char titleText[MAXBUFSIZE]; /* Plot title */
char XUnits[MAXBUFSIZE]; /* X Unit string */
char YUnits[MAXBUFSIZE]; /* Y Unit string */
int bwFlag; /* Black and white flag */
int tickFlag; /* Don't draw full grid */
int bbFlag; /* Whether to draw bb */
int noLines; /* Don't draw lines */
int markFlag; /* Draw marks at points */
int pixelMarks; /* Draw pixel markers */
int bigPixel; /* Draw big pixels */
int colorMark; /* Normal markers track color */
int logXFlag; /* Logarithmic X axis */
int logYFlag; /* Logarithmic Y axis */
int barFlag; /* Draw bar graph */
double barBase, barWidth; /* Base and width of bars */
int lineWidth; /* Width of data lines */
char *geoSpec = ""; /* Geometry specification */
int numFiles = 0; /* Number of input files */
char *inFileNames[MAXSETS]; /* File names */
char *Odevice = ""; /* Output device */
char *Odisp = "To Device"; /* Output disposition */
char *OfileDev = ""; /* Output file or device */
int debugFlag = 0; /* Whether debugging is on */
/* Possible user specified bounding box */
static double UsrLX, UsrLY, UsrRX, UsrRY;
/* Total number of active windows */
static int Num_Windows = 0;
static char *Prog_Name;
/*
* Marker bitmaps
*/
#include "dot.11"
#include "mark1.11"
#include "mark2.11"
#include "mark3.11"
#include "mark4.11"
#include "mark5.11"
#include "mark6.11"
#include "mark7.11"
#include "mark8.11"
/* Sizes exported for marker drawing */
unsigned int dot_w = dot_width;
unsigned int dot_h = dot_height;
unsigned int mark_w = mark1_width;
unsigned int mark_h = mark1_height;
int mark_cx = mark1_x_hot;
/* Contrary to what lint says, these are used in xgX.c */
int mark_cy = mark1_y_hot;
Pixmap dotMap = (Pixmap) 0;
static int XErrHandler(); /* Handles error messages */
main(argc, argv)
int argc;
char *argv[];
/*
* This sets up the hard-wired defaults and reads the X defaults.
* The command line format is: xgraph [host:display].
*/
{
Window primary, NewWindow();
XEvent theEvent;
LocalWin *win_info;
Cursor zoomCursor;
FILE *strm;
XColor fg_color, bg_color;
char keys[MAXKEYS];
int nbytes, idx, maxitems;
/* Open up new display */
Prog_Name = argv[0];
disp = ux11_open_display(argc, argv);
XSetErrorHandler(XErrHandler);
/* Set up hard-wired defaults and allocate spaces */
InitSets();
/* Read X defaults and override hard-coded defaults */
ReadDefaults();
/* Parse the argument list */
ParseArgs(argc, argv);
/* Read the data into the data sets */
llx = lly = MAXFLOAT;
urx = ury = -MAXFLOAT;
for (idx = 0; idx < numFiles; idx++) {
strm = fopen(inFileNames[idx], "r");
if (!strm) {
(void) fprintf(stderr, "Warning: cannot open file `%s'\n",
inFileNames[idx]);
} else {
if ((maxitems = ReadData(strm, inFileNames[idx])) < 0) {
(void) fprintf(stderr, "data formatting error\n");
exit(1);
}
(void) fclose(strm);
}
}
if (!numFiles) {
if ((maxitems = ReadData(stdin, (char *) 0)) < 0) {
(void) fprintf(stderr, "data formatting error\n");
exit(1);
}
}
Xsegs = (XSegment *) malloc((unsigned) (maxitems * sizeof(XSegment)));
/* Nasty hack here for bar graphs */
if (barFlag) {
llx -= barWidth;
urx += barWidth;
}
/* Create initial window */
#ifdef TOOLBOX
xtb_init(disp, screen, normPixel, bgPixel, axisFont);
#endif
primary = NewWindow(Prog_Name, UsrLX, UsrLY, UsrRX, UsrRY, 1.0);
if (!primary) {
(void) fprintf(stderr, "Main window would not open\n");
exit(1);
}
zoomCursor = XCreateFontCursor(disp, XC_sizing);
fg_color.pixel = normPixel;
XQueryColor(disp, cmap, &fg_color);
bg_color.pixel = bgPixel;
XQueryColor(disp, cmap, &bg_color);
XRecolorCursor(disp, zoomCursor, &fg_color, &bg_color);
Num_Windows = 1;
while (Num_Windows > 0) {
XNextEvent(disp, &theEvent);
#ifdef TOOLBOX
if (xtb_dispatch(&theEvent) != XTB_NOTDEF) continue;
#endif
if (XFindContext(theEvent.xany.display,
theEvent.xany.window,
win_context, (caddr_t *) &win_info)) {
/* Nothing found */
continue;
}
switch (theEvent.type) {
case Expose:
#ifdef PEXPOSE
printf("expose: ");
if (theEvent.xexpose.send_event) {
printf(" sendevent");
}
printf(" win=0x%x x=%d y=%d width=%d height=%d count=%d\n",
theEvent.xexpose.window, theEvent.xexpose.x,
theEvent.xexpose.y, theEvent.xexpose.width,
theEvent.xexpose.height, theEvent.xexpose.count);
#endif
if (theEvent.xexpose.count <= 0) {
XWindowAttributes win_attr;
XGetWindowAttributes(disp, theEvent.xany.window, &win_attr);
win_info->dev_info.area_w = win_attr.width;
win_info->dev_info.area_h = win_attr.height;
init_X(win_info->dev_info.user_state);
DrawWindow(win_info);
}
break;
case KeyPress:
nbytes = XLookupString(&theEvent.xkey, keys, MAXKEYS,
(KeySym *) 0, (XComposeStatus *) 0);
for (idx = 0; idx < nbytes; idx++) {
if (keys[idx] == CONTROL_D) {
/* Delete this window */
DelWindow(theEvent.xkey.window, win_info);
} else if (keys[idx] == CONTROL_C) {
/* Exit program */
Num_Windows = 0;
} else if (keys[idx] == 'h') {
#ifdef TOOLBOX
PrintWindow(theEvent.xany.window, win_info);
#endif
}
}
break;
case ButtonPress:
/* Handle creating a new window */
#ifdef ZOOM
Num_Windows += HandleZoom(Prog_Name,
&theEvent.xbutton,
win_info, zoomCursor);
#endif
break;
default:
(void) fprintf(stderr, "Unknown event type: %x\n", theEvent.type);
break;
}
}
exit(0);
}
#ifdef TOOLBOX
/*
* Button handling functions
*/
/*ARGSUSED*/
xtb_hret del_func(win, bval, info)
Window win; /* Button window */
int bval; /* Button value */
char *info; /* User information */
/*
* This routine is called when the `Close' button is pressed in
* an xgraph window. It causes the window to go away.
*/
{
Window the_win = (Window) info;
LocalWin *win_info;
xtb_bt_set(win, 1, (char *) 0);
if (!XFindContext(disp, the_win, win_context, (caddr_t *) &win_info)) {
DelWindow(the_win, win_info);
}
return XTB_HANDLED;
}
/*ARGSUSED*/
xtb_hret hcpy_func(win, bval, info)
Window win; /* Button Window */
int bval; /* Button value */
char *info; /* User Information */
/*
* This routine is called when the hardcopy button is pressed
* in an xgraph window. It causes the output dialog to be
* posted.
*/
{
Window the_win = (Window) info;
LocalWin *win_info;
xtb_bt_set(win, 1, (char *) 0);
if (!XFindContext(disp, the_win, win_context, (caddr_t *) &win_info)) {
PrintWindow(the_win, win_info);
}
xtb_bt_set(win, 0, (char *) 0);
return XTB_HANDLED;
}
#endif
#define NORMSIZE 600
#define MINDIM 100
Window NewWindow(progname, lowX, lowY, upX, upY, asp)
char *progname; /* Name of program */
double lowX, lowY; /* Lower left corner */
double upX, upY; /* Upper right corner */
double asp; /* Aspect ratio */
/*
* Creates and maps a new window. This includes allocating its
* local structure and associating it with the XId for the window.
* The aspect ratio is specified as the ratio of width over height.
*/
{
Window new_window;
LocalWin *new_info;
static Cursor theCursor = (Cursor) 0;
XSizeHints sizehints;
XSetWindowAttributes wattr;
XWMHints wmhints;
XColor fg_color, bg_color;
int geo_mask;
int width, height;
unsigned long wamask;
char defSpec[120];
double pad;
new_info = (LocalWin *) malloc(sizeof(LocalWin));
if (upX > lowX) {
new_info->loX = lowX;
new_info->hiX = upX;
} else {
new_info->loX = llx;
new_info->hiX = urx;
}
if (upY > lowY) {
new_info->loY = lowY;
new_info->hiY = upY;
} else {
new_info->loY = lly;
new_info->hiY = ury;
}
/* Increase the padding for aesthetics */
if (new_info->hiX - new_info->loX == 0.0) {
pad = MAX(0.5, fabs(new_info->hiX/2.0));
new_info->hiX += pad;
new_info->loX -= pad;
}
if (new_info->hiY - new_info->loY == 0) {
pad = MAX(0.5, fabs(ury/2.0));
new_info->hiY += pad;
new_info->loY -= pad;
}
/* Add 10% padding to bounding box (div by 20 yeilds 5%) */
pad = (new_info->hiX - new_info->loX) / 20.0;
new_info->loX -= pad; new_info->hiX += pad;
pad = (new_info->hiY - new_info->loY) / 20.0;
new_info->loY -= pad; new_info->hiY += pad;
/* Aspect ratio computation */
if (asp < 1.0) {
height = NORMSIZE;
width = ((int) (((double) NORMSIZE) * asp));
} else {
width = NORMSIZE;
height = ((int) (((double) NORMSIZE) / asp));
}
height = MAX(MINDIM, height);
width = MAX(MINDIM, width);
(void) sprintf(defSpec, "%dx%d+100+100", width, height);
wamask = ux11_fill_wattr(&wattr, CWBackPixel, bgPixel,
CWBorderPixel, bdrPixel,
CWColormap, cmap, UX11_END);
sizehints.flags = PPosition|PSize;
sizehints.x = sizehints.y = 100;
sizehints.width = width;
sizehints.height = height;
new_window = XCreateWindow(disp, RootWindow(disp, screen),
sizehints.x, sizehints.y,
(unsigned int) sizehints.width,
(unsigned int) sizehints.height,
(unsigned int) bdrSize,
depth, InputOutput, vis,
wamask, &wattr);
if (new_window) {
xtb_frame cl_frame, hd_frame;
XStoreName(disp, new_window, progname);
XSetIconName(disp, new_window, progname);
wmhints.flags = InputHint | StateHint;
wmhints.input = True;
wmhints.initial_state = NormalState;
XSetWMHints(disp, new_window, &wmhints);
geo_mask = XParseGeometry(geoSpec, &sizehints.x, &sizehints.y,
(unsigned int *) &sizehints.width,
(unsigned int *) &sizehints.height);
if (geo_mask & (XValue | YValue)) {
sizehints.flags = (sizehints.flags & ~PPosition) | USPosition;
}
if (geo_mask & (WidthValue | HeightValue)) {
sizehints.flags = (sizehints.flags & ~PSize) | USSize;
}
XSetNormalHints(disp, new_window, &sizehints);
/* Set device info */
set_X(new_window, &(new_info->dev_info));
#ifdef TOOLBOX
/* Make buttons */
xtb_bt_new(new_window, "Close", del_func,
(xtb_data) new_window, &cl_frame);
new_info->close = cl_frame.win;
XMoveWindow(disp, new_info->close, (int) BTNPAD, (int) BTNPAD);
xtb_bt_new(new_window, "Hardcopy", hcpy_func,
(xtb_data) new_window, &hd_frame);
new_info->hardcopy = hd_frame.win;
XMoveWindow(disp, new_info->hardcopy,
(int) (BTNPAD + cl_frame.width + BTNINTER),
BTNPAD);
#endif
XSelectInput(disp, new_window,
ExposureMask|KeyPressMask|ButtonPressMask);
if (!theCursor) {
theCursor = XCreateFontCursor(disp, XC_top_left_arrow);
fg_color.pixel = normPixel;
XQueryColor(disp, cmap, &fg_color);
bg_color.pixel = bgPixel;
XQueryColor(disp, cmap, &bg_color);
XRecolorCursor(disp, theCursor, &fg_color, &bg_color);
}
XDefineCursor(disp, new_window, theCursor);
if (!win_context) {
win_context = XUniqueContext();
}
XSaveContext(disp, new_window, win_context, (caddr_t) new_info);
XMapWindow(disp, new_window);
return new_window;
} else {
return (Window) 0;
}
}
DelWindow(win, win_info)
Window win; /* Window */
LocalWin *win_info; /* Local Info */
/*
* This routine actually deletes the specified window and
* decrements the window count.
*/
{
xtb_data info;
XDeleteContext(disp, win, win_context);
#ifdef TOOLBOX
xtb_bt_del(win_info->close, &info);
xtb_bt_del(win_info->hardcopy, &info);
#endif
free((char *) win_info);
XDestroyWindow(disp, win);
Num_Windows -= 1;
}
#ifdef TOOLBOX
PrintWindow(win, win_info)
Window win; /* Window */
LocalWin *win_info; /* Local Info */
/*
* This routine posts a dialog asking about the hardcopy
* options desired. If the user hits `OK', the hard
* copy is performed.
*/
{
ho_dialog(win, Prog_Name, (char *) win_info);
}
#endif
#ifdef ZOOM
static XRectangle boxEcho;
static GC echoGC = (GC) 0;
#define DRAWBOX \
if (startX < curX) { \
boxEcho.x = startX; \
boxEcho.width = curX - startX; \
} else { \
boxEcho.x = curX; \
boxEcho.width = startX - curX; \
} \
if (startY < curY) { \
boxEcho.y = startY; \
boxEcho.height = curY - startY; \
} else { \
boxEcho.y = curY; \
boxEcho.height = startY - curY; \
} \
XDrawRectangles(disp, win, echoGC, &boxEcho, 1);
#endif
#define TRANX(xval) \
(((double) ((xval) - wi->XOrgX)) * wi->XUnitsPerPixel + wi->UsrOrgX)
#define TRANY(yval) \
(wi->UsrOppY - (((double) ((yval) - wi->XOrgY)) * wi->YUnitsPerPixel))
#ifdef ZOOM
int HandleZoom(progname, evt, wi, cur)
char *progname;
XButtonPressedEvent *evt;
LocalWin *wi;
Cursor cur;
{
Window win, new_win;
Window root_rtn, child_rtn;
XEvent theEvent;
int startX, startY, curX, curY, newX, newY, stopFlag, numwin;
int root_x, root_y;
unsigned int mask_rtn;
double loX, loY, hiX, hiY, asp;
win = evt->window;
if (XGrabPointer(disp, win, True,
(unsigned int) (ButtonPressMask|ButtonReleaseMask|
PointerMotionMask|PointerMotionHintMask),
GrabModeAsync, GrabModeAsync,
win, cur, CurrentTime) != GrabSuccess) {
XBell(disp, 0);
return 0;
}
if (echoGC == (GC) 0) {
unsigned long gcmask;
XGCValues gcvals;
gcmask = ux11_fill_gcvals(&gcvals, GCForeground, zeroPixel ^ bgPixel,
GCFunction, GXxor,
UX11_END);
echoGC = XCreateGC(disp, win, gcmask, &gcvals);
}
startX = evt->x; startY = evt->y;
XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
&curX, &curY, &mask_rtn);
/* Draw first box */
DRAWBOX;
stopFlag = 0;
while (!stopFlag) {
XNextEvent(disp, &theEvent);
switch (theEvent.xany.type) {
case MotionNotify:
XQueryPointer(disp, win, &root_rtn, &child_rtn, &root_x, &root_y,
&newX, &newY, &mask_rtn);
/* Undraw the old one */
DRAWBOX;
/* Draw the new one */
curX = newX; curY = newY;
DRAWBOX;
break;
case ButtonRelease:
DRAWBOX;
XUngrabPointer(disp, CurrentTime);
stopFlag = 1;
if ((startX-curX != 0) && (startY-curY != 0)) {
/* Figure out relative bounding box */
loX = TRANX(startX); loY = TRANY(startY);
hiX = TRANX(curX); hiY = TRANY(curY);
if (loX > hiX) {
double temp;
temp = hiX;
hiX = loX;
loX = temp;
}
if (loY > hiY) {
double temp;
temp = hiY;
hiY = loY;
loY = temp;
}
/* physical aspect ratio */
asp = ((double) ABS(startX-curX))/((double) ABS(startY-curY));
new_win = NewWindow(progname, loX, loY, hiX, hiY, asp);
if (new_win) {
numwin = 1;
} else {
numwin = 0;
}
} else {
numwin = 0;
}
break;
default:
printf("unknown event: %d\n", theEvent.xany.type);
break;
}
}
return numwin;
}
#endif
unsigned long GetColor(name)
char *name;
/*
* Given a standard color name, this routine fetches the associated
* pixel value from the global `cmap'. The name may be specified
* using the standard specification format parsed by XParseColor.
* Some sort of parsing error causes the program to exit.
*/
{
XColor def;
if (XParseColor(disp, cmap, name, &def)) {
if (XAllocColor(disp, cmap, &def)) {
return def.pixel;
} else {
(void) fprintf(stderr, "xgraph: could not allocate color: `%s'\n",
name);
exit(1);
}
} else {
(void) fprintf(stderr, "xgraph: cannot parse color specification: `%s'\n",
name);
exit(1);
}
return 0;
}
/* Default line styles */
static char *defStyle[MAXATTR] = {
"11", "44", "1142", "31", "88", "113111", "2231", "224"
};
/* Default color names */
static char *defColors[MAXATTR] = {
"red", "SpringGreen", "blue", "yellow",
"cyan", "plum", "orange", "coral"
};
int InitSets()
/*
* Initializes the data sets with default information.
*/
{
int idx;
char setname[40];
Window temp_win;
XSetWindowAttributes wattr;
char *font_name;
if (ux11_std_vismap(disp, &vis, &cmap, &screen, &depth) == UX11_ALTERNATE) {
install_flag = 1;
} else {
install_flag = 0;
}
black_pixel = GetColor("black");
white_pixel = GetColor("white");
/* Create a temporary window for creating graphics contexts */
temp_win = XCreateWindow(disp, RootWindow(disp, screen),
0, 0, 10, 10, 0, depth, InputOutput,
vis, (unsigned long) 0, &wattr);
bwFlag = (depth < 4);
bdrSize = 2;
bdrPixel = black_pixel;
(void) strcpy(titleText, "X Graph");
(void) strcpy(XUnits, "X");
(void) strcpy(YUnits, "Y");
tickFlag = 0;
markFlag = 0;
pixelMarks = 0;
bigPixel = 0;
colorMark = 0;
bbFlag = 0;
noLines = 0;
logXFlag = 0;
logYFlag = 0;
barFlag = 0;
barBase = 0.0;
barWidth = -1.0; /* Holder */
lineWidth = 1;
echoPix = BIGINT;
/* Set the user bounding box */
UsrLX = UsrLY = MAXFLOAT;
UsrRX = UsrRY = -MAXFLOAT;
/* Depends critically on whether the display has color */
if (bwFlag) {
/* Its black and white */
bgPixel = white_pixel;
zeroPixel = black_pixel;
zeroWidth = 3;
normPixel = black_pixel;
/* Initialize set defaults */
for (idx = 0; idx < MAXATTR; idx++) {
/* Needs work! */
AllAttrs[idx].lineStyleLen =
ProcessStyle(defStyle[idx], AllAttrs[idx].lineStyle, MAXLS);
AllAttrs[idx].pixelValue = black_pixel;
}
} else {
/* Its color */
bgPixel = GetColor("LightGray");
zeroPixel = white_pixel;
zeroWidth = 1;
normPixel = black_pixel;
/* Initalize attribute colors defaults */
AllAttrs[0].lineStyle[0] = '\0';
AllAttrs[0].lineStyleLen = 0;
AllAttrs[0].pixelValue = GetColor(defColors[0]);
for (idx = 1; idx < MAXATTR; idx++) {
AllAttrs[idx].lineStyleLen =
ProcessStyle(defStyle[idx-1], AllAttrs[idx].lineStyle, MAXLS);
AllAttrs[idx].pixelValue = GetColor(defColors[idx]);
}
}
if (!ux11_size_font(disp, screen, 4000, &axisFont, &font_name)) {
fprintf(stderr, "Can't find an appropriate axis font\n");
abort();
}
if (!ux11_size_font(disp, screen, 6000, &titleFont, &font_name)) {
fprintf(stderr, "Can't find an appropriate title font\n");
abort();
}
/* Initialize the data sets */
for (idx = 0; idx < MAXSETS; idx++) {
(void) sprintf(setname, "Set %d", idx);
AllSets[idx].setName = STRDUP(setname);
AllSets[idx].numPoints = 0;
AllSets[idx].allocSize = 0;
AllSets[idx].xvec = AllSets[idx].yvec = (double *) 0;
}
/* Store bitmaps for dots and markers */
dotMap = XCreateBitmapFromData(disp, temp_win, dot_bits, dot_w, dot_h);
AllAttrs[0].markStyle = XCreateBitmapFromData(disp, temp_win,
mark1_bits, mark_w, mark_h);
AllAttrs[1].markStyle = XCreateBitmapFromData(disp, temp_win,
mark2_bits, mark_w, mark_h);
AllAttrs[2].markStyle = XCreateBitmapFromData(disp, temp_win,
mark3_bits, mark_w, mark_h);
AllAttrs[3].markStyle = XCreateBitmapFromData(disp, temp_win,
mark4_bits, mark_w, mark_h);
AllAttrs[4].markStyle = XCreateBitmapFromData(disp, temp_win,
mark5_bits, mark_w, mark_h);
AllAttrs[5].markStyle = XCreateBitmapFromData(disp, temp_win,
mark6_bits, mark_w, mark_h);
AllAttrs[6].markStyle = XCreateBitmapFromData(disp, temp_win,
mark7_bits, mark_w, mark_h);
AllAttrs[7].markStyle = XCreateBitmapFromData(disp, temp_win,
mark8_bits, mark_w, mark_h);
XDestroyWindow(disp, temp_win);
}
static char *def_str;
static Pixel def_pixel;
static int def_int;
static XFontStruct *def_font;
static double def_dbl;
int rd_pix(name)
char *name;
/* Result in def_pixel */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
def_pixel = GetColor(def_str);
if (debugFlag) printf("%s (pixel) = %s\n", name, def_str);
return 1;
} else {
return 0;
}
}
int rd_int(name)
char *name;
/* Result in def_int */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
if (sscanf(def_str, "%ld", &def_int) == 1) {
if (debugFlag) printf("%s (int) = %s\n", name, def_str);
return 1;
} else {
fprintf(stderr, "warning: could not read integer value for %s\n", name);
return 0;
}
} else {
return 0;
}
}
int rd_str(name)
char *name;
/* Result in def_str */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
if (debugFlag) printf("%s (str) = %s\n", name, def_str);
return 1;
} else {
return 0;
}
}
int rd_font(name)
char *name;
/* Result in def_font */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
if (def_font = XLoadQueryFont(disp, def_str)) {
if (debugFlag) printf("%s (font) = %s\n", name, def_str);
return 1;
} else {
fprintf(stderr, "warning: could not load font for %s\n", name);
return 0;
}
} else {
return 0;
}
}
int rd_flag(name)
char *name;
/* Result in def_int */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
def_int = (stricmp(def_str, "on") == 0) || (stricmp(def_str, "1") == 0);
if (debugFlag) printf("%s (flag) = %s\n", name, def_str);
return 1;
} else {
return 0;
}
}
int rd_dbl(name)
char *name;
/* Result in def_dbl */
{
if (def_str = XGetDefault(disp, Prog_Name, name)) {
if (sscanf(def_str, "%lg", &def_dbl) == 1) {
if (debugFlag) printf("%s (dbl) = %s\n", name, def_str);
return 1;
} else {
fprintf(stderr, "warning: could not read value of %s\n", name);
return 0;
}
} else {
return 0;
}
}
int ReversePixel(pixValue)
Pixel *pixValue; /* Pixel value to reverse */
{
if (*pixValue == white_pixel)
*pixValue = black_pixel;
else if (*pixValue == black_pixel)
*pixValue = white_pixel;
}
int ProcessStyle(style, buf, maxbuf)
char *style; /* Textual line style spec */
char *buf; /* Returned buf */
int maxbuf; /* Maximum size of buffer */
/*
* Translates a textual specification for a line style into
* an appropriate dash list for X11. Returns the length.
*/
{
int len, i;
strncpy(buf, style, maxbuf-1);
buf[maxbuf-1] = '\0';
len = strlen(buf);
for (i = 0; i < len; i++) {
if ((buf[i] >= '0') && (buf[i] <= '9')) {
buf[i] = buf[i] - '0';
} else if ((buf[i] >= 'a') && (buf[i] <= 'f')) {
buf[i] = buf[i] - 'a' + 10;
} else if ((buf[i] >= 'A') && (buf[i] <= 'F')) {
buf[i] = buf[i] - 'A' + 10;
} else {
return 0;
}
}
return len;
}
int ReadDefaults()
/*
* Reads X default values which override the hard-coded defaults
* set up by InitSets.
*/
{
char newname[100];
int idx;
if (rd_pix("Background")) {
bgPixel = def_pixel;
}
if (rd_int("BorderSize")) {
bdrSize = def_int;
}
if (rd_pix("Border")) {
bdrPixel = def_pixel;
}
if (rd_int("GridSize")) {
axisWidth = def_int;
}
if (rd_str("GridStyle")) {
axisLSLen = ProcessStyle(def_str, axisLS, MAXLS);
}
if (rd_pix("Foreground")) {
normPixel = def_pixel;
}
if (rd_pix("ZeroColor")) zeroPixel = def_pixel;
if (rd_str("ZeroStyle")) {
zeroLSLen = ProcessStyle(def_str, zeroLS, MAXLS);
}
if (rd_int("ZeroSize")) zeroWidth = def_int;
if (rd_font("LabelFont")) {
axisFont = def_font;
}
if (rd_font("TitleFont")) {
titleFont = def_font;
}
if (rd_flag("Ticks")) tickFlag = def_int;
if (rd_str("Device")) Odevice = def_str;
if (rd_str("Disposition")) Odisp = def_str;
if (rd_str("FileOrDev")) OfileDev = def_str;
/* Read device specific parameters */
for (idx = 0; idx < hard_count; idx++) {
sprintf(newname, "%s.Dimension", hard_devices[idx].dev_name);
if (rd_dbl(newname)) hard_devices[idx].dev_max_dim = def_dbl;
sprintf(newname, "%s.OutputTitleFont", hard_devices[idx].dev_name);
if (rd_str(newname)) {
(void) strncpy(hard_devices[idx].dev_title_font, def_str, MFNAME-1);
}
sprintf(newname, "%s.OutputTitleSize", hard_devices[idx].dev_name);
if (rd_dbl(newname)) hard_devices[idx].dev_title_size = def_dbl;
sprintf(newname, "%s.OutputAxisFont", hard_devices[idx].dev_name);
if (rd_str(newname)) {
(void) strncpy(hard_devices[idx].dev_axis_font, def_str, MFNAME-1);
}
sprintf(newname, "%s.OutputAxisSize", hard_devices[idx].dev_name);
if (rd_dbl(newname)) hard_devices[idx].dev_axis_size = def_dbl;
}
if (rd_flag("SmallPixels")) {
if (def_int) { noLines = markFlag = 1; pixelMarks = 1; bigPixel = 0; }
}
if (rd_flag("LargePixels")) {
if (def_int) {
markFlag = 1; pixelMarks = 1; bigPixel = 1;
}
}
if (rd_flag("Markers")) {
if (def_int) { markFlag = 1; pixelMarks = 0; colorMark = 0; }
}
if (rd_flag("StyleMarkers")) {
if (def_int) { markFlag = 1; pixelMarks = 0; colorMark = 1; }
}
if (rd_flag("BoundBox")) bbFlag = def_int;
if (rd_flag("NoLines")) noLines = def_int;
if (rd_flag("PixelMarkers")) pixelMarks = def_int;
if (rd_int("LineWidth")) lineWidth = def_int;
/* Read the default line and color attributes */
for (idx = 0; idx < MAXATTR; idx++) {
(void) sprintf(newname, "%d.Style", idx);
if (rd_str(newname)) {
AllAttrs[idx].lineStyleLen =
ProcessStyle(def_str, AllAttrs[idx].lineStyle, MAXLS);
}
(void) sprintf(newname, "%d.Color", idx);
if (rd_pix(newname)) {
AllAttrs[idx].pixelValue = def_pixel;
}
}
if (bwFlag) {
/* Black and white - check for reverse video */
if (rd_flag("ReverseVideo")) {
if (def_int) {
ReversePixel(&bgPixel);
ReversePixel(&bdrPixel);
ReversePixel(&zeroPixel);
ReversePixel(&normPixel);
for (idx = 0; idx < MAXATTR; idx++) {
ReversePixel(&(AllAttrs[idx].pixelValue));
}
}
}
}
}
int argerror(err, val)
char *err, *val;
{
(void) fprintf(stderr, "Error: %s: %s\n\n", val, err);
(void) fprintf(stderr,
"format: xgraph [-bd color] [-bg color] [-fg color] [-zg color]\n");
(void) fprintf(stderr,
" [-bw bdr_width] [-lf label_font] [-tf title_font]\n");
(void) fprintf(stderr,
" [-<digit> set_name] [-t title] [-x unitname] [-y unitname]\n");
(void) fprintf(stderr,
" [-lx x1,x2] [-ly y1,y2] [-bar] [-brb base] [-brw width]\n");
(void) fprintf(stderr,
" [-bb] [-db] [-lnx] [-lny] [-nl] [-m] [-M] [-p] [-P] [-rv]\n");
(void) fprintf(stderr,
" [-tk] [-lw linewidth] [-display host:display.screen] [=geospec]\n");
(void) fprintf(stderr, "\nFonts must be fixed width\n");
(void) fprintf(stderr, "-bar Draw bar graph with base -brb and width -brw\n");
(void) fprintf(stderr, "-bb Draws bounding box around data\n");
(void) fprintf(stderr, "-db Turns on debugging mode\n");
(void) fprintf(stderr, "-lnx Logarithmic scale for X axis\n");
(void) fprintf(stderr, "-lny Logarithmic scale for Y axis\n");
(void) fprintf(stderr, "-nl Don't draw lines (scatter plot)\n");
(void) fprintf(stderr, "-m -M Mark points distinctively (M varies with color)\n");
(void) fprintf(stderr, "-p -P Mark points with dot (P means big dot)\n");
(void) fprintf(stderr, "-rv Reverse video on black and white displays\n");
(void) fprintf(stderr, "-tk Draw tick marks instead of full grid\n");
exit(1);
}
int ParseArgs(argc, argv)
int argc;
char *argv[];
/*
* This routine parses the argument list for xgraph. There are too
* many to mention here so I won't.
*/
{
int idx, set, tempPixel;
XFontStruct *tempFont;
idx = 1;
while (idx < argc) {
if (argv[idx][0] == '-') {
/* Check to see if its a data set name */
if (sscanf(argv[idx], "-%d", &set) == 1) {
/* The next string is a set name */
if (idx+1 >= argc) argerror("missing set name", argv[idx]);
AllSets[set].setName = argv[idx+1];
idx += 2;
} else {
/* Some non-dataset option */
if (strcmp(argv[idx], "-x") == 0) {
/* Units for X axis */
if (idx+1 >= argc)
argerror("missing axis name", argv[idx]);
(void) strcpy(XUnits, argv[idx+1]);
idx += 2;
} else if (strcmp(argv[idx], "-y") == 0) {
/* Units for Y axis */
if (idx+1 >= argc)
argerror("missing axis name", argv[idx]);
(void) strcpy(YUnits, argv[idx+1]);
idx += 2;
} else if (strcmp(argv[idx], "-t") == 0) {
/* Title of plot */
if (idx+1 >= argc)
argerror("missing plot title", argv[idx]);
(void) strcpy(titleText, argv[idx+1]);
idx += 2;
} else if (strcmp(argv[idx], "-fg") == 0) {
/* Foreground color */
if (idx+1 >= argc) argerror("missing color", argv[idx]);
tempPixel = GetColor(argv[idx+1]);
normPixel = tempPixel;
idx += 2;
} else if (strcmp(argv[idx], "-bg") == 0) {
/* Background color */
if (idx+1 >= argc) argerror("missing color", argv[idx]);
tempPixel = GetColor(argv[idx+1]);
bgPixel = tempPixel;
idx += 2;
} else if (strcmp(argv[idx], "-bd") == 0) {
/* Border color */
if (idx+1 >= argc) argerror("missing color", argv[idx]);
tempPixel = GetColor(argv[idx+1]);
bdrPixel = tempPixel;
idx += 2;
} else if (strcmp(argv[idx], "-bw") == 0) {
/* Border width */
if (idx+1 >= argc) argerror("missing border size",
argv[idx]);
bdrSize = atoi(argv[idx+1]);
idx += 2;
} else if (strcmp(argv[idx], "-zg") == 0) {
/* Zero grid color */
if (idx+1 >= argc) argerror("missing color", argv[idx]);
tempPixel = GetColor(argv[idx+1]);
zeroPixel = tempPixel;
idx += 2;
} else if (strcmp(argv[idx], "-tf") == 0) {
/* Title Font */
if (idx+1 >= argc) argerror("missing font", argv[idx]);
tempFont = XLoadQueryFont(disp, argv[idx+1]);
if (!tempFont) argerror("can't get font", argv[idx+1]);
titleFont = tempFont;
idx += 2;
} else if (strcmp(argv[idx], "-lf") == 0) {
/* Label Font */
if (idx+1 >= argc) argerror("missing font", argv[idx]);
tempFont = XLoadQueryFont(disp, argv[idx+1]);
if (!tempFont) argerror("can't get font", argv[idx+1]);
axisFont = tempFont;
idx += 2;
} else if (strcmp(argv[idx], "-rv") == 0) {
/* Reverse video option */
ReversePixel(&bgPixel);
ReversePixel(&bdrPixel);
ReversePixel(&zeroPixel);
ReversePixel(&normPixel);
for (set = 0; set < MAXATTR; set++) {
ReversePixel(&(AllAttrs[set].pixelValue));
}
idx++;
} else if (strcmp(argv[idx], "-tk") == 0) {
/* Draw tick marks instead of full grid */
tickFlag = 1;
idx++;
} else if (strcmp(argv[idx], "-bb") == 0) {
/* Draw bounding box around graph region */
bbFlag = 1;
idx++;
} else if (strcmp(argv[idx], "-lx") == 0) {
/* Limit the X coordinates */
if (idx+1 >= argc) argerror("missing coordinate(s)",
argv[idx]);
(void) sscanf(argv[idx+1], "%lf,%lf", &UsrLX, &UsrRX);
idx += 2;
} else if (strcmp(argv[idx], "-ly") == 0) {
/* Limit the Y coordinates */
if (idx+1 >= argc) argerror("missing coordinate(s)",
argv[idx]);
(void) sscanf(argv[idx+1], "%lf,%lf", &UsrLY, &UsrRY);
idx += 2;
} else if (strcmp(argv[idx], "-lw") == 0) {
/* Set the line width */
if (idx+1 >= argc) argerror("missing line width",
argv[idx]);
lineWidth = atoi(argv[idx+1]);
idx += 2;
} else if (strcmp(argv[idx], "-nl") == 0) {
noLines = 1;
idx++;
} else if (strcmp(argv[idx], "-m") == 0) {
/*
* Mark each point with a individual marker
* varying with linestyle
*/
markFlag = 1; pixelMarks = colorMark = 0;
idx++;
} else if (strcmp(argv[idx], "-M") == 0) {
/*
* Mark each point with an individual marker
* varying with color.
*/
markFlag = colorMark = 1; pixelMarks = 0;
idx++;
} else if (strcmp(argv[idx], "-p") == 0) {
/* Draw small pixel sized markers */
noLines = markFlag = pixelMarks = 1;
bigPixel = 0;
idx++;
} else if (strcmp(argv[idx], "-P") == 0) {
/* Draw large pixel sized markers */
markFlag = pixelMarks = bigPixel = 1;
idx++;
} else if (strcmp(argv[idx], "-lnx") == 0) {
/* The X axis is logarithmic */
logXFlag = 1;
idx++;
} else if (strcmp(argv[idx], "-lny") == 0) {
/* The Y axis is logarithmic */
logYFlag = 1;
idx++;
} else if (strcmp(argv[idx], "-bar") == 0) {
/* Draw bar graph */
barFlag = 1;
idx++;
} else if (strcmp(argv[idx], "-brw") == 0) {
/* Set width of bar */
if (idx+1 >= argc) argerror("missing width", argv[idx]);
(void) sscanf(argv[idx+1], "%lf", &barWidth);
idx += 2;
} else if (strcmp(argv[idx], "-brb") == 0) {
if (idx+1 >= argc) argerror("missing base", argv[idx]);
(void) sscanf(argv[idx+1], "%lf", &barBase);
idx += 2;
} else if (strcmp(argv[idx], "-db") == 0) {
/* Debug on */
debugFlag = 1;
XSynchronize(disp, 1);
XFlush(disp);
idx++;
} else if (strcmp(argv[idx], "-display") == 0) {
/* Harmless display specification */
idx += 2;
} else {
argerror("unknown option", argv[idx]);
}
}
} else if (argv[idx][0] == '=') {
/* Its a geometry specification */
geoSpec = &(argv[idx][1]);
idx++;
} else {
/* It might be the host:display string */
if (rindex(argv[idx], ':') == (char *) 0) {
/* Should be an input file */
inFileNames[numFiles] = argv[idx];
numFiles++;
}
idx++;
}
}
}
/* For reading in the data */
static int setNumber = 0;
static maxSize = 0;
int ReadData(stream, filename)
FILE *stream;
char *filename;
/*
* Reads in the data sets from the supplied stream. If the format
* is correct, it returns the current maximum number of points across
* all data sets. If there is an error, it returns -1.
*/
{
char buffer[MAXBUFSIZE];
char setname[40];
int spot = 0;
int line_count = 0;
/* Set name of set to file name if appropriate */
(void) sprintf(setname, "Set %d", setNumber);
if ((strcmp(AllSets[setNumber].setName, setname) == 0) && filename) {
AllSets[setNumber].setName = filename;
}
/* Eliminate over-zealous set increments */
if (setNumber > 0) {
if (AllSets[setNumber-1].numPoints == 0) {
setNumber--;
return ReadData(stream, filename);
}
}
if (!filename) filename = "stdin";
while (setNumber < MAXSETS) {
if (!fgets(buffer, MAXBUFSIZE, stream)) break;
line_count++;
if (buffer[0] == '#') continue;
if (buffer[0] == '\n') {
/* Empty line - increment data set */
setNumber++;
if (spot > maxSize) maxSize = spot;
spot = 0;
} else if (buffer[0] == '"') {
buffer[strlen(buffer)-1] = '\0';
AllSets[setNumber].setName = STRDUP(&(buffer[1]));
} else {
if (spot >= AllSets[setNumber].allocSize) {
/* Time to make the arrays bigger (or initialize them) */
if (AllSets[setNumber].allocSize == 0) {
AllSets[setNumber].allocSize = INITSIZE;
AllSets[setNumber].xvec = (double *)
malloc((unsigned) (INITSIZE * sizeof(double)));
AllSets[setNumber].yvec = (double *)
malloc((unsigned) (INITSIZE * sizeof(double)));
} else {
AllSets[setNumber].allocSize *= 2;
AllSets[setNumber].xvec = (double *)
realloc((char *) AllSets[setNumber].xvec,
(unsigned) (AllSets[setNumber].allocSize *
sizeof(double)));
AllSets[setNumber].yvec = (double *)
realloc((char *) AllSets[setNumber].yvec,
(unsigned) (AllSets[setNumber].allocSize *
sizeof(double)));
}
}
if (sscanf(buffer, "%F %F",
&(AllSets[setNumber].xvec[spot]),
&(AllSets[setNumber].yvec[spot])) != 2)
{
(void) fprintf(stderr, "file: `%s', line: %d\n",
filename, line_count);
(void) fprintf(stderr, "Exactly two coordinates per line\n");
return -1;
}
if (logXFlag) {
if (AllSets[setNumber].xvec[spot] <= 0.0) {
(void) fprintf(stderr, "file: `%s', line: %d\n",
filename, line_count);
(void) fprintf(stderr, "Non-positive X value in logarithmic mode\n");
return -1;
}
AllSets[setNumber].xvec[spot] =
log10(AllSets[setNumber].xvec[spot]);
}
if (logYFlag) {
if (AllSets[setNumber].yvec[spot] <= 0.0) {
(void) fprintf(stderr, "file: `%s', line: %d\n",
filename, line_count);
(void) fprintf(stderr, "Non-positive Y value in logarithmic mode\n");
return -1;
}
AllSets[setNumber].yvec[spot] =
log10(AllSets[setNumber].yvec[spot]);
}
/* Update bounding box */
if (AllSets[setNumber].xvec[spot] < llx)
llx = AllSets[setNumber].xvec[spot];
if (AllSets[setNumber].xvec[spot] > urx)
urx = AllSets[setNumber].xvec[spot];
if (AllSets[setNumber].yvec[spot] < lly)
lly = AllSets[setNumber].yvec[spot];
if (AllSets[setNumber].yvec[spot] > ury)
ury = AllSets[setNumber].yvec[spot];
spot++;
AllSets[setNumber].numPoints += 1;
}
}
if (spot > maxSize) maxSize = spot;
if (line_count <= 0) {
(void) fprintf(stderr, "No data found\n");
return -1;
}
if (setNumber >= MAXSETS) {
(void) fprintf(stderr, "Too many data sets\n");
return -1;
} else {
setNumber++;
return maxSize;
}
}
int DrawWindow(win_info)
LocalWin *win_info; /* Window information */
/*
* Draws the data in the window. Does not clear the window.
* The data is scaled so that all of the data will fit.
* Grid lines are drawn at the nearest power of 10 in engineering
* notation.. Draws axis numbers along bottom and left hand edges.
* Centers title at top of window.
*/
{
/* Figure out the transformation constants */
if (TransformCompute(win_info)) {
/* Draw the title */
DrawTitle(win_info);
/* Draw the legend */
DrawLegend(win_info);
/* Draw the axis unit labels, grid lines, and grid labels */
DrawGridAndAxis(win_info);
/* Draw the data sets themselves */
DrawData(win_info);
}
}
DrawTitle(wi)
LocalWin *wi; /* Window information */
/*
* This routine draws the title of the graph centered in
* the window. It is spaced down from the top by an amount
* specified by the constant PADDING. The font must be
* fixed width. The routine returns the height of the
* title in pixels.
*/
{
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->dev_info.area_w/2,
wi->dev_info.axis_pad,
titleText, T_TOP, T_TITLE);
}
int TransformCompute(wi)
LocalWin *wi; /* Window information */
/*
* This routine figures out how to draw the axis labels and grid lines.
* Both linear and logarithmic axes are supported. Axis labels are
* drawn in engineering notation. The power of the axes are labeled
* in the normal axis labeling spots. The routine also figures
* out the necessary transformation information for the display
* of the points (it touches XOrgX, XOrgY, UsrOrgX, UsrOrgY, and
* UnitsPerPixel).
*/
{
double bbCenX, bbCenY, bbHalfWidth, bbHalfHeight;
int idx, maxName, leftWidth;
char err[MAXBUFSIZE];
/*
* First, we figure out the origin in the X window. Above
* the space we have the title and the Y axis unit label.
* To the left of the space we have the Y axis grid labels.
*/
wi->XOrgX = wi->dev_info.bdr_pad + (7 * wi->dev_info.axis_width)
+ wi->dev_info.bdr_pad;
wi->XOrgY = wi->dev_info.bdr_pad + wi->dev_info.title_height
+ wi->dev_info.bdr_pad + wi->dev_info.axis_height
+ wi->dev_info.axis_height/2 + wi->dev_info.bdr_pad;
/*
* Now we find the lower right corner.. Below the space we
* have the X axis grid labels. To the right of the space we
* have the X axis unit label and the legend. We assume the
* worst case size for the unit label.
*/
maxName = 0;
for (idx = 0; idx < MAXSETS; idx++) {
if (AllSets[idx].numPoints > 0) {
int tempSize;
tempSize = strlen(AllSets[idx].setName);
if (tempSize > maxName) maxName = tempSize;
}
}
/* Worst case size of the X axis label: */
leftWidth = (strlen(XUnits)) * wi->dev_info.axis_width;
if ((maxName*wi->dev_info.axis_width)+wi->dev_info.bdr_pad > leftWidth)
leftWidth = maxName * wi->dev_info.axis_width + wi->dev_info.bdr_pad;
wi->XOppX = wi->dev_info.area_w - wi->dev_info.bdr_pad - leftWidth;
wi->XOppY = wi->dev_info.area_h - wi->dev_info.bdr_pad
- wi->dev_info.axis_height - wi->dev_info.bdr_pad;
if ((wi->XOrgX >= wi->XOppX) || (wi->XOrgY >= wi->XOppY)) {
#ifdef TOOLBOX
do_error(strcpy(err, "Drawing area is too small\n"));
#else
(void) fprintf(stderr, "Drawing area is too small\n");
#endif
return 0;
}
/*
* We now have a bounding box for the drawing region.
* Figure out the units per pixel using the data set bounding box.
*/
wi->XUnitsPerPixel = (wi->hiX - wi->loX)/((double) (wi->XOppX - wi->XOrgX));
wi->YUnitsPerPixel = (wi->hiY - wi->loY)/((double) (wi->XOppY - wi->XOrgY));
/*
* Find origin in user coordinate space. We keep the center of
* the original bounding box in the same place.
*/
bbCenX = (wi->loX + wi->hiX) / 2.0;
bbCenY = (wi->loY + wi->hiY) / 2.0;
bbHalfWidth = ((double) (wi->XOppX - wi->XOrgX))/2.0 * wi->XUnitsPerPixel;
bbHalfHeight = ((double) (wi->XOppY - wi->XOrgY))/2.0 * wi->YUnitsPerPixel;
wi->UsrOrgX = bbCenX - bbHalfWidth;
wi->UsrOrgY = bbCenY - bbHalfHeight;
wi->UsrOppX = bbCenX + bbHalfWidth;
wi->UsrOppY = bbCenY + bbHalfHeight;
/*
* Everything is defined so we can now use the SCREENX and SCREENY
* transformations.
*/
return 1;
}
int DrawGridAndAxis(wi)
LocalWin *wi; /* Window information */
/*
* This routine draws grid line labels in engineering notation,
* the grid lines themselves, and unit labels on the axes.
*/
{
int expX, expY; /* Engineering powers */
int startX;
int Yspot, Xspot;
char power[10], value[10], final[MAXBUFSIZE+10];
double Xincr, Yincr, Xstart, Ystart, Yindex, Xindex, larger;
XSegment segs[2];
double initGrid(), stepGrid();
/*
* Grid display powers are computed by taking the log of
* the largest numbers and rounding down to the nearest
* multiple of 3.
*/
if (logXFlag) {
expX = 0;
} else {
if (fabs(wi->UsrOrgX) > fabs(wi->UsrOppX)) {
larger = fabs(wi->UsrOrgX);
} else {
larger = fabs(wi->UsrOppX);
}
expX = ((int) floor(nlog10(larger)/3.0)) * 3;
}
if (logYFlag) {
expY = 0;
} else {
if (fabs(wi->UsrOrgY) > fabs(wi->UsrOppY)) {
larger = fabs(wi->UsrOrgY);
} else {
larger = fabs(wi->UsrOppY);
}
expY = ((int) floor(nlog10(larger)/3.0)) * 3;
}
/*
* With the powers computed, we can draw the axis labels.
*/
if (expY != 0) {
(void) strcpy(final, YUnits);
(void) strcat(final, " x 10");
Xspot = wi->dev_info.bdr_pad +
((strlen(YUnits)+5) * wi->dev_info.axis_width);
Yspot = wi->dev_info.bdr_pad * 2 + wi->dev_info.title_height +
wi->dev_info.axis_height/2;
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot, Yspot, final, T_RIGHT, T_AXIS);
(void) sprintf(power, "%d", expY);
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot, Yspot, power, T_LOWERLEFT, T_AXIS);
} else {
Yspot = wi->dev_info.bdr_pad * 2 + wi->dev_info.title_height;
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->dev_info.bdr_pad, Yspot, YUnits,
T_UPPERLEFT, T_AXIS);
}
startX = wi->dev_info.area_w - wi->dev_info.bdr_pad;
if (expX != 0) {
(void) sprintf(power, "%d", expX);
startX -= (strlen(power) + 5) * wi->dev_info.axis_width;
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, power, T_LOWERLEFT, T_AXIS);
(void) strcpy(final, XUnits);
(void) strcat(final, " x 10");
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, final, T_RIGHT, T_AXIS);
} else {
wi->dev_info.xg_text(wi->dev_info.user_state,
startX, wi->XOppY, XUnits, T_RIGHT, T_AXIS);
}
/*
* First, the grid line labels
*/
Yincr = (wi->dev_info.axis_pad + wi->dev_info.axis_height) * wi->YUnitsPerPixel;
Ystart = initGrid(wi->UsrOrgY, Yincr, logYFlag);
for (Yindex = Ystart; Yindex < wi->UsrOppY; Yindex = stepGrid()) {
Yspot = SCREENY(wi, Yindex);
/* Write the axis label */
WriteValue(value, Yindex, expY, logYFlag);
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->dev_info.bdr_pad +
(7 * wi->dev_info.axis_width),
Yspot, value, T_RIGHT, T_AXIS);
}
Xincr = (wi->dev_info.axis_pad + (wi->dev_info.axis_width * 7)) * wi->XUnitsPerPixel;
Xstart = initGrid(wi->UsrOrgX, Xincr, logXFlag);
for (Xindex = Xstart; Xindex < wi->UsrOppX; Xindex = stepGrid()) {
Xspot = SCREENX(wi, Xindex);
/* Write the axis label */
WriteValue(value, Xindex, expX, logXFlag);
wi->dev_info.xg_text(wi->dev_info.user_state,
Xspot,
wi->dev_info.area_h - wi->dev_info.bdr_pad,
value, T_BOTTOM, T_AXIS);
}
/*
* Now, the grid lines or tick marks
*/
Yincr = (wi->dev_info.axis_pad + wi->dev_info.axis_height) * wi->YUnitsPerPixel;
Ystart = initGrid(wi->UsrOrgY, Yincr, logYFlag);
for (Yindex = Ystart; Yindex < wi->UsrOppY; Yindex = stepGrid()) {
Yspot = SCREENY(wi, Yindex);
/* Draw the grid line or tick mark */
if (tickFlag) {
segs[0].x1 = wi->XOrgX;
segs[0].x2 = wi->XOrgX + wi->dev_info.tick_len;
segs[1].x1 = wi->XOppX - wi->dev_info.tick_len;
segs[1].x2 = wi->XOppX;
segs[0].y1 = segs[0].y2 = segs[1].y1 = segs[1].y2 = Yspot;
} else {
segs[0].x1 = wi->XOrgX; segs[0].x2 = wi->XOppX;
segs[0].y1 = segs[0].y2 = Yspot;
}
if ((ABS(Yindex) < ZERO_THRES) && !logYFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, zeroWidth,
L_ZERO, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), zeroWidth,
L_ZERO, 0, 0);
}
} else {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, axisWidth,
L_AXIS, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), axisWidth,
L_AXIS, 0, 0);
}
}
}
Xincr = (wi->dev_info.axis_pad + (wi->dev_info.axis_width * 7)) * wi->XUnitsPerPixel;
Xstart = initGrid(wi->UsrOrgX, Xincr, logXFlag);
for (Xindex = Xstart; Xindex < wi->UsrOppX; Xindex = stepGrid()) {
Xspot = SCREENX(wi, Xindex);
/* Draw the grid line or tick marks */
if (tickFlag) {
segs[0].x1 = segs[0].x2 = segs[1].x1 = segs[1].x2 = Xspot;
segs[0].y1 = wi->XOrgY;
segs[0].y2 = wi->XOrgY + wi->dev_info.tick_len;
segs[1].y1 = wi->XOppY - wi->dev_info.tick_len;
segs[1].y2 = wi->XOppY;
} else {
segs[0].x1 = segs[0].x2 = Xspot;
segs[0].y1 = wi->XOrgY; segs[0].y2 = wi->XOppY;
}
if ((ABS(Xindex) < ZERO_THRES) && !logXFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, zeroWidth, L_ZERO, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), zeroWidth, L_ZERO, 0, 0);
}
} else {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, segs, axisWidth, L_AXIS, 0, 0);
if (tickFlag) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &(segs[1]), axisWidth, L_AXIS, 0, 0);
}
}
}
/* Check to see if he wants a bounding box */
if (bbFlag) {
XSegment bb[4];
/* Draw bounding box */
bb[0].x1 = bb[0].x2 = bb[1].x1 = bb[3].x2 = wi->XOrgX;
bb[0].y1 = bb[2].y2 = bb[3].y1 = bb[3].y2 = wi->XOrgY;
bb[1].x2 = bb[2].x1 = bb[2].x2 = bb[3].x1 = wi->XOppX;
bb[0].y2 = bb[1].y1 = bb[1].y2 = bb[2].y1 = wi->XOppY;
wi->dev_info.xg_seg(wi->dev_info.user_state,
4, bb, axisWidth, L_AXIS, 0, 0);
}
}
static double gridBase, gridStep, gridJuke[101];
static int gridNJuke, gridCurJuke;
#define ADD_GRID(val) (gridJuke[gridNJuke++] = log10(val))
double initGrid(low, step, logFlag)
double low; /* desired low value */
double step; /* desired step (user coords) */
int logFlag; /* is axis logarithmic? */
{
double ratio, x;
double RoundUp(), stepGrid();
gridNJuke = gridCurJuke = 0;
gridJuke[gridNJuke++] = 0.0;
if (logFlag) {
ratio = pow(10.0, step);
gridBase = floor(low);
gridStep = ceil(step);
if (ratio <= 3.0) {
if (ratio > 2.0) {
ADD_GRID(3.0);
} else if (ratio > 1.333) {
ADD_GRID(2.0); ADD_GRID(5.0);
} else if (ratio > 1.25) {
ADD_GRID(1.5); ADD_GRID(2.0); ADD_GRID(3.0);
ADD_GRID(5.0); ADD_GRID(7.0);
} else {
for (x = 1.0; x < 10.0 && (x+.5)/(x+.4) >= ratio; x += .5) {
ADD_GRID(x + .1); ADD_GRID(x + .2);
ADD_GRID(x + .3); ADD_GRID(x + .4);
ADD_GRID(x + .5);
}
if (floor(x) != x) ADD_GRID(x += .5);
for ( ; x < 10.0 && (x+1.0)/(x+.5) >= ratio; x += 1.0) {
ADD_GRID(x + .5); ADD_GRID(x + 1.0);
}
for ( ; x < 10.0 && (x+1.0)/x >= ratio; x += 1.0) {
ADD_GRID(x + 1.0);
}
if (x == 7.0) {
gridNJuke--;
x = 6.0;
}
if (x < 7.0) {
ADD_GRID(x + 2.0);
}
if (x == 10.0) gridNJuke--;
}
x = low - gridBase;
for (gridCurJuke = -1; x >= gridJuke[gridCurJuke+1]; gridCurJuke++){
}
}
} else {
gridStep = RoundUp(step);
gridBase = floor(low / gridStep) * gridStep;
}
return(stepGrid());
}
double stepGrid()
{
if (++gridCurJuke >= gridNJuke) {
gridCurJuke = 0;
gridBase += gridStep;
}
return(gridBase + gridJuke[gridCurJuke]);
}
double RoundUp(val)
double val; /* Value */
/*
* This routine rounds up the given positive number such that
* it is some power of ten times either 1, 2, or 5. It is
* used to find increments for grid lines.
*/
{
int exponent, idx;
exponent = (int) floor(nlog10(val));
if (exponent < 0) {
for (idx = exponent; idx < 0; idx++) {
val *= 10.0;
}
} else {
for (idx = 0; idx < exponent; idx++) {
val /= 10.0;
}
}
if (val > 5.0) val = 10.0;
else if (val > 2.0) val = 5.0;
else if (val > 1.0) val = 2.0;
else val = 1.0;
if (exponent < 0) {
for (idx = exponent; idx < 0; idx++) {
val /= 10.0;
}
} else {
for (idx = 0; idx < exponent; idx++) {
val *= 10.0;
}
}
return val;
}
int WriteValue(str, val, exp, logFlag)
char *str; /* String to write into */
double val; /* Value to print */
int exp; /* Exponent */
int logFlag; /* Is this a log axis? */
/*
* Writes the value provided into the string in a fixed format
* consisting of seven characters. The format is:
* -ddd.dd
*/
{
int idx;
if (logFlag) {
if (val == floor(val)) {
(void) sprintf(str, "%.0e", pow(10.0, val));
} else {
(void) sprintf(str, "%.2g", pow(10.0, val - floor(val)));
}
} else {
if (exp < 0) {
for (idx = exp; idx < 0; idx++) {
val *= 10.0;
}
} else {
for (idx = 0; idx < exp; idx++) {
val /= 10.0;
}
}
(void) sprintf(str, "%.2f", val);
}
}
#define LEFT_CODE 0x01
#define RIGHT_CODE 0x02
#define BOTTOM_CODE 0x04
#define TOP_CODE 0x08
/* Clipping algorithm from Neumann and Sproull by Cohen and Sutherland */
#define C_CODE(xval, yval, rtn) \
rtn = 0; \
if ((xval) < wi->UsrOrgX) rtn = LEFT_CODE; \
else if ((xval) > wi->UsrOppX) rtn = RIGHT_CODE; \
if ((yval) < wi->UsrOrgY) rtn |= BOTTOM_CODE; \
else if ((yval) > wi->UsrOppY) rtn |= TOP_CODE
int DrawData(wi)
LocalWin *wi;
/*
* This routine draws the data sets themselves using the macros
* for translating coordinates.
*/
{
double sx1, sy1, sx2, sy2, tx, ty;
int idx, subindex;
int code1, code2, cd, mark_inside;
int X_idx;
XSegment *ptr;
for (idx = 0; idx < MAXSETS; idx++) {
X_idx = 0;
for (subindex = 0; subindex < AllSets[idx].numPoints-1; subindex++) {
/* Put segment in (sx1,sy1) (sx2,sy2) */
sx1 = AllSets[idx].xvec[subindex];
sy1 = AllSets[idx].yvec[subindex];
sx2 = AllSets[idx].xvec[subindex+1];
sy2 = AllSets[idx].yvec[subindex+1];
/* Now clip to current window boundary */
C_CODE(sx1, sy1, code1);
C_CODE(sx2, sy2, code2);
mark_inside = (code1 == 0);
while (code1 || code2) {
if (code1 & code2) break;
cd = (code1 ? code1 : code2);
if (cd & LEFT_CODE) { /* Crosses left edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOrgX - sx1) / (sx2 - sx1);
tx = wi->UsrOrgX;
} else if (cd & RIGHT_CODE) { /* Crosses right edge */
ty = sy1 + (sy2 - sy1) * (wi->UsrOppX - sx1) / (sx2 - sx1);
tx = wi->UsrOppX;
} else if (cd & BOTTOM_CODE) { /* Crosses bottom edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOrgY - sy1) / (sy2 - sy1);
ty = wi->UsrOrgY;
} else if (cd & TOP_CODE) { /* Crosses top edge */
tx = sx1 + (sx2 - sx1) * (wi->UsrOppY - sy1) / (sy2 - sy1);
ty = wi->UsrOppY;
}
if (cd == code1) {
sx1 = tx; sy1 = ty;
C_CODE(sx1, sy1, code1);
} else {
sx2 = tx; sy2 = ty;
C_CODE(sx2, sy2, code2);
}
}
if (!code1 && !code2) {
/* Add segment to list */
Xsegs[X_idx].x1 = SCREENX(wi, sx1);
Xsegs[X_idx].y1 = SCREENY(wi, sy1);
Xsegs[X_idx].x2 = SCREENX(wi, sx2);
Xsegs[X_idx].y2 = SCREENY(wi, sy2);
X_idx++;
}
/* Draw markers if requested and they are in drawing region */
if (markFlag && mark_inside) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x1, Xsegs[X_idx-1].y1,
P_DOT, 0, idx % MAXATTR);
} else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x1, Xsegs[X_idx-1].y1,
P_PIXEL, 0, PIXVALUE(idx));
}
} else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x1, Xsegs[X_idx-1].y1,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
/* Draw bar elements if requested */
if (barFlag) {
int barPixels, baseSpot;
XSegment line;
barPixels = (int) ((barWidth / wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0) barPixels = 1;
baseSpot = SCREENY(wi, barBase);
line.x1 = line.x2 = Xsegs[X_idx-1].x1;
line.y1 = baseSpot; line.y2 = Xsegs[X_idx-1].y1;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
}
/* Handle last marker */
if (markFlag && (AllSets[idx].numPoints > 0)) {
C_CODE(AllSets[idx].xvec[AllSets[idx].numPoints-1],
AllSets[idx].yvec[AllSets[idx].numPoints-1],
mark_inside);
if (mark_inside == 0) {
if (pixelMarks) {
if (bigPixel) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x2, Xsegs[X_idx-1].y2,
P_DOT, 0, idx % MAXATTR);
} else {
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x2, Xsegs[X_idx-1].y2,
P_PIXEL, 0, PIXVALUE(idx));
}
} else {
/* Distinctive markers */
wi->dev_info.xg_dot(wi->dev_info.user_state,
Xsegs[X_idx-1].x2, Xsegs[X_idx-1].y2,
P_MARK, MARKSTYLE(idx),
PIXVALUE(idx));
}
}
}
/* Handle last bar */
if ((AllSets[idx].numPoints > 0) && barFlag) {
int barPixels, baseSpot;
XSegment line;
barPixels = (int) ((barWidth / wi->XUnitsPerPixel) + 0.5);
if (barPixels <= 0) barPixels = 1;
baseSpot = SCREENY(wi, barBase);
line.x1 = line.x2 = Xsegs[X_idx-1].x2;
line.y1 = baseSpot; line.y2 = Xsegs[X_idx-1].y2;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &line, barPixels, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
/* Draw segments */
if (AllSets[idx].numPoints > 0 && (!noLines) && (X_idx > 0)) {
ptr = Xsegs;
while (X_idx > wi->dev_info.max_segs) {
wi->dev_info.xg_seg(wi->dev_info.user_state,
wi->dev_info.max_segs, ptr,
lineWidth, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
ptr += wi->dev_info.max_segs;
X_idx -= wi->dev_info.max_segs;
}
wi->dev_info.xg_seg(wi->dev_info.user_state,
X_idx, ptr,
lineWidth, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
}
}
}
int DrawLegend(wi)
LocalWin *wi;
/*
* This draws a legend of the data sets displayed. Only those that
* will fit are drawn.
*/
{
int idx, spot, lineLen, oneLen;
XSegment leg_line;
spot = wi->XOrgY;
lineLen = 0;
/* First pass draws the text */
for (idx = 0; idx < MAXSETS; idx++) {
if ((AllSets[idx].numPoints > 0) &&
(spot + wi->dev_info.axis_height + 2 < wi->XOppY))
{
/* Meets the criteria */
oneLen = strlen(AllSets[idx].setName);
if (oneLen > lineLen) lineLen = oneLen;
wi->dev_info.xg_text(wi->dev_info.user_state,
wi->XOppX + wi->dev_info.bdr_pad,
spot+2,
AllSets[idx].setName,
T_UPPERLEFT, T_AXIS);
spot += 2 + wi->dev_info.axis_height + wi->dev_info.bdr_pad;
}
}
lineLen = lineLen * wi->dev_info.axis_width;
leg_line.x1 = wi->XOppX + wi->dev_info.bdr_pad;
leg_line.x2 = leg_line.x1 + lineLen;
spot = wi->XOrgY;
/* second pass draws the lines */
for (idx = 0; idx < MAXSETS; idx++) {
if ((AllSets[idx].numPoints > 0) &&
(spot + wi->dev_info.axis_height + 2 < wi->XOppY))
{
leg_line.y1 = leg_line.y2 = spot - wi->dev_info.legend_pad;
wi->dev_info.xg_seg(wi->dev_info.user_state,
1, &leg_line, 1, L_VAR,
LINESTYLE(idx), PIXVALUE(idx));
if (markFlag && !pixelMarks) {
wi->dev_info.xg_dot(wi->dev_info.user_state,
leg_line.x1, leg_line.y1,
P_MARK, MARKSTYLE(idx), PIXVALUE(idx));
}
spot += 2 + wi->dev_info.axis_height + wi->dev_info.bdr_pad;
}
}
}
#define RND(val) ((int) ((val) + 0.5))
#ifdef TOOLBOX
/*ARGSUSED*/
void do_hardcopy(prog, info, init_fun, dev_spec, file_or_dev, maxdim,
ti_fam, ti_size, ax_fam, ax_size)
char *prog; /* Program name for Xdefaults */
char *info; /* Some state information */
int (*init_fun)(); /* Hardcopy init function */
char *dev_spec; /* Device specification (if any) */
char *file_or_dev; /* Filename or device spec */
double maxdim; /* Maximum dimension in cm */
char *ti_fam, *ax_fam; /* Font family names */
double ti_size, ax_size; /* Font sizes in points */
/*
* This routine resets the function pointers to those specified
* by `init_fun' and causes a screen redisplay. If `dev_spec'
* is non-zero, it will be considered a sprintf string with
* one %s which will be filled in with `file_or_dev' and fed
* to popen(3) to obtain a stream. Otherwise, `file_or_dev'
* is considered to be a file and is opened for writing. The
* resulting stream is fed to the initialization routine for
* the device.
*/
{
LocalWin *curWin = (LocalWin *) info;
LocalWin thisWin;
FILE *out_stream;
char buf[MAXBUFSIZE], err[MAXBUFSIZE], ierr[ERRBUFSIZE];
char tilde[MAXBUFSIZE*10];
int final_w, final_h;
double ratio;
if (dev_spec) {
(void) sprintf(buf, dev_spec, file_or_dev);
out_stream = popen(buf, "w");
if (!out_stream) {
#ifdef TOOLBOX
do_error(sprintf(err, "Unable to issue command:\n %s\n", buf));
#else
(void) fprintf(stderr, "Unable to issue command:\n %s\n", buf));
#endif
return;
}
} else {
tildeExpand(tilde, file_or_dev);
out_stream = fopen(tilde, "w");
if (!out_stream) {
#ifdef TOOLBOX
do_error(sprintf(err, "Unable to open file `%s'\n", tilde));
#else
(void) fprintf(stderr, "Unable to open file `%s'\n", tilde);
#endif
return;
}
}
thisWin = *curWin;
ratio = ((double) thisWin.dev_info.area_w) /
((double) thisWin.dev_info.area_h);
if (thisWin.dev_info.area_w > thisWin.dev_info.area_h) {
final_w = RND(maxdim * 10000.0);
final_h = RND(maxdim/ratio * 10000.0);
} else {
final_w = RND(maxdim * ratio * 10000.0);
final_h = RND(maxdim * 10000.0);
}
ierr[0] = '\0';
if ((*init_fun)(out_stream, final_w, final_h, ti_fam, ti_size,
ax_fam, ax_size, &(thisWin.dev_info), ierr)) {
DrawWindow(&thisWin);
if (thisWin.dev_info.xg_end) {
thisWin.dev_info.xg_end(thisWin.dev_info.user_state);
}
} else {
#ifdef TOOLBOX
do_error(ierr);
#else
(void) fprintf(stderr, "%s\n", ierr);
#endif
}
if (dev_spec) {
(void) pclose(out_stream);
} else {
(void) fclose(out_stream);
}
}
#endif
static char *tildeExpand(out, in)
char *out; /* Output space for expanded file name */
char *in; /* Filename with tilde */
/*
* This routine expands out a file name passed in `in' and places
* the expanded version in `out'. It returns `out'.
*/
{
char username[50], *userPntr;
struct passwd *userRecord;
out[0] = '\0';
/* Skip over the white space in the initial path */
while ((*in == ' ') || (*in == '\t')) in++;
/* Tilde? */
if (in[0] == TILDE) {
/* Copy user name into 'username' */
in++; userPntr = &(username[0]);
while ((*in != '\0') && (*in != '/')) {
*(userPntr++) = *(in++);
}
*(userPntr) = '\0';
/* Look up user directory in passwd file */
if ((userRecord = getpwnam(username)) != (struct passwd *) 0) {
/* Found user in passwd file. Concatenate user directory */
strcat(out, userRecord->pw_dir);
}
}
/* Concantenate remaining portion of file name */
strcat(out, in);
return out;
}
/*ARGSUSED*/
static int XErrHandler(disp, evt)
Display *disp;
XErrorEvent *evt;
/*
* Displays a nicely formatted message and core dumps.
*/
{
fprintf(stderr, "Fatal X Error: %s", ux11_error(evt));
abort();
}
int stricmp(a, b)
register char *a, *b;
/*
* This routine compares two strings disregarding case.
*/
{
register int value;
if ((a == (char *) 0) || (b == (char *) 0)) {
return a - b;
}
for ( /* nothing */;
((*a | *b) &&
!(value = ((isupper(*a) ? *a - 'A' + 'a' : *a) -
(isupper(*b) ? *b - 'A' + 'a' : *b))));
a++, b++)
/* Empty Body */;
return value;
}
\End\Of\Shar\
else
echo "will not over write ./xgraph-11/xgraph.c"
fi
echo "Finished archive 4 of 6"
More information about the Comp.sources.x
mailing list