|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T h
Length: 9825 (0x2661)
Types: TextFile
Names: »handler.c«
└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
└─⟦e10a7c8ba⟧ »./UNRELEASED/xgdb.tar.Z«
└─⟦ae30648b5⟧
└─⟦this⟧ »./handler.c«
\f
#ifndef lint
static char rcsid[] = "$Header: handler.c,v 1.1 89/07/05 15:36:04 hubbard Exp $";
#endif
/*
*
* Copyright 1988, 1989
* PCS Computer Systeme, GmbH
* Munich, West Germany
*
* All rights reserved.
*
* This is unsupported software and is subject to change without notice.
* PCS makes no representations about the suitability of this software
* for any purpose. It is supplied "as is" without express or implied
* warranty.
*
* 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 PCS Computer Systeme not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission.
*
*/
/*
* Author: Jordan K. Hubbard
* For: PCS Computer Systems, GmbH.
* When: February 23rd, 1989.
*
* $Log: handler.c,v $
* Revision 1.1 89/07/05 15:36:04 hubbard
* Initial revision
*
*
*/
#include "xgdb.h"
#ifdef PCS
#include <bsd/sys/time.h>
#else
#include <sys/time.h>
#endif
/*
* The main transaction queue.
*/
Queue TQ;
/*
* The parser queue.
*/
Queue ParserQueue;
/*
* The current output buffer.
*/
static String Buffer;
static int Buflen;
/*
* The current output threshold.
*/
static int OutputThreshold;
/*
* Free the data fron a compiled regular expression.
*/
static void freeCompiledRegexp(re)
struct re_pattern_buffer *re;
{
Entry("freeCompiledRegexp");
ASSERT(NULLP(re));
if (re->buffer) {
XtFree(re->buffer);
re->buffer = (char *)NULL;
re->allocated = 0;
}
if (re->fastmap) {
XtFree(re->fastmap);
re->fastmap = (char *)NULL;
}
Leave_void;
}
/*
* Create a debugger transaction.
*/
void queueDebuggerTrans(send, special, handler)
String send;
SimpleParser *special;
StrFuncP handler;
{
Transaction *tmp;
Entry("queueDebuggerTrans");
NEW(tmp, Transaction);
tmp->send = NULL;
tmp->simple_parsers = special;
tmp->handler = handler;
if (send) {
/*
* If there's nothing on the queue, and the debugger's at a prompt,
* it means the debugger is waiting for input so we should just
* send this right now.
*/
if (queueEmpty(&TQ) && dbg_state.S_promptSeen)
sendToProcess(DebuggerProcess, send);
else /* Save it for later then.. */
STASH(tmp->send, send);
}
addQueueEntry(&TQ, (GenericPtr)tmp);
#ifdef DEBUG
debug("%p: Added transaction. Send = '%s', simple = %x, handler = %x",
send, special, handler);
#endif DEBUG
Leave_void;
}
/*
* Create a parser entry, but don't add it to the queue.
*/
Parser *createParser(proc)
StrFuncP proc;
{
Parser *tmp;
Entry("createParser");
ASSERT(NULLP(proc));
NEW(tmp, Parser);
tmp->handler = proc;
Leave(tmp);
}
/*
* Allocate a parser and add it to the queue.
*/
Parser *installParser(proc)
StrFuncP proc;
{
Parser *tmp;
Entry("installParser");
ASSERT(NULLP(proc));
tmp = createParser(proc);
addQueueEntry(&ParserQueue, (GenericPtr)tmp);
#ifdef DEBUG
debug("%p: Added parser %x\n", proc);
#endif DEBUG
Leave(tmp);
}
/*
* Check to see whether the buffer ends with a valid prompt.
*/
static int bufferEndsWithPrompt(buf, len)
char *buf;
int len;
{
static struct re_pattern_buffer comp;
Entry("bufferEndsWithPrompt");
if (!comp.buffer) {
if (!re_init_comp(DebuggerPromptRegexp, &comp)) {
puke("%p: Can't compile debugger prompt regexp.");
Leave(-1);
}
}
Leave(re_search(&comp, buf, len, len, -len, 0));
}
/*
* Only used in case of error. Takes any output left pending/unparsed
* and prints it to the process's output view.
*/
void flushPendingOutput(proc)
Process *proc;
{
int len = 0;
char buf[BUFSIZ];
Entry("flushPendingOutput");
ASSERT(NULLP(proc));
if (Buflen)
viewAppendText(proc->view, Buffer, Buflen);
/*
* More output pending? Wish there was a nice transparent
* way of doing this, but there doesn't seem to be any way
* to get XtPending() to tell you that I/O is pending on
* a specific input source. Oh well..
*/
bzero(buf, BUFSIZ);
#if defined(BSD) || defined(HAVE_SELECT)
#ifndef FD_SETSIZE /* We don't have the FD_ macros. BSD? */
#define FD_SETSIZE 64 /* Adjust for your machine */
#define FD_ZERO(fdl) *fdl = 0
#define FD_SET(fd, fdl) *(fdl) |= (1 << (fd))
#endif /* !FD_SETSIZE */
{
fd_set readfds;
struct timeval timeout;
FD_ZERO(&readfds);
FD_SET(proc->in_channel, &readfds);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
while (select(FD_SETSIZE, &readfds, 0, 0, &timeout) > 0) {
if (read(proc->in_channel, buf + len, 1) < 1)
break;
len++;
}
}
#elif defined(FIONREAD)
ioctl(proc->in_channel, FIONREAD, &len);
if (len)
read(proc->in_channel, buf, len);
#endif /* FIONREAD or select() */
buf[len] = '\0';
if (len)
viewAppendText(proc->view, buf, len);
viewChangeCursor(proc->view, 0, TRUE);
Leave_void;
}
/*
* The main dude.
*/
void handleOutput(T_PROC_ARGS)
T_PROC_DECL;
{
static String cp;
static struct re_registers regs;
int matched;
Transaction *tmpt;
Parser *tmpp;
Entry("handleOutput");
/*
* Grow or create the output buffer.
*/
if (Buflen) {
cp = Buffer = XtRealloc(Buffer, Buflen + len + 1);
strncat(Buffer, s, len);
Buflen += len;
#ifdef DEBUG
debug("%p: Buffer grown to %d bytes", Buflen);
#endif DEBUG
}
else {
cp = Buffer = XtMalloc(len + 1);
Buflen = len;
strncpy(Buffer, s, len);
}
Buffer[Buflen] = '\0';
/*
* Make sure we've got all the text.
*/
matched = bufferEndsWithPrompt(Buffer, Buflen);
#ifdef DEBUG
debug("%p: Looked for prompt terminator. Match = %d", matched);
#endif DEBUG
if (matched < 0) {
/*
* Ok, we don't have a prompt, but have we accumulated
* enough output to safely do some parsing anyway?
*/
if (Buflen < OutputThreshold) {
Leave_void;
}
#ifdef DEBUG
else {
debug("%p: %d is < threshold of %d", Buflen, OutputThreshold);
}
#endif DEBUG
}
/*
* START PROCESSING OUTPUT:
*
* Each parser is responsible for returning any text not parsed and
* adjusting the value of "buflen" accordinly. It should be noted that
* it's perfectly acceptable for a parser to get passed a NULL value
* for the text or a zero value for the length. It's necessary that all
* parsers get called, even if there's no text left, so that they
* can reset any state information that may have been set for them.
*
* Each transaction (if any) can have a private set of parsers which
* are invoked, and/or a special function to handle the text.
*
*/
if ((tmpt = (Transaction *)popQueueEntry(&TQ, FIFO))) {
#ifdef DEBUG
debug("%p: popped transaction %x. Snd '%s', spcl '%x', hndl '%x'",
tmpt, tmpt->send, tmpt->simple_parsers, tmpt->handler);
#endif DEBUG
/* special parser list? */
if (tmpt->simple_parsers)
cp = parseSimpleList(tmpt->simple_parsers, p, cp, &Buflen);
/* Special handler? */
if (tmpt->handler)
cp = (*tmpt->handler)(p, cp, &Buflen);
#ifdef DEBUG
debug("%p: finished transaction %x.", tmpt);
#endif DEBUG
XtFree(tmpt);
}
/*
* Now call all installed "global" parsers.
*/
for (tmpp = FIRST(&ParserQueue, Parser); tmpp; tmpp = NEXT(tmpp)) {
#ifdef DEBUG
debug("%p: Invoking global parser '%x'", tmpp->handler);
#endif DEBUG
cp = (*tmpp->handler)(p, cp, &Buflen);
}
/*
* If there's something left unparsed, complain, otherwise check to see
* if any output was generated in the debugger's "output" area and
* print/mark a new prompt, if necessary. If the last operation
* in the output area was an interactive user command, print a
* prompt anyway to simulate "tty" behaviour.
*/
if (cp && Buflen)
puke("%p: %d bytes ('%s') left unparsed\n", Buflen, cp);
else if (dbg_state.S_promptSeen) {
#ifdef DEBUG
debug("%p: promptSeen: %d, userInput: %d, outputSent: %d",
dbg_state.S_promptSeen, dbg_state.S_userInput,
dbg_state.S_outputSent);
#endif DEBUG
if (dbg_state.S_outputSent || dbg_state.S_userInput)
viewMarkPrompt(p); /* print the prompt */
dbg_state.S_outputSent = FALSE;
dbg_state.S_userInput = FALSE;
viewChangeCursor(p->view, 0, TRUE);/* change cursor back */
/*
* If there's another transaction queued, send its output now.
*/
if ((tmpt = LAST(&TQ, Transaction))) {
if (tmpt->send) {
sendToProcess(p, tmpt->send);
XtFree(tmpt->send);
tmpt->send = NULL;
}
}
}
updateAllViews();
XtFree(Buffer);
Buflen = 0;
Leave_void;
}
/*
* Set the output threshold to some value, returning previous.
*/
int setOutputThreshold(n)
int n;
{
int old;
Entry("setOutputThreshold");
old = OutputThreshold;
OutputThreshold = n;
Leave(old);
}
/*
* Toggle the output threshold on and off.
*/
void toggleOutputThreshold()
{
static int old_threshold = 0;
Entry("toggleOutputThreshold");
#ifdef DEBUG
debug("%p: oldThreshold = %d", old_threshold);
#endif DEBUG
if (old_threshold) {
setOutputThreshold(old_threshold);
old_threshold = 0;
}
else
old_threshold = setOutputThreshold(0xffff);
Leave_void;
}