home *** CD-ROM | disk | FTP | other *** search
/ Micro R&D 1 / MicroRD-CD-ROM-Vol1-1994.iso / os20 / cli / cfn.lha / CFN / source / cfn.c < prev    next >
C/C++ Source or Header  |  1993-06-24  |  8KB  |  277 lines

  1. /* - cfn -  completes filenames when pressing the "TAB" key */
  2.  
  3. /*  written in 1993 by Andreas Günther                      */
  4.  
  5. /*  ( compiled with aztec-C 5.2 )                           */
  6. /*  for more information, please read the doc-file          */
  7.  
  8.  
  9. /*  this is NOT great artwork, so                           */
  10.  
  11. /*           FEEL FREE TO IMPROVE THIS CODE !               */
  12.  
  13.  
  14.  
  15. /* note: this piece of code is real public domain, do with  */
  16. /*       it whatever you want, but I would be happy if you  */
  17. /*       left my name in it :)                              */
  18.  
  19.  
  20.  
  21. #include "string.h"
  22.  
  23. #include "exec/types.h"
  24. #include "exec/interrupts.h"
  25. #include "exec/memory.h"
  26. #include "intuition/intuitionbase.h"
  27. #include "functions.h"
  28. #include "devices/input.h"
  29. #include "dos/exall.h"
  30.  
  31. #define BUF_LEN   256   /* number of buffered characters from input stream */
  32. #define COMPL_LEN  64   /* maximum length of filename completion */
  33. #define FILTER "~(#?.info)"
  34. #define FILTER_LEN 10
  35. #pragma amicall(SysBase, 0, observe_input(a0))
  36.  
  37. char *ver="$VER: cfn 1.0 (21.6.93)  by Andreas Günther";
  38.  
  39. struct IntuitionBase *IntuitionBase=NULL;
  40. struct Library *KeymapBase=NULL;
  41. struct Library *UtilityBase=NULL;
  42. ULONG ilock,sig;
  43. BOOL ready;
  44. struct InputEvent event, *cur_ev;
  45.  
  46. struct Task *task;
  47. char buf[BUF_LEN];    /* recently typed characters */
  48. struct InputEvent ie_buffer[2*BUF_LEN];    /* recently typed characters as InputEvents*/
  49. int bufpos=0;
  50. BOOL buf_busy=FALSE;
  51. char compl[COMPL_LEN];   /* actual completion */
  52. struct Interrupt *handler;
  53. struct MsgPort *port;
  54. struct IOStdReq *io_req;
  55.  
  56.  
  57. BOOL open_libs()
  58. {
  59.   IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37);
  60.   KeymapBase = OpenLibrary("keymap.library",37);
  61.   UtilityBase = OpenLibrary("utility.library",37);
  62.   return(IntuitionBase!=NULL && KeymapBase!=NULL && UtilityBase!=NULL);
  63. }
  64.  
  65. void close_libs()
  66. {
  67.   if(NULL!=IntuitionBase)
  68.     CloseLibrary(IntuitionBase);
  69.   if(NULL!=KeymapBase)
  70.     CloseLibrary(KeymapBase);
  71.   if(NULL!=UtilityBase)
  72.     CloseLibrary(UtilityBase);
  73. }
  74.  
  75.  
  76.  
  77. void filter_equal_part(char *file)
  78. {
  79. /* leaves in compl[] only the first chars that are equal with "file" */
  80.   int i=0;
  81.   while(ToUpper(file[i])==ToUpper(compl[i]) && compl[i]!=0 && file[i]!=0)
  82.     i++;
  83.   compl[i]=0;
  84. }
  85.  
  86. void find_completion(char *part, BPTR dir)
  87. {
  88. /* scans the given dir and finds the longest unique completion */
  89.   char pat[COMPL_LEN*2+6];
  90.   struct ExAllControl *eac;
  91.   struct ExAllData *alldata, *ead;
  92.   BPTR lock;
  93.  
  94.   compl[0]=0;
  95.   if(NULL!=(alldata=(struct ExAllData *)malloc(3000)))
  96.    {
  97.     strcat(part,FILTER);
  98.     ParsePatternNoCase(part,pat,COMPL_LEN*2+6);
  99.     eac=AllocDosObject(DOS_EXALLCONTROL,NULL);
  100.     if(eac!=NULL)
  101.      {
  102.       eac->eac_MatchString=pat;
  103.       eac->eac_LastKey=0;
  104.       ExAll(dir,alldata,3000,ED_NAME,eac);
  105.       if(eac->eac_Entries!=0)
  106.        {
  107.         strcpy(compl,&alldata->ed_Name[strlen(part)-FILTER_LEN]);
  108.         if(eac->eac_Entries==1)
  109.          {
  110.           struct FileInfoBlock *fileinfo;
  111.           if(NULL!=(fileinfo=AllocDosObject(DOS_FIB,NULL)))
  112.            {
  113.             CurrentDir(dir);
  114.             lock=Lock(alldata->ed_Name,ACCESS_READ);
  115.             Examine(lock,fileinfo);
  116.             if(fileinfo->fib_DirEntryType>0)  /* Directory ? */
  117.               strcat(compl,"/");
  118.             UnLock(lock);
  119.             FreeDosObject(DOS_FIB,fileinfo);
  120.            }
  121.          }
  122.         else
  123.           for(ead=alldata->ed_Next; ead!=NULL; ead=ead->ed_Next)
  124.            {
  125.             filter_equal_part(&ead->ed_Name[strlen(part)-FILTER_LEN]);
  126.            }
  127.        }
  128.       FreeDosObject(DOS_EXALLCONTROL,eac);
  129.      }
  130.     free(alldata);
  131.    }
  132. }
  133.  
  134.  
  135.  
  136. struct InputEvent *observe_input(struct InputEvent *oldevent)
  137. {
  138. /* This is the handler itself.
  139.    It puts every rawkey into the buffer, clears the buffer when a
  140.    SPACE comes along and signals on arrival of a TAB */
  141.  
  142.   int_start();
  143.   if(!buf_busy)
  144.     for(cur_ev=oldevent; cur_ev!=NULL; cur_ev=cur_ev->ie_NextEvent)
  145.      {
  146.       if(cur_ev->ie_Class==IECLASS_RAWKEY/* && !(cur_ev->ie_Code&0x80)*/)
  147.        {
  148.         if(cur_ev->ie_Code==0x42)    /* TAB */
  149.          {
  150.           event=*cur_ev;
  151.           buf_busy=TRUE;
  152.           Signal(task,sig);
  153.           cur_ev->ie_Class=IECLASS_NULL;
  154.          }
  155.         else if(cur_ev->ie_Code==0x40 ||    /* SPACE */
  156.                 cur_ev->ie_Code==0x44 ||    /* RETURN */
  157.                 cur_ev->ie_Code==0x4c ||    /* Arrow Up */
  158.                 cur_ev->ie_Code==0x4d ||    /* Arrow Down */
  159.                 cur_ev->ie_Code==0x4e)      /* Arrow Right */
  160.           bufpos=0;
  161.         else
  162.          {
  163.           ie_buffer[bufpos++]=*cur_ev;
  164.           if(bufpos==BUF_LEN)
  165.             bufpos=0;
  166.          }
  167.        }
  168.      }
  169.   int_end();
  170.   return(oldevent);
  171. }
  172.  
  173.  
  174. void put_into_stream(char *str)
  175. {
  176.   /* puts the given string into the input stream */
  177.   int i;
  178.   struct cq_pair {UBYTE code, qual;} raw_char;
  179.  
  180.   event.ie_NextEvent=NULL;    /* recycle received event */
  181.   for(i=0; str[i]!=0; i++)
  182.    {
  183.     MapANSI(&str[i],1,&raw_char,1,NULL);
  184.     event.ie_Code=raw_char.code;
  185.     event.ie_Qualifier=raw_char.qual;
  186.     io_req->io_Data=(APTR)&event;
  187.     io_req->io_Length=sizeof(struct InputEvent);
  188.     io_req->io_Command=IND_WRITEEVENT;
  189.     DoIO((struct IORequest *)io_req);
  190.    }
  191. }
  192.  
  193. serve_handler()
  194. {
  195.   /* Waits for a Signal from the handler, finds the appropriate completion
  196.      for the given part of the path and puts it into the input stream
  197.      (sends it to the input device) */
  198.  
  199.   struct Process *proc;   /* process of the current CLI */
  200.   BPTR old_lock,path_lock;
  201.   int i,strpos;
  202.   char tmp;
  203.  
  204.   sig=1<<AllocSignal(-1);
  205.   task=FindTask(NULL);    /* for signaling from interrupt */
  206.   for(;;)
  207.    {
  208.     Wait(sig);
  209.     ilock=LockIBase(0);
  210.     proc=IntuitionBase->ActiveWindow->UserData; /* set by cfn_newshell */
  211.     UnlockIBase(ilock);
  212.     if(proc!=NULL)    /* set by "cfn_newshell" (should be started first) */
  213.      {
  214.       strpos=0;
  215.       for(i=0; i<bufpos; i++)
  216.        {
  217.         ie_buffer[i].ie_NextEvent=NULL;
  218.         if(ie_buffer[i].ie_Code==0x41)  /* Backspace */
  219.           buf[strpos ? strpos--:0]=0;
  220.         else
  221.           strpos+=MapRawKey(&ie_buffer[i],&buf[strpos],20,NULL);
  222.        }
  223.       buf_busy=FALSE;
  224.       buf[strpos]=0;  /* buf is now the incomplete filename */
  225.       old_lock=CurrentDir(proc->pr_CurrentDir);   /* CDir of the input shell */
  226.       strpos=(int)(PathPart(buf)-buf);
  227.       tmp=buf[strpos];
  228.       buf[strpos]=0;
  229.       path_lock=Lock(buf,ACCESS_READ);
  230.       buf[strpos]=tmp;
  231.       find_completion(FilePart(buf),path_lock);
  232.       put_into_stream(compl);
  233.       CurrentDir(old_lock);
  234.       UnLock(path_lock);
  235.      }
  236.    }
  237. }
  238.  
  239.  
  240. main()
  241. {
  242.   if(open_libs())
  243.    {
  244.     if(port=CreatePort(NULL,0))
  245.      {
  246.       if(handler=AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR))
  247.        {
  248.         if(io_req=(struct IOStdReq *)CreateExtIO(port,sizeof(struct IOStdReq)))
  249.          {
  250.           if(!OpenDevice("input.device",0,(struct IORequest *)io_req,0))
  251.            {
  252.             handler->is_Code=observe_input;
  253.             handler->is_Data=NULL;
  254.             handler->is_Node.ln_Pri=1;  /* just before console.device */
  255.             handler->is_Node.ln_Name="cfn";
  256.             io_req->io_Data=(APTR)handler;
  257.             io_req->io_Command=IND_ADDHANDLER;
  258.             DoIO((struct IORequest *)io_req);
  259.             serve_handler();  /* never returns... */
  260.            }
  261.           else
  262.             puts("cfn: ERROR: could not open input.device\n");
  263.          }
  264.         else
  265.           puts("cfn: ERROR: could not create IO-Request\n");
  266.        }
  267.       else
  268.         puts("cfn: ERROR: could not allocate memory for interrupt structure\n");
  269.      }
  270.     else
  271.       puts("cfn: ERROR: could not create port \n");
  272.    }
  273.   else
  274.     puts("cfn: ERROR: could not open intuition.library !\n");
  275.   close_libs();
  276. }
  277.