v04i065: xtroff -- troff previewer for X11, Part18/18
Dan Heller
argv at island.uu.net
Fri Jul 21 04:57:55 AEST 1989
Submitted-by: Mark Moraes <moraes at ai.toronto.edu>
Posting-number: Volume 4, Issue 65
Archive-name: xtroff/part18
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 18 (of 18)."
# Contents: xtroff/xwindows.c
# Wrapped by moraes at neat.ai on Thu Jul 13 20:55:26 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xtroff/xwindows.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'xtroff/xwindows.c'\"
else
echo shar: Extracting \"'xtroff/xwindows.c'\" \(35916 characters\)
sed "s/^X//" >'xtroff/xwindows.c' <<'END_OF_FILE'
X#ifndef SUNTOOLS
X/*
X * X Windows routines - These pretty closely mirror the SunView
X * interface in sunwindows.c. The main difference is that this has more
X * and more flexible bindings, and has the Next-Section, Prev-Section
X * bindings. This one also lacks the StatusPanel stuff - nice, but
X * somewhat unnecessary in my opinion. Instead, it has an emacs-style
X * Minibuffer at the bottom for interaction. It also lacks the feature
X * to Print the file or page - sheer laziness. The code is there - just
X * didn't bother to call the routines because it also means fixing the
X * printcaps. Sigh! The suntroff code is remarkably independent of the
X * window system - the routines in this file or windows.c set up the
X * frame window (a Form), the drawing window (Chris Peterson's
X * Window.c, lifted straight from xman. It should be in Xaw), the event
X * handlers, and menus(the menu widget in contrib/menus). The only
X * other X dependent code is in draw.c and a small chunk in the
X * LoadFontBits() routine in font.c! Its been ifdef'ed assuming
X * that if you're not compiling for SUNTOOLS, you're compiling for
X * X11. - Mark Moraes.
X */
X#ifndef lint
Xstatic char rcsid[]="$Header: xwindows.c,v 1.6 89/03/01 23:38:29 xwindows Exp $";
X#endif
X
X#include <stdio.h>
X#include <ctype.h>
X#include <signal.h>
X#include <X11/Intrinsic.h>
X#include <X11/StringDefs.h>
X#include <X11/Shell.h>
X#include <X11/Scroll.h>
X#include <X11/Form.h>
X#include "Window.h" /* Chris Peterson's Window widget */
X#include "Minibuf.h" /* My Minibuf widget */
X#include "Menu.h" /* contrib/menus after Dana Chee's fixes */
X#include <X11/cursorfont.h>
X#include <X11/Xutil.h>
X
X#define YES 1
X#define NO 0
X#define ABORT -1
X
X/*
X * These are the various actions allowed in the canvas window - each
X * related to a procedure
X */
Xstatic void StartPan(), EndPan(), PagePan(), Number(), EscapeNumber(),
X GoToPage(), ForwardPage(), BackPage(), NextSection(), PrevSection(),
X Quit(), SetMenuPos(), MenuSelection(), Popdown(), Rerasterize(),
X MousePrintPage(), MousePrintDocument();
X
Xstatic XtActionsRec canvasActionTable[] = {
X {"SetMenuPos", SetMenuPos},
X {"start-pan", StartPan},
X {"end-pan", EndPan},
X {"page-pan", PagePan},
X {"number", Number},
X {"escape", EscapeNumber},
X {"go-to-page", GoToPage},
X {"forward-page",ForwardPage},
X {"back-page", BackPage},
X {"print-page", MousePrintPage},
X {"print-document", MousePrintDocument},
X {"next-section",NextSection},
X {"prev-section",PrevSection},
X {"rerasterize", Rerasterize},
X {"quit", Quit},
X};
X
X/* We want the menu to go away when the button comes up */
Xstatic String menuTransTbl = "<Btn3Up>: MenuPopdown(popupShell)";
X
X/*
X * These are default bindings for the actions in the canvas window. All
X * actions except MenuPopup and MenuPopdown are defined in the action
X * table above, and have corresp callback routines in this file.
X * MenuPopup and MenuPopdown are provided by the Xt Intrinsics - for
X * some reason, it doesn't seem possible to create a spring-loaded
X * shell from an application other than by these two actions. I'd have
X * preferred an XtPopup() with a spring-loaded parameter, and there's
X * even such a routine in the Toolkit - _XtPopup! Of course, I may
X * just be missing something obvious... I plead guilty to complete
X * (well, almost complete) incomprehension of the Toolkit Intrinsics
X * doc. - moraes
X */
Xstatic String canvasTransTbl =
X "<Btn3Down>: SetMenuPos() MenuPopup(popupShell)\n\
X <Btn3Up>: MenuPopdown(popupShell)\n\
X <Btn2Down>: start-pan()\n\
X <Btn2Up>: end-pan()\n\
X <LeaveWindow>: end-pan()\n\
X <Btn2Motion>: page-pan()\n\
X <Key>0x30: number()\n\
X <Key>0x31: number()\n\
X <Key>0x32: number()\n\
X <Key>0x33: number()\n\
X <Key>0x34: number()\n\
X <Key>0x35: number()\n\
X <Key>0x36: number()\n\
X <Key>0x37: number()\n\
X <Key>0x38: number()\n\
X <Key>0x39: number()\n\
X <Key>0xff1b: escape()\n\
X Shift<Key>P: print-page()\n\
X <Key>P: back-page()\n\
X <Key>B: back-page()\n\
X <Key>-: back-page()\n\
X <Key>0xff7f: back-page()\n\
X <Key>0xff08: back-page()\n\
X <Key>0xffff: back-page()\n\
X Ctrl<Key>H: back-page()\n\
X <Key>0xff51: back-page()\n\
X <Key>N: forward-page()\n\
X <Key>F: forward-page()\n\
X <Key>+: forward-page()\n\
X <Key>0xff0d: forward-page()\n\
X Ctrl<Key>M: forward-page()\n\
X <Key>0xff0a: forward-page()\n\
X Ctrl<Key>J: forward-page()\n\
X <Key>0xff53: forward-page()\n\
X Shift<Btn1Down>:prev-section()\n\
X <Key>0xff52: prev-section()\n\
X <Btn1Down>: next-section()\n\
X <Key>0x20: next-section()\n\
X <Key>0xff54: next-section()\n\
X <Key>G: go-to-page()\n\
X <Key>R: rerasterize()\n\
X <Key>Q: quit()\n\
X ";
X
X#include "suntroff.h"
X
X/* Preserved most of the sunview names */
XWindow OuterFrame;
XWidget BaseFrame; /* Top Level Window Frame */
XWidget CanvasWidget;
XWindow DrawingCanvas; /* Main Drawing Window for Text */
XWidget MainMenu; /* Top Level User Menu */
XWidget PopupShell; /* Popup Shell enclosing the Main menu */
XWidget HorizScroll; /* Horizontal Scroll Bar */
XWidget VertScroll; /* Vertical Scroll Bar */
XWidget InputWidget = NULL; /* Minibuffer widget for input and dislay */
XWindow InputWin;
XPixmap PagePixRect; /* Full Page Pix Rect for Drawing Page */
Xint ViewLeft = 0, ViewTop = 0; /* Page Offset for display */
X/* Set these to the window height and width */
Xint ViewWidth = 0, ViewHeight = 0;
Xint OriginalX = -1;
Xint OriginalY = -1;
Xint Scrollbars = 1; /* Does User want scrollbars????? */
Xchar *homeDir;
Xchar *Printer;
X
X/*
X * The following icon of a hand was generated by Stefano Concino at SPAR.
X */
X#define hand_width 16
X#define hand_height 16
X#define hand_x_hot 8
X#define hand_y_hot 8
Xstatic char hand_bits[] = {
X 0x80, 0x00, 0x40, 0x09, 0x48, 0x15, 0x54, 0x15, 0x54, 0x15, 0x54, 0x15,
X 0x54, 0x15, 0x54, 0x15, 0x74, 0xd2, 0x04, 0xa8, 0x08, 0xa8, 0x18, 0xa8,
X 0x30, 0x90, 0x20, 0x40, 0x20, 0x20, 0x60, 0x18};
X
Xstatic char hand_mask_bits[] = {
X 0xc0, 0x09, 0x68, 0x1d, 0x7e, 0x37, 0x76, 0x37, 0x76, 0x37, 0x76, 0x37,
X 0x76, 0x37, 0x76, 0xf7, 0x76, 0xf2, 0x06, 0xb8, 0x0e, 0xb8, 0x1c, 0xb8,
X 0x3c, 0x90, 0x38, 0xc0, 0x30, 0x60, 0x70, 0x38};
X
X#include "ditroff.bm"
X
XCursor HandCursor;
XCursor WorkingCursor;
XCursor WaitCursor;
XCursor TextCursor;
X
XXWMHints xwmh;
X
XPixel fgcolor, bgcolor;
X/* Needed for the undocumented XCreatePixmapCursor() */
Xstatic XColor bg = {0, 0, 0, 0};
Xstatic XColor fg = {0, ~0, ~0, ~0};
Xunsigned int depth;
XDimension xwidth, xheight;
X
XDisplay *dpy;
XScreen *scn;
XGC gc; /* The Graphic context we use for all drawing */
XGC fillgc; /* Used for filled objects - presently only bullets */
XGC cleargc; /* The GC used for clearing the Pixmap */
X
X/*
X * DON'T CHANGE THE ORDER OF THE ARGS IN THE VARIOUS ARG STRUCTS. IF
X * YOU WANT TO ADD STUFF, ADD IT AT THE END OF THE STRUCT, BECAUSE WE
X * REFER TO SOME OF THE ELEMENTS BY POSITION IN THE CODE.
X */
X/* No spacing between the widgets on the Form */
Xstatic Arg form_args[] = {
X {XtNdefaultDistance, (XtArgVal) 0},
X};
X
Xstatic void finished_input();
Xstatic XtCallbackRec minibufCallbacks[] = {
X {finished_input, NULL},
X {NULL, NULL},
X};
X
Xstatic Arg minibuf_args[] = {
X {XtNwidth, (XtArgVal) 0},
X {XtNfinishedCallback, (XtArgVal) minibufCallbacks},
X {XtNfromVert, (XtArgVal) NULL},
X {XtNresizable, (XtArgVal) False},
X};
X
X/* we use this when we ask what the various attributes of the Canvas. */
Xstatic Arg query_args[] = {
X {XtNbackground, (XtArgVal) &bgcolor},
X {XtNforeground, (XtArgVal) &fgcolor},
X {XtNwidth, (XtArgVal) &xwidth},
X {XtNheight, (XtArgVal) &xheight},
X};
X
X/* args for the canvas window - we fill in translations by hand */
Xstatic Arg canvas_args[] = {
X {XtNwidth, (XtArgVal) 950},
X {XtNheight, (XtArgVal) 830},
X {XtNfromHoriz, (XtArgVal) NULL},
X {XtNtranslations, 0},
X};
X
Xstatic void Scrolled();
Xstatic XtCallbackRec scrollCallbacks[] = {
X { Scrolled, NULL },
X { NULL, NULL },
X};
X
Xstatic void Jumped();
Xstatic XtCallbackRec jumpCallbacks[] = {
X { Jumped, NULL },
X { NULL, NULL },
X};
X
X/*
X * We change the XtNlength, XtNorientation and XtNfromHoriz by getting
X * the size from the Canvas - don't take this value seriously.
X * XtNfromHoriz also changes to XtNfromVert.
X */
Xstatic Arg scroll_args[] = {
X {XtNlength, (XtArgVal) 850},
X {XtNorientation, (XtArgVal) XtorientVertical},
X {XtNfromHoriz, (XtArgVal) NULL},
X {XtNscrollProc, (XtArgVal) scrollCallbacks},
X {XtNjumpProc, (XtArgVal) jumpCallbacks},
X};
X
Xstatic MenuItemsList menu_list[] = {
X {"Rerasterize", MenuSelection, (caddr_t) 1, 0},
X {"Next Page", MenuSelection, (caddr_t) 2, 0},
X {"Previous Page", MenuSelection, (caddr_t) 3, 0},
X {"Next Page Section", MenuSelection, (caddr_t) 4, 0},
X {"Previous Page Section", MenuSelection, (caddr_t) 5, 0},
X {"Show Status", MenuSelection, (caddr_t) 6, 0},
X {"Search Forward", MenuSelection, (caddr_t) 7, 0},
X {"Search Backward", MenuSelection, (caddr_t) 8, 0},
X {"Change File", MenuSelection, (caddr_t) 9, 0},
X {"Change Command", MenuSelection, (caddr_t) 10, 0},
X {"Go To Page", MenuSelection, (caddr_t) 11, 0},
X {"Print Page", MenuSelection, (caddr_t) 12, 0},
X {"Print Document", MenuSelection, (caddr_t) 13, 0},
X {"Set Printer", MenuSelection, (caddr_t) 14, 0},
X {"Quit", MenuSelection, (caddr_t) 0, 0},
X {NULL, NULL, NULL, NULL}
X};
X
Xstatic Arg menu_args[] = {
X {XtNmenuItemsList, (XtArgVal) menu_list },
X {XtNtranslations, 0},
X};
X
Xstatic Arg shell_args[] = {
X {XtNtranslations, 0},
X};
X
Xstatic int CurrentPage = 1;
Xchar FileName[BUFSIZ] = ""; /* File containing ditroff output */
Xchar TempFileName[BUFSIZ]; /* Temp file that can be deleted. */
Xchar CommandString[BUFSIZ] = "";/* String pointer to ditroff command */
Xchar *ActualFileName; /* File that buffers ditroff output */
Xint PageRequest = 0; /* Partially read page number request */
Xint CommandMode = 0; /* Taking input from file or command line */
X/* not used in the X version - we don't print any messages. sigh! one day... */
Xint ErrorsPending = 0; /* Set if errors are pending and need to be
X * displayed. Used in case tool is iconic
X * when error message is needed. This boolean
X * variable is checked at redisplay time.
X * This was done at the suggestion of
X * davy at ecn.purdue.edu.......11/28/86
X */
Xint isMapped = 0;
Xchar *SearchItem;
Xint SUNRES = 120;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X char *option;
X XGCValues gcv; /* Struct for creating GC */
X Pixmap cursorPixmap, cursorMask;
X void RepaintCanvas();
X static void RecordMapStatus();
X Widget topLevel;
X XtTranslations canvasTranslations;
X XtTranslations menuTranslations;
X extern char *getenv();
X
X if ((homeDir = getenv("HOME")) == NULL)
X homeDir = "";
X if ((Printer = getenv("PRINTER")) == NULL)
X Printer = "PostScript";
X /* make the top level using argc, argv */
X topLevel = XtInitialize("xtroff", "TroffPreviewer",
X (XrmOptionDescRec *) NULL, 0, (Cardinal *) &argc, argv);
X dpy = XtDisplay(topLevel);
X scn = XtScreen(topLevel);
X depth = DefaultDepthOfScreen(scn);
X /* just one option for ourselves - rest are Toolkit options */
X if (option = XGetDefault(dpy, "xtroff", "scrollbar")) {
X if (strcmp(option, "on") == 0)
X Scrollbars = 1;
X else
X Scrollbars = 0;
X }
X argv++;
X while (*argv && argv[0][0] == '-'){
X if (strncmp(argv[0],"-scrollbar",4) == NULL){
X Scrollbars = 0;
X } else if (strncmp(argv[0],"-full",3) == NULL){
X SUNRES = 75;
X canvas_args[0].value = 647;
X } else if (strncmp(argv[0],"-command",3) == NULL){
X *CommandString = '\0';
X while (*++argv) {
X strcat(CommandString,*argv);
X strcat(CommandString, " ");
X }
X CommandMode = 1;
X } else {
X fprintf(stderr,"Unknown option %s\n",argv[0]);
X }
X if (*argv){
X argv++;
X }
X }
X if (argv[0] && argv[0][0]){
X CommandMode = 0;
X strcpy(FileName,argv[0]);
X }
X#ifdef DEBUG
X if (CommandMode)
X printf("Command = \"%s\"\n", CommandString);
X else {
X if (FileName) printf("File = \"%s\"\n", FileName);
X else printf ("reading from stdin");
X }
X#endif
X /* CreatePopUpPanel(); */
X XtAddActions(canvasActionTable, XtNumber(canvasActionTable));
X canvasTranslations = XtParseTranslationTable(canvasTransTbl);
X BaseFrame = XtCreateManagedWidget("form", formWidgetClass, topLevel,
X form_args, XtNumber(form_args));
X canvas_args[3].value = (XtArgVal) canvasTranslations;
X CanvasWidget = XtCreateManagedWidget("canvas", windowWidgetClass,
X BaseFrame, canvas_args, XtNumber(canvas_args));
X XtGetValues(CanvasWidget, query_args, XtNumber(query_args));
X ViewWidth = xwidth;
X ViewHeight = xheight;
X if (Scrollbars) {
X /* vertical scrollbar to the right of the canvas */
X XtSetArg(scroll_args[0], XtNlength, xheight);
X XtSetArg(scroll_args[2], XtNfromHoriz, CanvasWidget);
X VertScroll = XtCreateManagedWidget("vscroll",
X scrollbarWidgetClass, BaseFrame,
X scroll_args, XtNumber(scroll_args));
X /* horizontal scrollbar below the canvas */
X XtSetArg(scroll_args[0], XtNlength, xwidth);
X XtSetArg(scroll_args[1], XtNorientation, XtorientHorizontal);
X XtSetArg(scroll_args[2], XtNfromVert, CanvasWidget);
X HorizScroll = XtCreateManagedWidget("hscroll",
X scrollbarWidgetClass, BaseFrame,
X scroll_args, XtNumber(scroll_args));
X }
X XtAddEventHandler(CanvasWidget, (EventMask) ExposureMask, NULL,
X RepaintCanvas, "redraw_data");
X XtAddEventHandler(CanvasWidget, (EventMask) StructureNotifyMask, NULL,
X RecordMapStatus, "map_data");
X /*
X * make a menu or button box - ShowStatus, ReRasterize, Print,
X * Print Page, previous Page, Next Page, Quit
X */
X menuTranslations = XtParseTranslationTable(menuTransTbl);
X shell_args[0].value = menu_args[1].value = (XtArgVal) menuTranslations;
X PopupShell = XtCreatePopupShell ("popupShell",
X overrideShellWidgetClass,
X CanvasWidget,
X (ArgList) shell_args,
X XtNumber(shell_args));
X MainMenu = XtCreateManagedWidget ("mainMenu",
X menuWidgetClass,
X PopupShell,
X (ArgList) menu_args,
X XtNumber (menu_args));
X minibuf_args[0].value = (XtArgVal) ViewWidth;
X if (Scrollbars)
X minibuf_args[2].value = (XtArgVal) HorizScroll;
X else
X minibuf_args[2].value = (XtArgVal) CanvasWidget;
X InputWidget = XtCreateManagedWidget("minibuf", minibufWidgetClass,
X BaseFrame, minibuf_args, XtNumber(minibuf_args));
X XtRealizeWidget(topLevel);
X DrawingCanvas = XtWindow(CanvasWidget);
X OuterFrame = XtWindow(topLevel);
X InputWin = XtWindow(InputWidget);
X
X fg.pixel = fgcolor;
X bg.pixel = bgcolor;
X XQueryColor(dpy, DefaultColormapOfScreen(scn), &fg);
X XQueryColor(dpy, DefaultColormapOfScreen(scn), &bg);
X cursorPixmap = XCreateBitmapFromData(dpy, DrawingCanvas,
X hand_bits, hand_width, hand_height);
X cursorMask = XCreateBitmapFromData(dpy, DrawingCanvas,
X hand_mask_bits, hand_width, hand_height);
X HandCursor = XCreatePixmapCursor(dpy, cursorPixmap, cursorMask,
X &fg, &bg, hand_x_hot, hand_y_hot);
X XFreePixmap(dpy, cursorPixmap);
X XFreePixmap(dpy, cursorMask);
X
X xwmh.icon_pixmap = XCreatePixmapFromBitmapData(dpy, XtWindow(topLevel),
X ditroff_bits, ditroff_width, ditroff_height, fgcolor, bgcolor, depth);
X xwmh.flags = IconPixmapHint;
X XSetWMHints(dpy, XtWindow(topLevel), &xwmh);
X WorkingCursor = XCreateFontCursor(dpy, XC_diamond_cross);
X WaitCursor = XCreateFontCursor(dpy, XC_watch);
X TextCursor = XCreateFontCursor(dpy, XC_xterm);
X XDefineCursor(dpy, DrawingCanvas, WorkingCursor);
X gcv.font = XLoadFont(dpy, "variable");
X gcv.foreground = fgcolor;
X gcv.background = bgcolor;
X gcv.function = GXcopy;
X gc = XCreateGC(dpy, DrawingCanvas,
X (GCForeground | GCBackground | GCFunction | GCFont), &gcv);
X gcv.foreground = bgcolor;
X gcv.background = fgcolor;
X cleargc = XCreateGC(dpy, DrawingCanvas,
X (GCForeground | GCBackground | GCFunction), &gcv);
X gcv.foreground = fgcolor;
X gcv.background = bgcolor;
X gcv.function = GXcopy;
X gcv.fill_style = FillSolid;
X gcv.arc_mode = ArcPieSlice;
X fillgc = XCreateGC(dpy, DrawingCanvas,
X (GCForeground | GCBackground | GCFunction | GCFillStyle | GCArcMode),
X &gcv);
X /* Alloc a 1 bit deep pixmap if PAGE_PIXEL_WIDTH X PAGE_PIXEL_HEIGHT */
X PagePixRect = XCreatePixmap(dpy, DrawingCanvas,
X (unsigned int) PAGE_PIXEL_WIDTH, (unsigned int) PAGE_PIXEL_HEIGHT,
X depth);
X XFlush(dpy);
X /*
X * We'll keep changing fonts - simpler, but is it fast enough?
X * Should we try setting the font path
X */
X#ifdef DEBUG
X {
X int nfonts;
X int i;
X char **fonts = XGetFontPath(dpy, &nfonts);
X for (i = 0; i < nfonts; i++) {
X printf("\"%s\"\n", fonts[i]);
X }
X XFreeFontPath(fonts);
X }
X#endif
X XtMainLoop();
X if (*TempFileName)
X (void) unlink(TempFileName);
X exit(0);
X}
X
X/*ARGSUSED*/
Xvoid
XRepaintCanvas(w, data, ev)
XWidget w;
Xcaddr_t data;
XXEvent *ev;
X{
X static rastered = 0;
X
X if (!isMapped)
X return;
X
X /*
X Put the pixmap on the screen at the appropriate
X ViewLeft, ViewTop;
X */
X if (ev && ev->xexpose.count == 0) {
X XEvent event;
X /* Skip all excess redraws */
X while (XCheckTypedEvent(dpy, Expose, &event))
X ;
X }
X
X if( !rastered && ev)
X {
X rastered = 1;
X Rerasterize(BaseFrame, (XEvent *) NULL, (String *) NULL,
X (Cardinal *) NULL);
X }
X SetScrollBar();
X
X#ifdef WINDOWDEBUG
X printf("repaint - ViewLeft = %d, Top = %d, Width = %d, Height = %d\n",
X ViewLeft, ViewTop, ViewWidth, ViewHeight);
X#endif
X XCopyArea(dpy, PagePixRect, DrawingCanvas, gc, ViewLeft, ViewTop,
X (unsigned int) ViewWidth, (unsigned int) ViewHeight, 0, 0);
X XFlush(dpy);
X}
X
X/*ARGSUSED*/
Xstatic void
XRecordMapStatus(w, data, ev)
XWidget w;
Xcaddr_t data;
XXEvent *ev;
X{
X if (ev->type == MapNotify) {
X#ifdef WINDOWDEBUG
X printf("window mapped\n");
X#endif
X isMapped = TRUE;
X RepaintCanvas(CanvasWidget, (caddr_t) NULL, (XEvent *) NULL);
X } else if (ev->type = ConfigureNotify) {
X XConfigureEvent *cev = (XConfigureEvent *) ev;
X#ifdef WINDOWDEBUG
X printf("window resized\n");
X#endif
X if (cev->width != ViewWidth || cev->height != ViewHeight) {
X ViewWidth = cev->width;
X ViewHeight = cev->height;
X ResizeScrollBar();
X }
X }
X}
X
X
X
X/*ARGSUSED*/
Xstatic void
XStartPan(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXMotionEvent *event;
X{
X OriginalX = event->x;
X OriginalY = event->y;
X#ifdef DEBUG
X printf("starting pan from %d, %d\n", OriginalX, OriginalY);
X#endif
X XDefineCursor(dpy, DrawingCanvas, HandCursor);
X PageRequest = 0;
X}
X
X/*ARGSUSED*/
Xstatic void
XEndPan(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXMotionEvent *event;
X{
X if (OriginalX != -1 && OriginalY != -1){
X OriginalX = OriginalY = -1;
X#ifdef DEBUG
X printf("ending pan\n");
X#endif
X XDefineCursor(dpy, DrawingCanvas, WorkingCursor);
X }
X PageRequest = 0;
X}
X
X/*ARGSUSED*/
Xstatic void
XPagePan(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXMotionEvent *event;
X{
X ViewLeft -= event->x - OriginalX;
X if (ViewLeft + ViewWidth > PAGE_PIXEL_WIDTH)
X ViewLeft = PAGE_PIXEL_WIDTH - ViewWidth;
X if (ViewLeft < 0)
X ViewLeft = 0;
X
X ViewTop -= event->y - OriginalY;
X if (ViewTop + ViewHeight > PAGE_PIXEL_HEIGHT)
X ViewTop = PAGE_PIXEL_HEIGHT - ViewHeight;
X if (ViewTop < 0)
X ViewTop = 0;
X#ifdef DEBUG
X printf("panning - ViewLeft, Top = %d, %d\n", ViewLeft, ViewTop);
X#endif
X if ((OriginalX != event->x) || (OriginalY != event->y)){
X XCopyArea(dpy, PagePixRect, DrawingCanvas, gc, ViewLeft,
X ViewTop, (unsigned int) ViewWidth, (unsigned int) ViewHeight,
X 0, 0);
X#ifdef DEBUG
X printf("panned\n");
X#endif
X OriginalX = event->x;
X OriginalY = event->y;
X SetScrollBar();
X }
X PageRequest = 0;
X}
X
X
X/*ARGSUSED*/
Xstatic void
XNumber(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X char ch;
X
X XLookupString(&event->xkey, &ch, 1, (KeySym *) NULL,
X (XComposeStatus *) NULL);
X PageRequest = PageRequest*10 + ch - '0';
X#ifdef WINDOWDEBUG
X printf("ch = %c, arg = %d\n", ch, PageRequest);
X#endif
X
X}
X
X/*ARGSUSED*/
Xstatic void
XEscapeNumber(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X PageRequest = 0;
X#ifdef WINDOWDEBUG
X printf("arg = 0\n");
X#endif
X}
X
X
X/*ARGSUSED*/
Xstatic void
XGoToPage(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X#ifdef WINDOWDEBUG
X printf("goto page %d\n", PageRequest);
X#endif
X ViewTop = 0;
X CurrentPage = ShowPage(PageRequest);
X PageRequest = 0;
X}
X
X/*ARGSUSED*/
Xstatic void
XBackPage(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X int curpage = CurrentPage;
X
X if (!PageRequest)
X PageRequest++;
X CurrentPage -= PageRequest;
X if (CurrentPage <= 0)
X CurrentPage = 1;
X if (CurrentPage != curpage) {
X ViewTop = 0;
X CurrentPage = ShowPage(CurrentPage);
X }
X PageRequest = 0;
X}
X
X/*ARGSUSED*/
Xstatic void
XForwardPage(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X if (!PageRequest)
X PageRequest++;
X CurrentPage += PageRequest;
X ViewTop = 0;
X CurrentPage = ShowPage(CurrentPage);
X PageRequest = 0;
X}
X
X/*ARGSUSED*/
Xstatic void
XPrevSection(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X int curpage = CurrentPage;
X
X /*
X * Back up to the previous section to be viewed. If
X * the screen is large enough to show the whole
X * page, then back up to the previous page. Else
X * back up to the previous half of the page. Only
X * change ViewTop - leave ViewLeft alone as
X * part of the philosophy - in general, the
X * width of the page fits nicely on the screen
X */
X do {
X ViewTop -= ViewHeight;
X if (ViewTop <= -ViewHeight) {
X if (CurrentPage > 1) {
X ViewTop = PAGE_PIXEL_HEIGHT - ViewHeight;
X CurrentPage--;
X } else {
X CurrentPage = 1;
X ViewTop = 0;
X break;
X }
X } else if (ViewTop < 0) {
X ViewTop = 0;
X }
X } while (--PageRequest > 0);
X if (curpage != CurrentPage)
X CurrentPage = ShowPage(CurrentPage);
X else
X RefreshPage();
X PageRequest = 0;
X}
X
X
X/*ARGSUSED*/
Xstatic void
XNextSection(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X int curpage = CurrentPage;
X
X /*
X * Advance to the next section to be viewed. If
X * the screen is large enough to show the whole
X * page, then advance to the next page. Else
X * advance to the next half of the page. Only
X * change ViewTop - leave ViewLeft alone as
X * part of the philosophy - in general, the
X * width of the page fits nicely on the screen
X */
X do {
X ViewTop += ViewHeight;
X if (ViewTop >= PAGE_PIXEL_HEIGHT) {
X ViewTop = 0;
X CurrentPage++;
X } else if (ViewTop > PAGE_PIXEL_HEIGHT - ViewHeight) {
X ViewTop = PAGE_PIXEL_HEIGHT - ViewHeight;
X }
X } while (--PageRequest > 0);
X if (curpage != CurrentPage)
X CurrentPage = ShowPage(CurrentPage);
X else
X RefreshPage();
X PageRequest = 0;
X}
X
Xstatic void MousePrintPage()
X{
X PrintPage(CurrentPage, Printer);
X}
X
Xstatic void MousePrintDocument()
X{
X PrintDocument(ActualFileName, Printer);
X
X}
X
X
X/*ARGSUSED*/
Xstatic void
XQuit(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X if (*TempFileName)
X (void) unlink(TempFileName);
X exit(0);
X}
X
X
X/* These are the scrolling and jumping (thumbing no longer supported)
X callbacks */
X/*ARGSUSED*/
Xstatic void
XScrolled(w, closure, call_data)
XWidget w;
Xcaddr_t closure;
Xint call_data;
X{
X#ifdef WINDOWDEBUG
X printf( "scrolled by %d pixels.\n", call_data );
X#endif
X if (w == VertScroll) {
X ViewTop += call_data * PAGE_PIXEL_HEIGHT / ViewHeight;
X if (ViewTop < 0)
X ViewTop = 0;
X else if (ViewTop > PAGE_PIXEL_HEIGHT - ViewHeight)
X ViewTop = PAGE_PIXEL_HEIGHT - ViewHeight;
X } else if (w == HorizScroll) {
X ViewLeft += call_data * PAGE_PIXEL_WIDTH / ViewWidth;
X if (ViewLeft < 0)
X ViewLeft = 0;
X else if (ViewLeft > PAGE_PIXEL_WIDTH - ViewWidth)
X ViewLeft = PAGE_PIXEL_WIDTH - ViewWidth;
X }
X
X XCopyArea(dpy, PagePixRect, DrawingCanvas, gc, ViewLeft, ViewTop,
X (unsigned int) ViewWidth, (unsigned int) ViewHeight, 0, 0);
X SetScrollBar();
X}
X
X
X/*ARGSUSED*/
Xstatic void
XJumped(w, closure, percent)
XWidget w;
Xcaddr_t closure;
Xcaddr_t percent;
X{
X float top = *((float *) percent);
X#ifdef WINDOWDEBUG
X printf( "thumbed to %f%%\n", top );
X#endif
X if (w == VertScroll) {
X ViewTop = top * PAGE_PIXEL_HEIGHT;
X if (ViewTop > PAGE_PIXEL_HEIGHT - ViewHeight)
X ViewTop = PAGE_PIXEL_HEIGHT - ViewHeight;
X } else if (w == HorizScroll) {
X ViewLeft = top * PAGE_PIXEL_WIDTH;
X if (ViewLeft > PAGE_PIXEL_WIDTH - ViewWidth)
X ViewLeft = PAGE_PIXEL_WIDTH - ViewWidth;
X }
X XCopyArea(dpy, PagePixRect, DrawingCanvas, gc, ViewLeft, ViewTop,
X (unsigned int) ViewWidth, (unsigned int) ViewHeight, 0, 0);
X SetScrollBar();
X}
X
X
XSetScrollBar()
X{
X if (!Scrollbars)
X return;
X XtScrollBarSetThumb(VertScroll,
X (float) ((float) ViewTop / (float) PAGE_PIXEL_HEIGHT),
X (float) ((float) ViewHeight / (float) PAGE_PIXEL_HEIGHT));
X XtScrollBarSetThumb(HorizScroll,
X (float) ((float) ViewLeft / (float) PAGE_PIXEL_WIDTH),
X (float) ((float) ViewWidth / (float) PAGE_PIXEL_WIDTH));
X}
X
XResizeScrollBar()
X{
X Dimension tmp;
X if (!Scrollbars)
X return;
X tmp = (Dimension) ViewHeight;
X XtSetArg(scroll_args[0], XtNlength, tmp);
X XtSetValues(VertScroll, scroll_args, 1);
X tmp = (Dimension) ViewWidth;
X XtSetArg(scroll_args[0], XtNlength, tmp);
X XtSetValues(HorizScroll, scroll_args, 1);
X SetScrollBar();
X}
X
X
XSearchForward(){
X int i;
X
X i = SearchFile(SearchItem,CurrentPage,1);
X if (i){
X CurrentPage = i;
X ShowPage(i);
X } else {
X SetTitleBar("Displaying",CurrentPage);
X }
X return(i);
X}
X
XSearchBackward(){
X int i;
X
X i = SearchFile(SearchItem,CurrentPage,-1);
X if (i){
X CurrentPage = i;
X ShowPage(i);
X } else {
X SetTitleBar("Displaying",CurrentPage);
X }
X return(i);
X}
X
X
X/*ARGSUSED*/
Xstatic void
XRerasterize(w, event, params, nparams)
XWidget w;
XString *params;
XCardinal *nparams;
XXEvent *event;
X{
X#ifndef STANDALONE
X static FILE *FilePointer = 0;
X static FILE *PipePointer = 0;
X static int ProcessPid = 0;
X extern char *mktemp();
X
X if (FilePointer && FilePointer != stdin){
X (void) fclose(FilePointer);
X }
X if (PipePointer){
X (void) fclose(PipePointer);
X (void) kill(ProcessPid, SIGKILL);
X }
X ProcessPid = 0;
X PipePointer = FilePointer = 0;
X
X if (!CommandMode && FileName != NULL && FileName[0] != '\0'){
X FilePointer = fopen(FileName,"r");
X if (!FilePointer){
X warning("Can't open %s for reading input.\n",
X FileName);
X } else {
X ActualFileName = FileName;
X InitializeFile(FilePointer, FilePointer);
X }
X } else {
X static char FileName[BUFSIZ], *p;
X int PipeFds[2];
X
X if (CommandMode) {
X p = CommandString;
X if (!p){
X while (isspace(*p))
X p++;
X }
X if (!p || !*p){
X warning("Rasterize called without a command.\nUse the menu to set a command.");
X return;
X }
X }
X
X (void) pipe(PipeFds); /* Get two halves of pipe */
X
X ProcessPid = fork(); /* And then Fork */
X if (ProcessPid == -1) {
X warning("Couldn't fork. Help\n");
X return;
X }
X if (!ProcessPid){ /* First the Child */
X int y;
X
X close(1);
X dup2(PipeFds[1], 1);
X for( y = 3; y < getdtablesize(); y++)
X close(y);
X
X if (!CommandMode) {
X execl("/bin/cat", (char *) 0);
X fatal("Someone stole /bin/cat - help!\n");
X } else {
X system(p);
X exit(0);
X }
X /*NOTREACHED*/
X }
X
X PipePointer = fdopen(PipeFds[0], "r");
X (void) close(PipeFds[1]);
X
X if (*TempFileName) {
X (void) strcpy(FileName, TempFileName);
X } else {
X (void) strcpy(FileName,"/tmp/suntroff.XXXXXX");
X (void) mktemp(FileName);
X (void) strcpy(TempFileName, FileName);
X }
X
X FilePointer = fdopen(open(FileName,
X O_RDWR|O_CREAT|O_TRUNC,0644), "r+");
X
X if (!FilePointer){
X (void) fprintf(stderr,
X "Can't open buffer file for the command:\n");
X (void) fprintf(stderr,"\t%s\n", CommandString);
X exit(1);
X }
X ActualFileName = FileName;
X InitializeFile(PipePointer, FilePointer);
X }
X
X ShowPage(CurrentPage);
X#endif STANDALONE
X}
X
X/*
X * For those without a window manager that puts titlebars, maybe we
X * should put a Label widget
X */
XSetTitleBar(status,PageNumber)
Xchar *status;
Xint PageNumber;
X{
X extern char *DefaultTitle;
X char Buffer[BUFSIZ];
X char TempStatus[BUFSIZ];
X int FrameWidth, Width, i;
X
X /* No way of getting this from the window manager, is there? */
X FrameWidth = 60;
X
X if (PageNumber >= 0)
X (void) sprintf(TempStatus,"%s Page %d",status,PageNumber);
X else
X (void) sprintf(TempStatus, "%s", status);
X
X strncpy(Buffer,DefaultTitle,BUFSIZ);
X i = strlen(DefaultTitle);
X
X Width = strlen(TempStatus);
X
X while (i + Width < FrameWidth){
X Buffer[i++] = ' ';
X }
X if (FrameWidth - i > 0){
X strncpy(&Buffer[i],TempStatus,FrameWidth-i);
X }
X XStoreName(dpy, OuterFrame, Buffer);
X#if 0
X if (PageNumber >= 0){
X (void) sprintf(PageNumberValue,"%d",PageNumber);
X panel_set_value(PageItem,PageNumberValue);
X }
X#endif
X if (STREQ(status, "Displaying"))
X XDefineCursor(dpy, DrawingCanvas, WorkingCursor);
X else
X XDefineCursor(dpy, DrawingCanvas, WaitCursor);
X XFlush(dpy);
X}
X
Xstatic char *SavedTitleBar = NULL;
X
XSaveTitleBar(){
X XFetchName(dpy, OuterFrame, &SavedTitleBar);
X XFlush(dpy);
X}
X
XRestoreTitleBar(){
X if (SavedTitleBar) {
X XStoreName(dpy, OuterFrame, SavedTitleBar);
X XFlush(dpy);
X XDefineCursor(dpy, DrawingCanvas, WorkingCursor);
X }
X}
X
X#include <varargs.h>
X
X/*VARARGS0*/
Xfatal(va_alist)
Xva_dcl
X{
X va_list args;
X char *fmt;
X
X va_start(args);
X fprintf(stderr,"Fatal Error: ");
X fmt = va_arg(args, char *);
X (void) vfprintf(stderr,fmt,args);
X va_end(args);
X if (*TempFileName)
X (void) unlink(TempFileName);
X exit(1);
X}
X
X/*VARARGS0*/
Xwarning(va_alist)
Xva_dcl
X{
X va_list args;
X char *fmt;
X char Message[BUFSIZ];
X
X va_start(args);
X fmt = va_arg(args, char *);
X (void) vsprintf(Message,fmt,args);
X va_end(args);
X message(Message);
X}
X
X
X/*
X * We move the menu to the current mouse location before popping it up
X * with MenuPopup. Pity MenuPopup doesn't do this!
X */
X/*ARGSUSED*/
Xstatic void
XSetMenuPos (w, clientdata, calldata)
XWidget w;
Xcaddr_t clientdata;
Xcaddr_t calldata;
X{
X Window root, child;
X int rootx, rooty, winx, winy;
X unsigned int mask;
X
X XQueryPointer(XtDisplay(w), XtWindow(w), &root, &child,
X &rootx, &rooty, &winx, &winy, &mask);
X /*
X * The -OFFSET,-OFFSET displacement just makes sure mouse is in
X * the menu
X */
X#define OFFSET 10
X XtMoveWidget(PopupShell, (Position) (rootx - OFFSET),
X (Position) rooty - OFFSET);
X}
X
X
X/*ARGSUSED*/
Xstatic void
XMenuSelection (widget, closure, call_data)
XWidget widget;
Xcaddr_t closure, call_data;
X{
X char *get_input();
X char *tmpstr;
X char statusbuf[128];
X
X XtPopdown(PopupShell);
X XFlush(dpy);
X switch ((int) closure)
X {
X case 1:
X Rerasterize(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X case 2:
X ForwardPage(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X case 3:
X BackPage(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X case 4:
X NextSection(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X case 5:
X PrevSection(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X case 6:
X if (CommandMode) {
X (void) sprintf(statusbuf, "Command is \"%s\"",
X CommandString);
X } else {
X (void) sprintf(statusbuf, "File is \"%s\"",
X FileName);
X }
X message(statusbuf);
X break;
X case 7:
X tmpstr = get_input(": search-forward ? ",
X SearchItem, FALSE);
X if (tmpstr) {
X if (SearchItem)
X free(SearchItem);
X SearchItem = tmpstr;
X if (SearchForward()) {
X message("Found!");
X } else {
X message("Not found!");
X }
X }
X break;
X case 8:
X tmpstr = get_input(": search-reverse ? ",
X SearchItem, FALSE);
X if (tmpstr) {
X if (SearchItem)
X free(SearchItem);
X SearchItem = tmpstr;
X if (SearchBackward()) {
X message("Found!");
X } else {
X message("Not found!");
X }
X }
X break;
X case 9:
X /* Change File */
X tmpstr = get_input(": file-name ? ", FileName, TRUE);
X if (tmpstr) {
X CommandMode = 0;
X strcpy(FileName, tmpstr);
X free(tmpstr);
X Rerasterize(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X }
X break;
X case 10:
X /* Change Command */
X tmpstr = get_input(": formatting-command ? ",
X CommandString, FALSE);
X if (tmpstr) {
X CommandMode = 1;
X strcpy(CommandString, tmpstr);
X free(tmpstr);
X Rerasterize(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X }
X break;
X case 11:
X /* Go to page */
X tmpstr = get_input(": go-to-page ? ", (char *) NULL,
X FALSE);
X if (tmpstr) {
X PageRequest = atoi(tmpstr);
X GoToPage(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X }
X break;
X case 12:
X /* Print page */
X MousePrintPage();
X break;
X case 13:
X /* Print document */
X MousePrintDocument();
X break;
X case 14:
X /* Set Printer name */
X tmpstr = get_input(": set-printer-name ? ", Printer,
X FALSE);
X if (tmpstr)
X Printer = tmpstr;
X break;
X case 0:
X Quit(BaseFrame, (XEvent *) NULL,
X (String *) NULL, (Cardinal *) NULL);
X break;
X default:
X message("Programmer error: unknown menu selection");
X break;
X }
X}
X
X
Xstatic char *input;
Xstatic int inputdone = TRUE;
X
X/*
X * This routine focuses all input on the InputWindow, and starts up a
X * loop which forms a secondary dispatcher, ignoring all events except
X * ExposeWindow events on windows other than the InputWindow. This
X * effectively forces the user to use the InputWindow. The loop
X * terminates when input is completed, either by inputting a string, in
X * which case finished_input will be invoked, or by aborting. Both set
X * the completion flag and the loop quits, focussing input back to the
X * previous holder. No harm is done to this application if focus is not
X * given to the minibuffer, or removed from it - it's just more
X * convenient for the user who doesn't have to move a mouse around too
X * much. The routine returns the input string, or a NULL if the input
X * was aborted.
X */
Xchar *
Xget_input(prompt, default_string, complete)
Xchar *prompt, *default_string;
X{
X XEvent ev;
X
X XDefineCursor(dpy, DrawingCanvas, TextCursor);
X MinibufGetInput(InputWidget, prompt, default_string, complete);
X XtAddGrab(InputWidget, False, False);
X XtSetKeyboardFocus(CanvasWidget, InputWidget);
X inputdone = FALSE;
X while (!inputdone) {
X XtNextEvent(&ev);
X (void) XtDispatchEvent(&ev);
X }
X XtSetKeyboardFocus(CanvasWidget, (Widget) None);
X XtRemoveGrab(InputWidget);
X XDefineCursor(dpy, DrawingCanvas, WorkingCursor);
X return(input);
X}
X
X
X/*
X * Callback, invoked when user hits RETURN in the InputWidget (or whatever
X * the user has bound 'newline' to) in which case inp_string points to
X * an alloc'ed string. If the user aborts input (^G, ^C) then
X * inp_string is NULL
X */
X/*ARGSUSED*/
Xstatic void
Xfinished_input(w, tag, inp_string)
XWindow w;
Xcaddr_t tag;
Xchar *inp_string;
X{
X input = inp_string;
X inputdone = TRUE;
X}
X
X
X/*
X * Asks to confirm something - If they reply "y", returns YES, if they
X * reply "n", returns NO, if they abort, returns ABORT. You are given
X * IMPATIENCE tries to answer
X */
Xconfirm(query, default_answer)
Xchar *default_answer;
Xchar *query;
X{
X char *answer;
X char c;
X char *mesg = "Answer yes or no, please (y/n)";
X int count = 0;
X#define IMPATIENCE 5
X
X do {
X if ((answer = get_input(query, default_answer, FALSE)) == NULL)
X return (ABORT);
X c = (isupper(answer[0])) ? tolower(answer[0]) : answer[0];
X if (c == 'y')
X return(YES);
X else if (c == 'n')
X return(NO);
X message(mesg);
X /* Let's get really explicit next time */
X mesg = "Type 'y' and RETURN if you want to answer YES, 'n' for NO, CTRL-G to abort";
X } while (count++ < IMPATIENCE);
X message("Forget it - Aborting");
X return(ABORT);
X}
X
X
X/*
X * Message is printed on the communication line if the windows are
X * mapped, otherwise fprintf'ed to stderr
X */
Xmessage(s)
Xchar *s;
X{
X if (InputWidget != 0)
X MinibufDisplayMessage(InputWidget, s, TRUE);
X else
X fprintf(stderr, "%s\n", s);
X}
X
X/*ARGSUSED*/
XSetPrinter(s)
Xchar *s;
X{
X}
X
X#ifdef STANDALONE
XShowPage(){
X printf("Show Page called.\n");
X}
X
Xchar *DefaultTitle = "Standalone Window Code";
X
XSearchFile(){
X printf("Search file called.\n");
X}
X
XRefreshPage(){
X}
X
X#endif STANDALONE
X#endif SUNTOOLS
X/* Don't put anything after this line */
END_OF_FILE
if test 35916 -ne `wc -c <'xtroff/xwindows.c'`; then
echo shar: \"'xtroff/xwindows.c'\" unpacked with wrong size!
fi
# end of 'xtroff/xwindows.c'
fi
echo shar: End of archive 18 \(of 18\).
cp /dev/null ark18isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 18 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
More information about the Comp.sources.x
mailing list