ftp.nice.ch/pub/next/text/tex/apps/TeXview-kp-hm01.s.tar.gz#/texview-hm/ComScroll.m

This is ComScroll.m in view mode; [Download] [Up]

/* Generated by Interface Builder */

#import "ComScroll.h"
#import "CText.h"
#import <appkit/nextstd.h>
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/Font.h>
#import <appkit/Panel.h>
#import <mach/cthreads.h> 
#import <dpsclient/dpsNeXT.h>
#import <objc/objc.h>

extern char defaultfont[] ;

extern void error(), configure() ;

static void getptys (master, slave)
int *master, *slave ;
{
   char device[12];
   char *block, *num;
   char *blockLoc;
   char *numLoc;
   char *msLoc;
   struct sgttyb setp =
      {B9600, B9600, (char)0x7f, (char)0x15, (ECHO|CRMOD|ANYP|PASS8|PASS8OUT)};
   struct tchars setc =
      {CINTR, CQUIT, CSTART, CSTOP, CEOF, CBRK};
   struct ltchars sltc =
      {CSUSP, CDSUSP, CRPRNT, CFLUSH, CWERASE, CLNEXT};
   int lset =
      (LCRTBS|LCRTERA|LCRTKIL|LCTLECH|LPENDIN|LDECCTQ);
   int setd = NTTYDISC;

   strcpy(device, "/dev/pty??");
   blockLoc = &device[ strlen("/dev/pty") ];
   numLoc = &device[ strlen("/dev/pty?") ];
   msLoc = &device[ strlen("/dev/") ];
   for (block = "pqrs"; *block; block++) {
      *blockLoc = *block;
      for (num = "0123456789abcdef"; *num; num++) {
         *numLoc = *num;
         *master = open(device, O_RDWR);
         if (*master >= 0) {
            *msLoc = 't';
            *slave = open(device, O_RDWR);
            if (*slave >= 0) {
               (void) ioctl(*slave, TIOCSETP, (char *)&setp);
               (void) ioctl(*slave, TIOCSETC, (char *)&setc);
               (void) ioctl(*slave, TIOCSETD, (char *)&setd);
               (void) ioctl(*slave, TIOCSLTC, (char *)&sltc);
               (void) ioctl(*slave, TIOCLSET, (char *)&lset);
               return;
            }
         }
      }
   }
   *master = -1;
   *slave = -1;
}

@implementation ComScroll

+ newFrame:(const NXRect *)frameRect
{
   self = [super newFrame:frameRect] ;
   [self setVertScrollerRequired: YES] ;
   [self setBackgroundGray: NX_WHITE] ;
   [self awake] ;
   childID = 0 ;
   waiting = 0 ;
   return self ;
}

- awake
{
   NXRect trect ;
   Font *mf = 0 ;

   configure() ;
   if (defaultfont[0]) {
      char *p = defaultfont ;
      char fname[2000] ;
      char *q = fname ;
      float size ;

      for (; *p && *p != ':'; p++, q++)
         *q = *p ;
      *q = 0 ;
      if (*p && sscanf(p+1, "%f", &size)==1)
         mf = [Font newFont:fname size:size] ;
   }
   if (mf == 0)
      mf = [Font newFont:"Ohlfs" size:10] ;
   trect.origin.x = trect.origin.y = 0 ;
   [self getContentSize: &(trect.size)] ;
   text = [[CText alloc]
                  initFrame:&trect text:NULL alignment:NX_LEFTALIGNED] ;
   [text setFont:mf] ;
   [text notifyAncestorWhenFrameChanged:YES] ;
// [text setEditable:NO] ;
   [text setEditable:YES] ;
   [text setHorizResizable:NO] ;
   [text setVertResizable:YES] ;
   [text setMinSize:&(trect.size)] ;
   trect.size.height = 1000000 ;
   trect.size.width = 1200 ;
   [text setMaxSize:&(trect.size)] ;
   [self setAutoresizeSubviews:YES] ;
   [self setAutosizing: NX_HEIGHTSIZABLE | NX_WIDTHSIZABLE] ;
   [text setMonoFont:YES] ;
   [text setOpaque:YES] ;
   [text setFontPanelEnabled:YES] ;
   [self setDocView:text] ;
   [text setDelegate:self] ;
   [text setController:self] ;
   return self ;
}

/*
 *   Currently (yuck!) we only handle leading back spaces.
 */
- addText:(const char *)s
{
   int bs = 0 ;
   int i, j ;
   char inbuf[4000] ;

   bs = 200 ;
   i = 200 ;
   while (*s) {
      if (*s == 8) {
         i-- ;
         if (i < bs)
            bs = i ;
      } else
         inbuf[i++] = *s ;
      s++ ;
   }
   inbuf[i] = 0 ;

   j = [text textLength] + bs - 200 ;
   if (j < 0) {
      j = 0 ;
   }
   [text setSel:j :bs+j];
   [text replaceSel:inbuf + bs] ;
   [text scrollSelToVisible];
   return self;
}

- addText2:(const char *)s:(int) len
{
   int j ;
   j = [text textLength];
   [text setSel:j :len+j];
   [text replaceSel:s] ;
   [text setSel:len+j-1 :len+j];
   [text scrollSelToVisible];
   return self;
}

- handler:(int)fd
{
   int r ;
   char outbuf[2000] ;

   if (childID == 0)
      return self ;
/* printf("In handler\n") ; */
   while ((r = read(fd, outbuf, 199)) > 0) {
/*    printf("<%d> bytes\n", r) ; */
      if (waiting) {
         struct timeval tv ;
         struct timezone tzp ;

         gettimeofday(&tv, &tzp) ;
         if (tv.tv_sec > waittime.tv_sec ||
             (tv.tv_sec == waittime.tv_sec && tv.tv_usec > waittime.tv_usec)) {
            [[self window] makeKeyAndOrderFront:0] ;
            waiting = 0 ;
         }
      }
      if (eofcount > 0) {
         write(fd, eofchar, 1) ;
         eofcount-- ;
      }
      outbuf[r] = 0 ;
      [self addText:outbuf] ;
   }
   if (r == 0)
      [self closeChild:fd] ;
   else if (errno != EWOULDBLOCK) {
      [self closeChild:fd] ;
   }
/* printf("Out handler\n") ; */
   return self ;
}

static void cm_handler(fd, sender)
int fd ;
id sender ;
{
   [sender handler:fd] ;
}

- closeChild:(int)fd
{
   if (childID) {
      if (fdadded)
         DPSRemoveFD(fd) ;
      childID = 0 ;
      close(fd) ;
      masterFD = 0 ;
   }
// [text setEditable:NO] ;
   [text setEditable:YES] ;
   return self ;
}

static void msleep(long len) {
   struct timeval tv ;

   tv.tv_usec = len % 1000000 ;
   tv.tv_sec = len / 1000000 ;
   select(0, 0, 0, 0, &tv) ;
}

- killOff
{
   if (childID) {
      kill(childID, SIGTERM) ;
      childID = 0 ;
   }
   return self ;
}

- logCommand:(const char *)s inBack:(int)async
{
   int masterPty, slavePty ;
   int tty, numFds, fd;
   int processGroup;
   int pidChild;
   int i ;

   while (wait3(0, WNOHANG, 0) > 0) ; /* allow zombies to go away */
   if (childID)
      if (masterFD)
         [self handler:masterFD] ;
   if (childID) {  // are we busy??
/*    i = NXRunAlertPanel(NULL, "Command window busy",
    "Cancel request", "Force EOF and override", "Force ^C and override", 0) ;
 */
      i = NX_ALERTALTERNATE ;
      if (i != NX_ALERTDEFAULT) {
         if (i == NX_ALERTALTERNATE)
            eofchar[0] = 4 ;
         else
            eofchar[0] = 3 ;
         write(masterFD, eofchar, 1) ;
         eofcount = 3 ;
         for (i=0; i<5; i++) {
            if (childID) {
               msleep(300000) ;
               [self handler:masterFD] ;
            }
         }
      }
   }
   if (childID) {
      // we tried nicely, now we get mean.
      kill(childID, SIGTERM) ;
      msleep(300000) ;
      [self handler:masterFD] ;
      if (childID)
         [self closeChild:masterFD] ;
   }
   if (childID) {
      error("you'll have to intercede for me; I couldn't get it to die.") ;
      return 0 ;
   }
   [self addText:" - "] ;
   [self addText:s] ;
   [self addText:"\n"] ;
   while (wait3(0, WNOHANG, 0) > 0) ; /* allow zombies to go away again */
   tty = open("/dev/tty", O_RDWR);
   getptys(&masterPty, &slavePty);
   if (masterPty <= 0 || slavePty <= 0)
       error("! error grabbing ptys for subprocess") ;

   // remove the controlling tty if launched from a shell,
   // but not Workspace;
   // so that we have job control over the parent application in shell
   // and so that subprocesses can be restarted in Workspace
   if  (tty<0) {
      if ((tty = open("/dev/tty", 2))>=0) {
         ioctl(tty, TIOCNOTTY, 0);
         close(tty);
      }
   } else {
      close(tty) ;
   }
   switch (pidChild = vfork()) {
   case -1:   // error
      error("! error starting UNIX vfork of subprocess.") ;
   case 0:   // child
      dup2(slavePty, 0);
      dup2(slavePty, 1);
      dup2(slavePty, 2);
      numFds = getdtablesize();
      for (fd=3; fd<numFds; fd++)
         close(fd);
      processGroup = getpid();
      ioctl(0, TIOCSPGRP, (char *)&processGroup);
      setpgrp (0, processGroup);
      execl("/bin/csh", "csh", "-c", s, 0) ;
      error("! vfork (child)") ;
   default:   // parent
      close(slavePty);
      childID = pidChild ;
      eofcount = 3 ;
      if (async) {
         [text setEditable:YES] ;
         if (fcntl(masterPty, F_SETFL, FNDELAY) == -1)
            error("! couldn't fcntl") ;
         DPSAddFD(masterPty, cm_handler, self, NX_MODALRESPTHRESHOLD) ;
         fdadded = 1 ;
         masterFD = masterPty ;
         eofcount = 0 ;
      } else {
         struct timezone tzp ;

         fdadded = 0 ;
         masterFD = 0 ;
         eofcount = 3 ;
         eofchar[0] = 4 ;
         write(masterPty, "\004", 1) ;
         waiting = ! [[self window] isVisible] ;
         gettimeofday(&waittime, &tzp) ;
         waittime.tv_sec += 5 ; /* pop up after five seconds if necessary */
         [self handler:masterPty] ;
      }
      break ;
   }
   return self ;
}

- abortCommand:sender
{
    return self;
}

- sendToMaster:(const char *)s
{
   if (masterFD)
      write(masterFD, s, strlen(s)) ;
   return self ;
}

- (BOOL)textWillChange:textObject
{
    [text setSel:[text textLength] :0];
    [text scrollSelToVisible];
    return NO;
}
- clear
{
   [text selectAll:self] ;
   if ([text isEditable])
      [text delete:self] ;
   else {
      [text setEditable:YES] ;
      [text delete:self] ;
      [text setEditable:NO] ;
   }
   return self ;
}

- text
{
   return text ;
}

static int eots_wanted=0;

static int rec(id self, char *pa, char *pe) { 
   char *pr = pa;

    for(;;) {
	while(*(pr++) != 4) ;
	if(pr==pe)	{					/* letztes Zeichen war Ende */
	    *(--pr) = 0;
	    [self addText2:pa:pr-pa] ;	
	    --eots_wanted;
	    return (eots_wanted);
	    }
	else if(pr > pe) {					/* Ende noch nicht erreicht */
	    *pe = 0;
	    [self addText2:pa:pe-pa] ;
	    return (eots_wanted);	
	    }
	else {	/* pa < pr < pe */				/* Ende war mittendrin */
	    *(--pr) = 0;
	    if (pr-pa) [self addText2:pa:pr-pa] ;
	    pa = ++pr;
	    --eots_wanted;
	};
    }
}

- MoConOut:(id)s
{
    int c;
    char ch[100],*pe;

extern int my_log_file;
extern myPageView;
extern int in_copy_file;

    if(!eots_wanted) return self;

    if(in_copy_file) {			/* postscript interpretation is active, will worry WM */
	SEL method = @selector(MoConOut:);
	[self perform:method with:self afterDelay:0 cancelPrevious:TRUE];
	return(self); 
    };

//    thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 3000);

    c = read(0,ch,99);
    if(c==1 && *ch==4) { eots_wanted--; return self; };

    [[self window] makeKeyAndOrderFront:nil] ;

    pe = &ch[c]; *pe = 4;			/* set sentinell */

    while( rec(self,ch,pe) ) {

//	thread_switch(THREAD_NULL, SWITCH_OPTION_DEPRESS, 5000);
	c = read(0,ch,99);
	pe = &ch[c]; *pe = 4;		        /* set sentinell */
    } ;

    [[myPageView window] makeKeyAndOrderFront:nil] ;	
    return self;
}

void ModalConsoleOutput () { 
    extern ComScroll *console;
	eots_wanted++;
	[console MoConOut:console]; 
};
@end

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.