DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T h

⟦e7c4eac1a⟧ TextFile

    Length: 9953 (0x26e1)
    Types: TextFile
    Names: »handler.c«

Derivation

└─⟦a05ed705a⟧ Bits:30007078 DKUUG GNU 2/12/89
    └─⟦34cc4e2f7⟧ »./UNRELEASED/xgdb3.2.tar.Z« 
        └─⟦80fac5d7c⟧ 
            └─⟦this⟧ »./handler.c« 

TextFile

\f


#ifndef lint
static char rcsid[] = "$Header: handler.c,v 1.2 89/07/07 17:04:54 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.2  89/07/07  17:04:54  hubbard
 * Fixed silly typo.
 * 
 * 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;

#ifdef DEBUG
     debug("Adding transaction. Send = '%s', simple = %x, handler = %x",
	   send, special, handler);
#endif DEBUG
     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);
     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("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;
{
     register struct re_pattern_buffer *comp;

     Entry("bufferEndsWithPrompt");

     comp = &(DebuggerPromptRegexp->comp);
     if (!comp->buffer) {
	  if (!re_init_comp(DebuggerPromptRegexp->str, comp)) {
	       puke("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("Buffer grown to %d bytes (%s)", Buflen, substr(s, 0, len));
#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("Looked for prompt terminator '%s'. Match = %d",
	   DebuggerPromptRegexp->str, 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("%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("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("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("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("%d bytes ('%s') left unparsed\n", Buflen, cp);
     else if (dbg_state.S_promptSeen) {
#ifdef DEBUG
	  debug("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;

     Entry("toggleOutputThreshold");

#ifdef DEBUG
     debug("oldThreshold = %d", old_threshold);
#endif DEBUG
     if (old_threshold) {
	  setOutputThreshold(old_threshold);
	  old_threshold = 0;
     }
     else
	  old_threshold = setOutputThreshold(65535);
     Leave_void;
}