diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /vendor/x11iraf/xtapemon/xtapemon.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'vendor/x11iraf/xtapemon/xtapemon.c')
-rw-r--r-- | vendor/x11iraf/xtapemon/xtapemon.c | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/vendor/x11iraf/xtapemon/xtapemon.c b/vendor/x11iraf/xtapemon/xtapemon.c new file mode 100644 index 00000000..1cd7f35d --- /dev/null +++ b/vendor/x11iraf/xtapemon/xtapemon.c @@ -0,0 +1,736 @@ +#include <stdio.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* #ifndef AUX */ +#include <fcntl.h> +/* #endif */ + +#include <X11/Intrinsic.h> +#include <X11/StringDefs.h> +#include <X11/Shell.h> +#include <X11/Xaw/Paned.h> +#include <X11/Xaw/Viewport.h> +#include <X11/Xaw/List.h> +#include <X11/Xaw/Form.h> +#include <X11/Xaw/Box.h> +#include <X11/Xaw/Label.h> +#include <X11/Xaw/AsciiText.h> +#include <X11/Xaw/Command.h> +#include <X11/Xaw/Cardinals.h> + +#include "appres.h" +#include "xtapemon.h" +#include "classnames.h" +#include "patchlevel.h" + +/* + * XTAPEMON -- X window system based tape monitoring utility. + * + * Monitors the raw ascii status output of the iraf tape driver and + * maintains a graphical display of the tape status in a window. + * + */ + +/* Local definitions. + */ +#define MAXCONN 0 +#define MAXPORTS 2 +#define ERR (-1) +#define EOS '\0' +#define SZ_FNAME 256 +#define SZ_LINE 512 +#define SZ_MSGBUF 2048 + +extern errno; + +/* Functions defined in this file. + */ +int main(); +void doPendingEvents(); +void initWidgetsFromString(); +void setText(), setLabel(); +void status0(), status1(), status2(); +void fail0(), fail1(); + +static int portSetup(), portOpen(); +static void initGraphics(), initWidgets(); +static void selectItem(), portClose(); +static void syntax(), appendText(); +static void Quit(); +static XtInputCallbackProc connectToClient(), readClientData(); + +/* Global graphics data. + */ +Display *display; +Screen *screen; +Window root; +int server_socket; +int server_port; + +/* Global widget data. + */ +XtAppContext appContext; +Widget toplevel; + +static Widget statusText, messages, quitButton, recordLabel; +static Widget devtypeText, tapetypeText, tapesizeText, tapeusedText; +static Widget acmodeText, densityText, blksizeText, fileText, recordText; +static Widget recsizeText, nfilesText; + +/* Other global data. + */ +char *progname; +AppResources appResources; + +/* Non-widget resources obtained from resource manager. + */ +static XtResource resources[] = { + { "widgets", "Widgets", XtRString, sizeof(String), + XtOffset(AppResources *,widgets), XtRImmediate, "" }, + { "port", "Port", XtRInt, sizeof(int), + XtOffset(AppResources *,port), XtRImmediate, (XtPointer)5138 }, + { "alternate", "Alternate", XtRInt, sizeof(int), + XtOffset(AppResources *,alternate), XtRImmediate, (XtPointer)0 }, + { "debug", "Debug", XtRInt, sizeof(int), + XtOffset(AppResources *,debug), XtRImmediate, (XtPointer)0 }, +}; + +/* Non-widget resources set on command line. + */ +static XrmOptionDescRec options[] = { + { "-port", ".port", XrmoptionSepArg, (XtPointer)"5138" }, + { "-a", ".alternate", XrmoptionNoArg, (XtPointer)"1" }, + { "-d", ".debug", XrmoptionNoArg, (XtPointer)"1" }, +}; + +/* Widget and non-widget resources if the application defaults file can't + * be found. Generated automatically from XTapemon.ad by "ad2c". + */ +static String fallbackResources[] = { +#include "XTapemon.ad.h" + NULL +}; + +/* Compatibility hacks. */ +#ifdef AUX +void *memmove(a,b,n) void *a; const void *b; size_t n; { bcopy(b,a,n); } +#else +#if defined(sun) && !defined(SYSV) +void *memmove(a,b,n) void *a, *b; int n; { bcopy(b,a,n); } +#endif +#endif + +/* + * The main program. + */ +main(argc,argv) +int argc; +char **argv; +{ + char buf[80]; + int port; + + progname = argv[0]; + initGraphics(&argc,argv); + if (argc > 1) { + syntax(argc,argv); + XtDestroyApplicationContext(appContext); + exit(1); + } + initWidgets(); + XtRealizeWidget(toplevel); + /* Set window title to indicate version */ + sprintf (buf, "xtapemon %d.%d - IRAF Tape Monitor Utility", + xtapemonMajorVersion, xtapemonMinorVersion); + XStoreName(display,XtWindow(toplevel),buf); + sprintf(buf, "Welcome to xtapemon %d.%d", + xtapemonMajorVersion, xtapemonMinorVersion); + status0(buf); + + /* Prepare to receive a connection, set up Xt callback to accept a + * client connection when one arrives. + */ + port = appResources.port + appResources.alternate; + if ((server_socket = portSetup(port)) >= 0) + XtAppAddInput (appContext, server_socket, (XtPointer)XtInputReadMask, + (XtInputCallbackProc)connectToClient, (XtPointer)server_socket); + + /* Identify port in use. */ + sprintf (buf, "ready on port %s (%d)", + (server_port == appResources.port) ? "A" : "B", server_port); + setText (messages, buf); + + /* do it */ + XtAppMainLoop(appContext); + /*NOTREACHED*/ +} + + +void +doPendingEvents() +{ + while (XtAppPending(appContext)) + XtAppProcessEvent(appContext,XtIMAll); +} + +static void +initGraphics(argcp,argv) +int *argcp; +char **argv; +{ + toplevel = XtAppInitialize(&appContext, "XTapemon", + options, XtNumber(options), + argcp,argv,fallbackResources,NULL,ZERO); + initConverters(appContext); + /* XawSimpleMenuAddGlobalActions(appContext); */ + /* XtAppAddActions(appContext,actionTable,XtNumber(actionTable)); */ + XtGetApplicationResources(toplevel,(XtPointer)&appResources, + resources,XtNumber(resources),NULL,ZERO); + display = XtDisplay(toplevel); + screen = XtScreen(toplevel); + root = RootWindowOfScreen(screen); +} + + +/* initWidgets -- Initialize the widgets given in the .widgets resource, + * check for required widgets, and set globals vars. + */ +static void +initWidgets() +{ + initWidgetsFromString(appResources.widgets,".widgets"); + + /* set globals for optional widgets */ + statusText = XtNameToWidget (toplevel, "*statusText"); + messages = XtNameToWidget (toplevel, "*messages"); + quitButton = XtNameToWidget (toplevel, "*quitButton"); + devtypeText = XtNameToWidget (toplevel, "*devtypeText"); + tapetypeText = XtNameToWidget (toplevel, "*tapetypeText"); + tapesizeText = XtNameToWidget (toplevel, "*tapesizeText"); + tapeusedText = XtNameToWidget (toplevel, "*tapeusedText"); + acmodeText = XtNameToWidget (toplevel, "*acmodeText"); + densityText = XtNameToWidget (toplevel, "*densityText"); + blksizeText = XtNameToWidget (toplevel, "*blksizeText"); + fileText = XtNameToWidget (toplevel, "*fileText"); + recordText = XtNameToWidget (toplevel, "*recordText"); + recordLabel = XtNameToWidget (toplevel, "*recordLabel"); + recsizeText = XtNameToWidget (toplevel, "*recsizeText"); + nfilesText = XtNameToWidget (toplevel, "*nfilesText"); + + /* Set up Quit button callback. */ + XtAddCallback (quitButton, XtNcallback, Quit, (XtPointer)NULL); +} + +static void +Quit(w, call_data, client_data) +Widget w; +XtPointer call_data, client_data; +{ + XtDestroyApplicationContext(XtWidgetToApplicationContext(w)); + exit(0); +} + +#define ISSPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n') +#define NUL '\0' + +/* initWidgetsFromString -- Create the widgets specified in resourceStr as + * "parent class name" triples. The resourceName is used for error messages. + */ +void +initWidgetsFromString(resourceStr,resourceName) +char *resourceStr,*resourceName; +{ + char name[32],class[32],parent[256]; + char *s,*t; + Boolean isShell; + WidgetClass wc; + Widget pw; + + if ((s=resourceStr) == NULL) + fail1("no widgets specified in %s resource!",resourceName); + while (*s) { + /* skip leading whitespace */ + while (ISSPACE(*s)) + s += 1; + if (!*s) + break; + /* Gather the parent widget name */ + t = parent; + while (*s && !ISSPACE(*s)) + *t++ = *s++; + *t = NUL; + /* skip whitespace */ + while (ISSPACE(*s)) + s += 1; + if (!*s) + fail1("missing widget class and name in %s resource",resourceName); + /* Gather the class name */ + t = class; + while (*s && !ISSPACE(*s)) + *t++ = *s++; + *t = NUL; + /* skip whitespace */ + while (ISSPACE(*s)) + s += 1; + if (!*s) + fail1("missing widget name in %s resource",resourceName); + /* Gather the widget's name */ + t = name; + while (*s && !ISSPACE(*s)) + *t++ = *s++; + *t = NUL; + /* convert class name to WidgetClass */ + if ((wc=classNameToWidgetClass(class,&isShell)) == NULL) + fail1("can't convert string \"%s\" to widgetClass",class); + /* convert parent name to Widget */ + if (strcmp(parent,"toplevel") == 0) + pw = toplevel; + else if ((pw=XtNameToWidget(toplevel,parent)) == NULL) + fail1("can't convert string \"%s\" to widget",parent); + /* finally create the widget */ + if (isShell) + (void)XtCreatePopupShell(name,wc,pw,NULL,ZERO); + else + (void)XtCreateManagedWidget(name,wc,pw,NULL,ZERO); + } +} + + +/* + * Client actions. + * -------------------------- + */ + +/* connectToClient -- Called when a client has attempted a connection on + * the xtapemon socket. Accept the connection and open a file pointer on + * the status output stream of the client. + */ +static XtInputCallbackProc +connectToClient (client_data, source, id) +XtPointer client_data; +int *source; +XtInputId *id; +{ + int fd; + + setText (statusText, "connecting to client..."); + if ((fd = portOpen ((int)*source)) < 0) + setText (statusText, "connection failed"); + else { + setText (statusText, "connection established"); + if (fcntl (fd, F_SETFD, O_RDWR|O_NDELAY) < 0) { + char buf[80]; + sprintf (buf, "fcntl failed, errno=%d", errno); + setText (statusText, buf); + portClose (fd); + } else { + /* Enable the following to prohibit multiple clients. + * XtRemoveInput (*id); + */ + XtAppAddInput (appContext, fd, (XtPointer)XtInputReadMask, + (XtInputCallbackProc)readClientData, (XtPointer)NULL); + } + } + + doPendingEvents(); +} + + +/* readClientData -- Called when there is client data to be read and + * displayed. + */ +static XtInputCallbackProc +readClientData (client_data, source, id) +XtPointer client_data; +int *source; +XtInputId *id; +{ + register int fd = *source; + register char *ip, *op; + static char msg[SZ_MSGBUF]; + static int nleft, tapesize, blksize; + char word[SZ_LINE], value[SZ_LINE]; + char obuf[SZ_LINE], iodev[SZ_FNAME]; + int nchars, newline, maxch, ival; + char *start; + + start = msg + nleft; + maxch = SZ_MSGBUF - nleft; + nleft = 0; + + /* Read a block of text from the input socket and process each line to + * the monitor window. Messages may be batched for efficiency, i.e., + * the text block may contain several lines. Since socket i/o is stream + * based we can't assume that lines are not broken over read transfer + * boundaries, so it is necessary to save any partial line at the end of + * a read and join the line when the next data block is read. + */ + nchars = read (fd, start, maxch); + if (nchars >= 0) { + if (appResources.debug) + write (2, start, nchars); + *(start + nchars) = EOS; + } + ip = msg; + + while (*ip) { + start = ip; + newline = 0; + + /* Get first whitespace delimited word. */ + for (op=word; *ip && !isspace(*ip); ) + *op++ = *ip++; + *op = EOS; + while (*ip && *ip == ' ') + ip++; + + /* Anything other than "keyword = value" is a message and is sent + * to the message window. Messages are newline delimited. The + * newline is required to delimit records. To include a newline + * in a message one must pass an explicit \n, e.g, "foo\\n\n". + */ + if (*ip == '=') { + for (ip++, op=value; *ip; ) { + if (*ip == '\n') { + ip++; + newline++; + break; + } else + *op++ = *ip++; + } + *op = EOS; + } else { + for (ip=start, op=value; *ip; ) { + if (*ip == '\n') { + ip++; + newline++; + break; + } else if (*ip == '\\' && *(ip+1) == 'n') { + *op++ = '\n'; + ip += 2; + } else + *op++ = *ip++; + } + *op = EOS; + if (newline) { + appendText (value); + continue; + } + } + + /* Save any partial line for next time. */ + if (!newline) { + strcpy (msg, start); + nleft = strlen (msg); + break; + } + + /* Set the value of a keyword. */ + if (word[0] == EOS) { + continue; + } else if (strcmp (word, "iodev") == 0) { + strcpy (iodev, value+1); + } else if (strcmp (word, "host") == 0) { + sprintf (obuf, "connected to %s,%s on port %s (%d)", + value+1, iodev, + (server_port == appResources.port) ? "A" : "B", server_port); + setText (statusText, obuf); + + } else if (strcmp (word, "devtype") == 0) { + setText (devtypeText, value); + } else if (strcmp (word, "tapetype") == 0) { + setText (tapetypeText, value); + + } else if (strcmp (word, "tapesize") == 0) { + ival = atoi (value); + sprintf (obuf, " %d.%02d Mb", ival / 1000, ((ival%1000) + 5) / 10); + setText (tapesizeText, obuf); + tapesize = ival; + + } else if (strcmp (word, "tapeused") == 0) { + ival = atoi (value); + sprintf (obuf, " %d.%02d Mb (%02d%%)", + ival / 1000, ((ival % 1000) + 5) / 10, + (ival / tapesize) * 100); + setText (tapeusedText, obuf); + + } else if (strcmp (word, "blksize") == 0) { + ival = atoi (value); + if (ival != blksize) { + setLabel (recordLabel, ival ? " Block:" : "Record:"); + blksize = ival; + } + setText (blksizeText, !strcmp(value," 0") ? " variable" : value); + + } else if (strcmp (word, "acmode") == 0) { + setText (acmodeText, value); + } else if (strcmp (word, "density") == 0) { + setText (densityText, value); + } else if (strcmp (word, "file") == 0) { + setText (fileText, value); + } else if (strcmp (word, "nfiles") == 0) { + setText (nfilesText, !strcmp(value," 0") ? " unknown" : value); + } else if (strcmp (word, "record") == 0) { + setText (recordText, value); + } else if (strcmp (word, "recsize") == 0) { + setText (recsizeText, value); + } else { + sprintf (obuf, "%s = %s", word, value); + appendText (obuf); + } + } + + /* Close connection, and ready to receive further connection. */ + if (nchars <= 0) { + close (fd); + XtRemoveInput (*id); + setText (statusText, "connection closed"); + + /* Enable the following if XtRemoveInput is used in XtInputCallback + * XtAppAddInput (appContext, server_socket, XtInputReadMask, + * (XtInputCallbackProc)connectToClient, (XtPointer)server_socket); + */ + } + +done: + + XFlush (display); + doPendingEvents(); +} + + +/* appendText -- Append some text to the message buffer. + */ +static void +appendText (text) +char *text; +{ + register char *ip, *op; + static XawTextPosition pos = 0; + static int newline = 0; + XawTextBlock tx; + char buf[1024]; + + if (pos == 0) + setText (messages, ""); + + op = buf; + if (newline) + *op++ = '\n'; + + for (ip=text; *ip; ) + *op++ = *ip++; + + if (newline = (*(ip-1) == '\n')) + op--; + + *op = EOS; + + tx.ptr = buf; + tx.length = op - buf; + tx.format = FMT8BIT; + tx.firstPos = 0; + + XawTextReplace (messages, pos, pos, &tx); + XawTextSetInsertionPoint (messages, (pos += (op - buf))); +} + + +/* + * Socket i/o code. + * -------------------------- + */ + + +/* portSetup -- Set up the tape status port, used by remote tape driver client + * to send messages to xtapemon. + */ +static int +portSetup (first_port) +int first_port; +{ + struct sockaddr_in sockaddr; + int bound, reuse=1; + int s, port, i; + + if ((s = socket (AF_INET, SOCK_STREAM, 0)) < 0) { + status1 ("socket creation fails, errno=%d", errno); + return (ERR); + } + + /* Try to bind an address to the socket. If the first try doesn't + * succeed it may be because a server is already bound to the port, + * so try a higher numbered port. + */ + for (bound=i=0; i < MAXPORTS; i++) { + port = first_port + i; + memset ((char *)&sockaddr, 0, sizeof(sockaddr)); + sockaddr.sin_family = AF_INET; + sockaddr.sin_port = htons((short)port); + sockaddr.sin_addr.s_addr = INADDR_ANY; + + if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, + sizeof(reuse)) < 0) { + close (s); + return (ERR); + } + + if (bind (s, (struct sockaddr *)&sockaddr, sizeof(sockaddr)) >= 0) { + server_port = port; + bound++; + break; + } + } + + if (!bound) { + status1 ("bind on socket fails, errno=%d", errno); + close (s); + return (ERR); + } + + if (listen (s, MAXCONN) < 0) { + status1 ("listen on socket fails, errno=%d", errno); + close (s); + return (ERR); + } + + return (s); +} + + +/* portOpen -- Called when processing is needed on a socket, either when + * a client is requesting a connection or when data is ready on a connected + * socket. + */ +static int +portOpen (s) +int s; +{ + int fd; + if ((fd = accept (s, (struct sockaddr *)0, (int *)0)) < 0) + return (ERR); + else + return (fd); +} + + +/* portClose -- Close a file descriptor opened on an active server socket. + */ +static void +portClose (fd) +int fd; +{ + close (fd); +} + + +/* + * Utility routines. + * -------------------------- + */ + +/* setText -- Set the given Text item's value to the given string. + */ +void +setText(item,text) +Widget item; +char *text; +{ + Arg args[1]; + + if (item != NULL) { + XtSetArg(args[0],XtNstring,text); + XtSetValues(item,args,ONE); + } +} + + +/* setLabel -- Set the given Label item's value to the given string. + */ +void +setLabel(item,text) +Widget item; +char *text; +{ + Arg args[1]; + + if (item != NULL) { + XtSetArg(args[0],XtNlabel,text); + XtSetValues(item,args,ONE); + } +} + +void +status0(str) +char *str; +{ + if (statusText != NULL) + setText(statusText,str); + doPendingEvents(); +} + +void +status1(fmt,arg) +char *fmt,*arg; +{ + char buf[256]; + + sprintf(buf,fmt,arg); + status0(buf); +} + +void +status2(fmt,arg1,arg2) +char *fmt,*arg1,*arg2; +{ + char buf[256]; + + sprintf(buf,fmt,arg1,arg2); + status0(buf); +} + +void +fail0(str) +char *str; +{ + fprintf(stderr,"%s: %s\n",progname,str); + XtDestroyApplicationContext(appContext); + exit(1); +} + +void +fail1(fmt,arg) +char *fmt,*arg; +{ + char buf[256]; + + sprintf(buf,fmt,arg); + fail0(buf); +} + +/* syntax -- Print whatever caused the error and the usage message. + */ +static void +syntax(argc,argv) +int argc; +char **argv; +{ + char *program; + + program = *argv; + argv += 1; + if (argc > 2 || (strcmp(*argv,"-help") != 0 && strcmp(*argv,"-?") != 0)) { + fprintf(stderr,"%s: bad argument(s): ",program); + while (--argc) + fprintf(stderr,"%s ",*argv++); + fprintf(stderr,"\n"); + } + fprintf(stderr,"Valid options (in addition to X Toolkit options) are:\n"); + fprintf(stderr," -port N\tlisten on port number N\n"); + fprintf(stderr," -a\tlisten on alternate port\n"); + fprintf(stderr," -d\tpass client messages to standard out\n"); + fprintf(stderr,"Options can be abbreviated to their shortest unique prefix.\n"); +} |