|
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; }