#line 13 "extern.c-nw" static char copyright[] = "Copyright NBBI, Den Haag, 1995"; #include #include #include #include #include #include #include #include #include #include #include #include #define METAMAIL_CMD "metamail -d -b -c '%s'" typedef struct { Widget w; pid_t child; int fin, fout; /* Child's input & output */ XtInputId id; } *Info; typedef struct _Assoc { long id; Info b; struct _Assoc *next; } *Assoc; static Assoc assoclist = NULL; /* store -- store an ID/Buffer combination */ static void store(Info b, long id) { Assoc h; new(h); h->id = id; h->b = b; h->next = assoclist; assoclist = h; } /* delete -- delete an ID/Buffer combination */ static void delete(long id) { Assoc g, h; assert(assoclist); if (assoclist->id == id) { h = assoclist; assoclist = assoclist->next; dispose(h); } else { assert(h->next); for (h = assoclist; h->next->id != id; h = h->next) assert(h->next); g = h->next; h->next = g->next; dispose(g); } } /* find -- find the Buffer associated with an ID */ static Info find(long id) { Assoc h; assert(assoclist); for (h = assoclist; h->id != id; h = h->next) assert(h->next); return h->b; } static void syserr(char *s) { perror(s); exit(1); } #line 90 "extern.c-nw" static void out_cb(XtPointer client_data, int *fid, XtInputId *id) { Widget w = (Widget) client_data; char buf[BUFSIZ]; int n; while ((n = read(*fid, buf, sizeof(buf) - 1)) == -1 && errno == EINTR) ; if (n == -1) XtAppWarning(XtWidgetToApplicationContext(w), "Read error"); /* else if (n == 0) { XtRemoveInput(*id); XmTextSetString(w, "Program has stopped"); } */ else { buf[n] = '\0'; XmTextInsert(w, XmTextGetLastPosition(w), buf); } } /* resize_cb -- callback for when the AnsiTerm changes size */ static void resize_cb(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { /* XfwfResizeInfo *size = (XfwfResizeInfo *) call_data; */ pid_t *child = (pid_t *) client_data; kill(*child, SIGWINCH); } /* initExtern -- initialize class variables for the Extern viewer */ EXPORT Bool initExtern(char ***mime_types, int *nrtypes, float **qual) { static char *types[] = {"*/*"}; static float pref[] = {0.1}; *mime_types = types; *nrtypes = 1; *qual = pref; return TRUE; /* Nothing to initialize */ } /* openExtern -- open an external viewer */ EXPORT Bool openExtern(const W3ADocumentInfo doc, W3AWindow area, long id) { int pfdout[2], pfdin[2]; long c, tblsiz; pid_t child; Info info; char s[BUFSIZ]; int n; static Arg args[] = { {XmNeditable, FALSE}, {XmNeditMode, XmMULTI_LINE_EDIT}, }; if (pipe(pfdout) == -1 || pipe(pfdin) == -1) return FALSE; switch ((child = fork())) { case -1: return FALSE; /* NOTREACHED */ case 0: #if 0 setsid(); /* Dissociate from terminal */ #endif if (close(0) == -1) syserr("close"); if (dup(pfdin[0]) != 0) syserr("dup failed\n"); if (close(1) == -1) syserr("close"); if (dup(pfdout[1]) != 1) syserr("dup failed\n"); if (close(2) == -1) syserr("close"); if (dup(pfdout[1]) != 2) syserr("dup failed\n"); /* Close all other files */ tblsiz = sysconf(_SC_OPEN_MAX); for (c = 3; c < tblsiz; c++) (void) close(c); sprintf(s, METAMAIL_CMD, doc.mime_type); printf("The document is shown by another program:\n"); printf(" %s\n\n", s); fflush(stdin); putenv("TERM=ansi"); execl(SHELL_PATH, SHELL_NAME, "-c", s, 0); syserr("execl failed"); /* NOTREACHED */ } if (close(pfdout[1]) == -1 || close(pfdin[0]) == -1) return FALSE; signal(SIGPIPE, SIG_IGN); new(info); store(info, id); info->child = child; info->fin = pfdin[1]; /* Child's input */ info->fout = pfdout[0]; /* Child's output */ info->w = XmCreateScrolledText(area, "extern", args, XtNumber(args)); /* Install input handler to read child's output pipe */ info->id = XtAppAddInput(XtWidgetToApplicationContext(info->w), info->fout, (XtPointer) XtInputReadMask, out_cb, info->w); return TRUE; } /* writeExtern -- copy data to external viewer */ EXPORT int writeExtern(long id, const char *buf, size_t nchars) { Info info = find(id); int n; if (nchars != 0) { while ((n = write(info->fin, buf, nchars)) == -1 && errno == EINTR) ; return n; } else /* End of input */ return close(info->fin); } /* closeExtern -- close external viewer */ EXPORT Bool closeExtern(long id) { Info info = find(id); XtRemoveInput(info->id); (void) close(info->fin); (void) close(info->fout); XtDestroyWidget(info->w); kill(info->child, SIGKILL); dispose(info); return TRUE; } /* infoExtern -- change document info, if needed */ EXPORT Bool infoExtern(long id, W3ADocumentInfo *info) { return TRUE; /* No changes */ } EXPORT void eventExtern(long id, long sourceid, long eventtype, void *params) { /* Doesn't handle W3A events */ }