[comp.sys.amiga] VT100 Workbench bug and fix

carl@umd5 (Carl Symborski) (01/15/87)

 
Here's another VT100 bug and associated fix to Dave Wecker's famous VT100
terminal program.  The problem is that VT100 seemed to cause the workbench
to hang/crash after exit from VT100.  Steve Walton mentioned in a recent
posting that this happened only when VT100 was run from the workbench (i.e.
invoked via double click on icon).  After exit, clicking on workbench icons
would not do anything etc...  I have also been having this problem, sometimes
accompanied by software task held messages, guru's etc.  Anyway, my 
environment is VT100 V2.3, Lattice V3.03, Release 1.1 of OS.

It turns out that the problem is with the Change Dir menu command.  Using
this feature will cause the above problem ONLY when running from workbench.
Quick fix: Don't use Change Dir... or use VT100 only from CLI.  

The trouble is in the set_dir routine in expand.c, which does something like:
          if (lock = (struct FileLock *)CurrentDir(lock))
              UnLock(lock);
Where "lock" is a lock on the directory to switch to.  CurrentDir returns the
lock on the "old" current dir, which is then unlocked.  This works in all
cases EXCEPT the first time through!  When a tool (like VT100) is started from
the workbench, Workbench will (among other things) create an argument for the
workbench startup message containing the name of the tool in the wa_Name
field and a lock of the directory where the tool is in the wa_Lock field.
This is linked into the startup message and sent to the tool at startup.
The stardard Lattice startup code (Lstartup.obj) plucks the lock out of this
message and does a CurrentDir on it.  So... the first time through VT100's
set_dir processing, the lock returned from CurrentDir will be that same lock
created by the Workbench.  You can bet that Workbench wants to UnLock this
lock as part of its cleanup processing after VT100 exits and the startup
message is replied back.  So if VT100 unlocks the lock, and later Workbench
unlocks the same lock... CRASH!  This is the heart of the problem.

All of this workbench stuff dosn't happen when RUNning under the CLI.  Thats
why this is not a problem under the CLI.

There are also a few more minor bugs in the set_dir routine which may or 
maynot have contributed to the original problem.  Lock was being called
without specifying the "accessMode" parameter (it was missing).  Examine was
being called with with a stack based "FileInfoBlock" structure.  The AmigaDOS
Developers Manual says that the FileInfoBlock must be longword aligned. 
I don't think this is guaranteed with stack variables.  Finally, the lock
obtained on the LAST directory set by set_dir is never unlocked by anyone.
This contributes to gradual memory loss.

What follows are edits to three VT100 files: VT100.h, VT100.c, and EXPAND.c
Crank up your favoriate editor, locate the modified areas, insert new lines
marked by the arrows.  Recompile VT100.c and EXPAND.c, alink and your done.

------ CHANGES TO VT100.H ------
VT100.h changed in two places.  Search for "MyDir" and insert new declaration
of "MyDirLock"...

int	multi = FALSE, server;
long    bytes_xferred;
char	MyDir[60];
struct FileLock *MyDirLock = NULL;  <----------- NEW
struct IntuitionBase *IntuitionBase;

Search for "MyDir" again and insert new external declaration of "MyDirLock"...

extern char    bufr[BufSize];
extern int     fd, timeout, ttime;
extern long    bytes_xferred;
extern char    MyDir[60];
extern struct FileLock *MyDirLock;   <------------ NEW


------ CHANGES TO VT100.C ------
One addition to VT100.C.   Search for "cleanup" function.  Add UnLock to
case 0 processing...


cleanup(reason, fault)
char *reason;
int fault;
    {
    switch(fault) {
	case 0:		/* quitting close everything */
	ClearMenuStrip( mywindow ); 
	CloseDevice(&Audio_Request);
        if (MyDirLock != NULL) UnLock(MyDirLock);   <-------  NEW


------ CHANGES TO EXPAND.C ------
Replace "set_dir" routine with the set_dir which follows...


set_dir(new)
char *new;
{
   register 	char 		*s;
   int   			i;
   struct 	FileLock 	*lock;
   char 			temp[60];
   struct       FileInfoBlock   *fib;
  
   if (*new != '\000') {
      strcpy(temp, MyDir);
      s = new;
      if (*s == '/') {
         s++;
         for (i=strlen(MyDir);
              MyDir[i] != '/' && MyDir[i] != ':';
              i--);
         MyDir[i+1] = '\0';
           strcat(MyDir, s);
         }
      else if (exists(s, ':') == 0) {
         if (MyDir[strlen(MyDir)-1] != ':')
            strcat(MyDir, "/");
         strcat(MyDir, s);
         }
      else
         strcpy(MyDir, s);

      if ((lock = (struct FileLock *)Lock(MyDir, ACCESS_READ)) == 0) {
         emits("Directory not found\n");
         strcpy(MyDir, temp);
         }
      else {
         fib = (struct FileInfoBlock *)AllocMem(
                           (long)sizeof(struct FileInfoBlock), MEMF_PUBLIC);
         if (fib) {
       	    if (Examine(lock, fib)) {
      	       if (fib->fib_DirEntryType > 0) {
                  CurrentDir(lock);
                  if (MyDirLock != NULL)
		     UnLock(MyDirLock);
		  MyDirLock = lock;
                  if (MyDir[strlen(MyDir)-1] == '/')
                     MyDir[strlen(MyDir)-1] = '\0';
                  }
               else {
            	  emits("Not a Directory\n");               
            	  strcpy(MyDir,temp);
                  }
               }
            FreeMem(fib, (long)sizeof(struct FileInfoBlock));
            }
         else {
            emits("Can't change Directory... no free memory!\n");
            strcpy(MyDir,temp);
            }
         }
      
      }
}


-------- END OF FIXES --------

I have to say CHEERS to those people who post sources along with their PD
offerings!!  This way we can fix those bugs we want to fix, when we want 
to fix them, AND learn something in the process.  I think of this often
whenever I read;  "... what follows is the UUENCODED binary of my program X.
Download this and...".  Sufficient provocation for the "j" key,
or perhaps the "^c".  A good way to keep up with the mail, ay?


Carl Symborski