/* Copyright 1991 by the Massachusetts Institute of Technology Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of M.I.T. not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. M.I.T. makes no representations about the suitability of this software for any purpose. It is provided "as is" without express or implied warranty. */ /* ** headers.c: manage the list of transaction headers ** */ #include #include #include #include #include #include #include #include "xdsc.h" static char rcsid[] = "$Id: headers.c,v 1.5 1999-12-16 01:58:23 danw Exp $"; extern char *RunCommand(); extern EntryRec toplevelbuttons[2][MAX_BUTTONS]; extern TextWidget bottextW, toptextW; extern Boolean debug; extern char filebase[]; extern int topscreen; extern void TopSelect(); extern char *CurrentMtg(); static void FetchHeaders(); static char oldmeeting[LONGNAMELEN]; /* ** Get the list of transaction headers from start to finish and ** put them into the upper text widget. */ PutUpTransactionList(start, finish) int start; int finish; { char command[LONGNAMELEN + 25]; char filename[70]; static int oldstart=0, oldfinish=0; Arg args[1]; XtSetArg(args[0], XtNsensitive, True); XtSetValues ((toplevelbuttons[0][5]).button, args, 1); if (start < TransactionNum(FIRST)) start = TransactionNum(FIRST); if (finish > TransactionNum(LAST)) finish = TransactionNum(LAST); /* ** Can we optimize by keeping some of the old data? */ if ( *oldmeeting && !strcmp (oldmeeting, CurrentMtg(0)) && finish == oldfinish && start <= oldstart) { /* ** Just put up old list */ if (oldstart == start) { sprintf (filename, "%s-list", filebase); FileIntoWidget(filename, toptextW); return; } /* ** Prepend to old list */ sprintf ( command, "mv %s-list %s-old", filebase, filebase); if (system (command) != 0) { sprintf ( command, "Cannot write to '%s-old'\n", filebase); PutUpWarning("WARNING", command, False); } FetchHeaders(start, oldstart-1); sprintf ( command, "cat %s-old >> %s-list", filebase, filebase); if (system (command) != 0) { sprintf ( command, "Cannot write to '%s-list'\n", filebase); PutUpWarning("WARNING", command, False); } sprintf (filename, "%s-old", filebase); unlink (filename); } /* ** Get an entirely new list */ else { FetchHeaders(start, finish); } sprintf (filename, "%s-list", filebase); FileIntoWidget(filename, toptextW); strcpy (oldmeeting, CurrentMtg(0)); oldstart = start; oldfinish = finish; sprintf (command, "Reading %s [%d-%d], #%d", CurrentMtg(0), TransactionNum(FIRST), TransactionNum(LAST), TransactionNum(CURRENT)); PutUpStatusMessage(command); } /* ** Get the headers for the specified range of transactions. Get them in ** packets of CHUNKSIZE if necessary, and update status line as doing so. */ static void FetchHeaders(start, finish) int start; int finish; { int localstart, localfinish; char command[LONGNAMELEN + 25]; char filename[70]; char *returndata; #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define CHUNKSIZE 25 localstart = start; localfinish = finish; sprintf (filename, "%s-list", filebase); unlink (filename); sprintf (filename, "%s-temp", filebase); unlink (filename); while (localstart <= finish) { localfinish = MIN (localstart + CHUNKSIZE - 1, finish); if (localfinish != finish) sprintf ( command, "Reading headers for transactions %d to %d (%d remaining)...", start, finish, (finish - localstart)); else sprintf ( command, "Reading headers for transactions %d to %d...", start, finish); if (start == finish) sprintf ( command, "Reading header for transaction %d...", start); PutUpTempMessage(command); sprintf (filename, "%s-temp", filebase); sprintf (command, "(ls %s %d %d 0 %s)\n", filename, localstart, localfinish, CurrentMtg(0)); returndata = RunCommand (command, NULL, NULL, True); if ((int) returndata <= 0) { TakeDownTempMessage(); sprintf (filename, "%s-temp", filebase); unlink (filename); return; } myfree (returndata); sprintf ( command, "cat %s-temp >> %s-list", filebase, filebase); if (system (command) != 0) { sprintf ( command, "Cannot write to '%s-list'\n", filebase); PutUpWarning("WARNING", command, False); } localstart += CHUNKSIZE; } TakeDownTempMessage(); sprintf (filename, "%s-temp", filebase); unlink (filename); } /* ** This should only be called if topscreen == LISTTRNS. It moves ** the marker on the upper text widget to the line for the ** specified transaction. If moveinsert is true, it tells PutUpArrow ** to move the text insert carat there, too. */ UpdateHighlightedTransaction(num, moveinsert) int num; Boolean moveinsert; { static int lastend; Arg args[5]; unsigned int n; char *tempstring, *foo = NULL, *bar = NULL; char buf[50]; n = 0; XtSetArg(args[n], XtNstring, &tempstring); n++; XtGetValues (toptextW, args, n); /* ** Okay, the following is REAL STUPID code. I'm looking for a specific ** transaction number, so I sprintf the specified transaction number ** into a string and search for it in each line of the text widget's string. ** ** Should really use a better way to find the line than sequential search! */ sprintf (buf, " [%04d]", num); foo = tempstring; /* ** Specialization for common case of moving one forwards... */ if ( lastend && lastend < strlen (tempstring) && (!strncmp (tempstring + lastend + 1, buf, strlen(buf)))) foo = tempstring + lastend + 1; else { while (*foo) { if (!strncmp (foo, buf, strlen(buf))) break; for ( ; *foo && *foo != '\n'; foo++) ; if (*foo) foo++; } } if (*foo) { for (bar = foo; *bar && *bar != '\n'; bar++) ; PutUpArrow(toptextW, foo - tempstring, moveinsert); } if (bar) lastend = bar - tempstring; } /* ** An arrow key has been hit in the upper text window. If we're showing ** transactions, see if we need to fetch another header. */ void FetchIfNecessary(w, event, params, num_params) Widget w; XEvent *event; String *params; int *num_params; { TextWidget ctx = toptextW; int num; int step; XawTextPosition inspoint = ctx->text.insertPos; if (*num_params < 2) return; if (topscreen != LISTTRNS) return; step = atoi (params[1]); if (!strcmp(params[0], "Up")) { num = HighlightedTransaction(); if ( (ctx->text.insertPostext.lt.info[1].position) && ctx->text.lt.top == 0 && num != TransactionNum(FIRST)) { XawTextDisableRedisplay(ctx); PutUpTransactionList(num - step, TransactionNum(LAST)); UpdateHighlightedTransaction(TransactionNum(CURRENT),False); XawTextSetInsertionPoint(ctx, inspoint + ctx->text.lt.info[step].position); XawTextEnableRedisplay(ctx); } } } /* ** Pull the transaction number out of the highlighted line and return it */ HighlightedTransaction() { Arg args[5]; unsigned int n, num; XawTextPosition start, inspoint; char *tempstring; n = 0; XtSetArg(args[n], XtNstring, &tempstring); n++; XtGetValues (toptextW, args, n); inspoint = XawTextGetInsertionPoint(toptextW); if (tempstring[inspoint] == '\0') return; for (start = inspoint; start && tempstring[start-1] != '\n'; start--) ; num = atoi (strchr (tempstring + start, '[') + 1); return (num); } InvalidateHeaders() { strcpy (oldmeeting, "\0"); }