include unistd for swab.
[AROS-Contrib.git] / fish / cfn / cfn.c
blobc0e5d4bc25a84c8fcc6e9af864bba5f971fcbf17
1 /* - cfn - completes filenames when pressing the "TAB" key */
3 /* written in 1993 by Andreas Günther */
5 /* ( compiled with aztec-C 5.2 ) */
6 /* for more information, please read the doc-file */
9 /* this is NOT great artwork, so */
11 /* FEEL FREE TO IMPROVE THIS CODE ! */
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 :) */
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
25 #include <exec/types.h>
26 #include <exec/interrupts.h>
27 #include <exec/memory.h>
28 #include <intuition/intuitionbase.h>
29 //#include "functions.h"
30 #include <devices/input.h>
31 #include <dos/dosextens.h>
32 #include <dos/exall.h>
33 #include <proto/alib.h>
34 #include <proto/keymap.h>
35 #include <proto/utility.h>
37 #include <aros/oldprograms.h>
38 #include <aros/debug.h>
40 #define BUF_LEN 256 /* number of buffered characters from input stream */
41 #define COMPL_LEN 64 /* maximum length of filename completion */
42 #define FILTER "~(#?.info)"
43 #define FILTER_LEN 10
44 #ifndef __GNUC__
45 #pragma amicall(SysBase, 0, observe_input(a0))
46 #endif
48 #define int_start()
49 #define int_end()
51 char *ver="$VER: cfn 1.0 (21.6.93) by Andreas Günther";
53 struct IntuitionBase *IntuitionBase=NULL;
54 struct Library *KeymapBase=NULL;
55 struct UtilityBase *UtilityBase=NULL;
56 ULONG ilock,sig;
57 BOOL ready;
58 struct InputEvent event, *cur_ev;
60 struct Task *task;
61 char buf[BUF_LEN]; /* recently typed characters */
62 struct InputEvent ie_buffer[2*BUF_LEN]; /* recently typed characters as InputEvents*/
63 int bufpos=0;
64 BOOL buf_busy=FALSE;
65 char compl[COMPL_LEN]; /* actual completion */
66 struct Interrupt *handler;
67 struct MsgPort *port;
68 struct IOStdReq *io_req;
71 BOOL open_libs()
73 IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",37);
74 KeymapBase = OpenLibrary("keymap.library",37);
75 UtilityBase = (struct UtilityBase *)OpenLibrary("utility.library",37);
76 return(IntuitionBase!=NULL && KeymapBase!=NULL && UtilityBase!=NULL);
79 void close_libs()
81 if(NULL!=IntuitionBase)
82 CloseLibrary((struct Library *)IntuitionBase);
83 if(NULL!=KeymapBase)
84 CloseLibrary(KeymapBase);
85 if(NULL!=UtilityBase)
86 CloseLibrary((struct Library *)UtilityBase);
91 void filter_equal_part(char *file)
93 /* leaves in compl[] only the first chars that are equal with "file" */
94 int i=0;
95 while(ToUpper(file[i])==ToUpper(compl[i]) && compl[i]!=0 && file[i]!=0)
96 i++;
97 compl[i]=0;
100 void find_completion(char *part, BPTR dir)
102 /* scans the given dir and finds the longest unique completion */
103 char pat[COMPL_LEN*2+6];
104 struct ExAllControl *eac;
105 struct ExAllData *alldata, *ead;
106 BPTR lock;
108 kprintf("cfn: find_completion(%s dir = %x)\n", part, dir);
110 compl[0]=0;
111 if(NULL!=(alldata=(struct ExAllData *)malloc(3000)))
113 strcat(part,FILTER);
114 ParsePatternNoCase(part,pat,COMPL_LEN*2+6);
115 eac=AllocDosObject(DOS_EXALLCONTROL,NULL);
116 if(eac!=NULL)
118 eac->eac_MatchString=pat;
119 eac->eac_LastKey=0;
120 ExAll(dir,alldata,3000,ED_NAME,eac);
121 if(eac->eac_Entries!=0)
123 strcpy(compl,&alldata->ed_Name[strlen(part)-FILTER_LEN]);
124 if(eac->eac_Entries==1)
126 struct FileInfoBlock *fileinfo;
127 if(NULL!=(fileinfo=AllocDosObject(DOS_FIB,NULL)))
129 CurrentDir(dir);
130 lock=Lock(alldata->ed_Name,ACCESS_READ);
131 Examine(lock,fileinfo);
132 if(fileinfo->fib_DirEntryType>0) /* Directory ? */
133 strcat(compl,"/");
134 UnLock(lock);
135 FreeDosObject(DOS_FIB,fileinfo);
138 else
139 for(ead=alldata->ed_Next; ead!=NULL; ead=ead->ed_Next)
141 filter_equal_part(&ead->ed_Name[strlen(part)-FILTER_LEN]);
144 FreeDosObject(DOS_EXALLCONTROL,eac);
146 free(alldata);
152 struct InputEvent *observe_input(struct InputEvent *oldevent)
154 /* This is the handler itself.
155 It puts every rawkey into the buffer, clears the buffer when a
156 SPACE comes along and signals on arrival of a TAB */
158 int_start();
159 if(!buf_busy)
160 for(cur_ev=oldevent; cur_ev!=NULL; cur_ev=cur_ev->ie_NextEvent)
162 if(cur_ev->ie_Class==IECLASS_RAWKEY/* && !(cur_ev->ie_Code&0x80)*/)
164 if(cur_ev->ie_Code==0x42) /* TAB */
166 kprintf("cfn: tab rawkey :-)\n");
167 event=*cur_ev;
168 buf_busy=TRUE;
169 Signal(task,sig);
170 cur_ev->ie_Class=IECLASS_NULL;
172 else if(cur_ev->ie_Code==0x40 || /* SPACE */
173 cur_ev->ie_Code==0x44 || /* RETURN */
174 cur_ev->ie_Code==0x4c || /* Arrow Up */
175 cur_ev->ie_Code==0x4d || /* Arrow Down */
176 cur_ev->ie_Code==0x4e) /* Arrow Right */
177 bufpos=0;
178 else
180 ie_buffer[bufpos++]=*cur_ev;
181 if(bufpos==BUF_LEN)
182 bufpos=0;
186 int_end();
187 return(oldevent);
191 void put_into_stream(char *str)
193 /* puts the given string into the input stream */
194 int i;
195 TEXT raw_char[2];
197 event.ie_NextEvent=NULL; /* recycle received event */
198 for(i=0; str[i]!=0; i++)
200 MapANSI(&str[i],1,&raw_char[0],1,NULL);
201 event.ie_Code=raw_char[0];
202 event.ie_Qualifier=raw_char[1];
203 io_req->io_Data=(APTR)&event;
204 io_req->io_Length=sizeof(struct InputEvent);
205 io_req->io_Command=IND_WRITEEVENT;
206 DoIO((struct IORequest *)io_req);
210 void serve_handler(void)
212 /* Waits for a Signal from the handler, finds the appropriate completion
213 for the given part of the path and puts it into the input stream
214 (sends it to the input device) */
216 struct Process *proc; /* process of the current CLI */
217 BPTR old_lock,path_lock;
218 int i,strpos;
219 char tmp;
221 sig=1<<AllocSignal(-1);
222 task=FindTask(NULL); /* for signaling from interrupt */
223 for(;;)
225 kprintf("cfn: waiting for sig\n");
226 Wait(sig);
227 kprintf("cfn: received sig\n");
228 ilock=LockIBase(0);
229 proc=(struct Process *)IntuitionBase->ActiveWindow->UserData; /* set by cfn_newshell */
230 UnlockIBase(ilock);
231 kprintf("cfn: proc = %x\n", proc);
232 if(proc!=NULL) /* set by "cfn_newshell" (should be started first) */
234 strpos=0;
235 for(i=0; i<bufpos; i++)
237 ie_buffer[i].ie_NextEvent=NULL;
238 if(ie_buffer[i].ie_Code==0x41) /* Backspace */
239 buf[strpos ? strpos:0]=0;
240 else
241 strpos+=MapRawKey(&ie_buffer[i],&buf[strpos],20,NULL);
244 buf_busy=FALSE;
245 buf[strpos]=0; /* buf is now the incomplete filename */
246 kprintf("cfn: buf = [%s]\n",buf);
248 old_lock=CurrentDir(proc->pr_CurrentDir); /* CDir of the input shell */
249 strpos=(int)((IPTR)PathPart(buf)-(IPTR)buf);
250 tmp=buf[strpos];
251 buf[strpos]=0;
252 path_lock=Lock(buf,ACCESS_READ);
253 buf[strpos]=tmp;
254 find_completion(FilePart(buf),path_lock);
255 put_into_stream(compl);
256 CurrentDir(old_lock);
257 UnLock(path_lock);
263 int main(int argc, char **argv)
265 if(open_libs())
267 if((port=CreatePort(NULL,0)))
269 if((handler=AllocMem(sizeof(struct Interrupt),MEMF_PUBLIC|MEMF_CLEAR)))
271 if((io_req=(struct IOStdReq *)CreateExtIO(port,sizeof(struct IOStdReq))))
273 if(!OpenDevice("input.device",0,(struct IORequest *)io_req,0))
275 handler->is_Code=(VOID_FUNC)observe_input;
276 handler->is_Data=NULL;
277 handler->is_Node.ln_Pri=1; /* just before console.device */
278 handler->is_Node.ln_Name="cfn";
279 io_req->io_Data=(APTR)handler;
280 io_req->io_Command=IND_ADDHANDLER;
281 DoIO((struct IORequest *)io_req);
282 serve_handler(); /* never returns... */
284 else
285 puts("cfn: ERROR: could not open input.device\n");
287 else
288 puts("cfn: ERROR: could not create IO-Request\n");
290 else
291 puts("cfn: ERROR: could not allocate memory for interrupt structure\n");
293 else
294 puts("cfn: ERROR: could not create port \n");
296 else
297 puts("cfn: ERROR: could not open intuition.library !\n");
298 close_libs();
299 return 0;