Detabbed
[AROS.git] / rom / dos / match_old.c
blob4b31f17ad700ca788ed49dd8cab26266e6e2d515
1 matchfirst.c:
5 /*
6 Copyright © 1995-2007, The AROS Development Team. All rights reserved.
7 $Id$
9 Desc:
10 Lang: english
12 #include "dos_intern.h"
13 #include <proto/exec.h>
14 #include <exec/memory.h>
15 #include <exec/types.h>
16 #include <dos/dos.h>
18 /*****************************************************************************
20 NAME */
21 #include <dos/dosasl.h>
22 #include <proto/dos.h>
24 AROS_LH2(LONG, MatchFirst,
26 /* SYNOPSIS */
27 AROS_LHA(STRPTR , pat, D1),
28 AROS_LHA(struct AnchorPath *, AP , D2),
30 /* LOCATION */
31 struct DosLibrary *, DOSBase, 137, Dos)
33 /* FUNCTION
35 Searches for the first file or directory that matches a given pattern.
36 MatchFirst() initializes the AnchorPath structure for you but you
37 must initilize the following fields: ap_Flags, ap_Strlen, ap_BreakBits
38 and ap_FoundBreak. The first call to MatchFirst() also passes you
39 the first matching file which you can examine in ap_Info and the directory
40 the files is in in ap_Current->an_Lock. After the first call to
41 MatchFirst() call MatchNext().
42 The search begins whereever the current directory is set to. See
43 CurrentDir();
44 For more info on patterns see ParsePattern().
46 INPUTS
47 pat - pattern to search for
48 AP - pointer to (initilized) AnchorPath structure
50 RESULT
51 0 = success
52 other = DOS error code
54 NOTES
56 EXAMPLE
58 BUGS
59 Copying of the relative path to ap_Buf is not implemented yet
61 SEE ALSO
62 MatchNext(), MatchEnd(), ParsePattern(), Examine(), CurrentDir()
63 <dos/dosasl.h>
65 INTERNALS
67 *****************************************************************************/
69 AROS_LIBFUNC_INIT
71 struct AChain * AC;
72 struct AChain * AC_Prev = NULL;
73 LONG PatLength;
74 STRPTR ParsedPattern;
75 BPTR firstlock;
77 bug("matchfirst\n");
79 if (!pat)
80 return FALSE;
82 AP->ap_Base = NULL;
83 AP->ap_Current = NULL;
85 PatLength = 2*strlen(pat)+2;
86 ParsedPattern = AllocMem(PatLength, MEMF_ANY);
89 if (NULL != ParsedPattern)
91 LONG PatStart = 0;
92 LONG PatEnd = 0;
93 BOOL AllDone = FALSE;
94 LONG index;
95 LONG success = FALSE;
96 BPTR origdir;
98 bug("matchfirst: ParsedPattern mem okay. Calling ParsePatternNoCase\n");
101 ** Put the preparsed string to some memory
102 ** If there are any wildcards then leave info
104 if (1 == ParsePatternNoCase(pat, ParsedPattern, PatLength))
105 AP->ap_Flags |= (BYTE)APF_ITSWILD;
107 //bug("matchfirst: ParsePatternNoCase returned: pattern = \"%s\"\n", ParsedPattern);
110 ** First I search for the very first ':'. If a '/' comes along
111 ** before that I quit. The string before and including the ':'
112 ** is assumed to be an assigned directory, for example 'libs:'.
113 ** So I will start looking for the pattern in that directory.
115 while (TRUE)
117 if (ParsedPattern[PatEnd] == ':')
119 success = TRUE;
120 break;
122 else
124 if ( ParsedPattern[PatEnd] == '/' ||
125 ParsedPattern[PatEnd] == '\0' ||
126 (ParsedPattern[PatEnd] & 0x80) != 0
127 /* a token or nonprintable letter */)
129 PatEnd = 0;
130 break;
133 PatEnd++;
137 ** Only if success == TRUE an assigned dir was found.
139 if (TRUE == success)
142 ** try to create a lock to that assigned dir.
144 char Remember = ParsedPattern[PatEnd+1];
145 PatEnd++;
146 ParsedPattern[PatEnd] = '\0';
147 firstlock = Lock(ParsedPattern, ACCESS_READ);
148 origdir = CurrentDir(firstlock);
151 ** check whether an error occurred
153 if (NULL == firstlock)
155 FreeMem(ParsedPattern, PatLength);
156 return IoErr(); // ERROR_DIR_NOT_FOUND; /* !!! hope that's the right error code... */
160 ** I have the correct lock.
162 ParsedPattern[PatEnd] = Remember;
163 PatStart=PatEnd;
165 } /* if (TRUE == success) */
166 else
169 ** Create a lock to the current dir.
171 origdir = CurrentDir(NULL);
172 firstlock = DupLock(origdir);
173 if (!firstlock)
175 FreeMem(ParsedPattern, PatLength);
176 return IoErr();
179 (void)CurrentDir(firstlock);
182 bug("MatchFirst: origdir = %x\n", origdir);
183 bug("MatchFirst: firstlock = %x\n", firstlock);
186 ** Allocate an AChain structure for the original directory.
188 AC = (struct AChain *)AllocVec(sizeof(struct AChain), MEMF_CLEAR);
189 if (NULL == AC)
192 ** No more memory
194 FreeMem(ParsedPattern, PatLength);
195 UnLock(firstlock);
196 CurrentDir(origdir);
198 return ERROR_NO_FREE_STORE;
201 AC->an_Lock = origdir;
202 AC->an_Flags = DDF_Completed|DDF_Single;
203 AC_Prev = AC;
206 AP->ap_Base = AC;
209 ** Build the Anchor Chain. For every subdirectory I allocate
210 ** an AChain structure and link them all together
212 while (FALSE == AllDone)
215 ** Search for the next '/' in the pattern and everything behind
216 ** the previous '/' and before this '/' will go to an_String
218 while (TRUE)
220 if (ParsedPattern[PatEnd] == '\0')
222 AllDone = TRUE;
223 PatEnd--;
224 break;
226 if (ParsedPattern[PatEnd] == '/')
228 PatEnd--;
229 break;
231 PatEnd++;
233 } /* while(TRUE) */
235 AC = AllocVec(sizeof(struct AChain)+(PatEnd-PatStart+2), MEMF_CLEAR);
236 if (NULL == AC)
238 /* not so bad if this was not the very first AC. */
239 if (NULL == AP->ap_Base)
242 ** oops, it was the very first one. I really cannot do anything for
243 ** you. - sorry
245 FreeMem(ParsedPattern, PatLength);
247 UnLock(AP->ap_Base->an_Lock);
248 CurrentDir(origdir); /* stegerg */
249 FreeMem(AP->ap_Base, sizeof(struct AChain));
251 return ERROR_NO_FREE_STORE;
255 ** let me out of here. I will at least try to do something for you.
256 ** I can check the first few subdirs but that's gonna be it.
258 AP->ap_Flags |= APF_NOMEMERR;
259 break;
261 } /* if (NULL == AC) */
263 if (NULL == AP->ap_Base)
264 AP->ap_Base = AC;
266 if (NULL == AP->ap_Current)
267 AP->ap_Current = AC;
270 if (NULL != AC_Prev)
271 AC_Prev->an_Child = AC;
273 AC->an_Parent = AC_Prev;
274 AC_Prev = AC;
277 ** copy the part of the pattern to the end of the AChain.
279 index = 0;
280 while (PatStart <= PatEnd)
282 AC->an_String[index] = ParsedPattern[PatStart];
283 index++;
284 PatStart++;
288 ** Put PatStart and PetEnd behind the '/' that was found.
290 PatStart = PatEnd + 2;
291 PatEnd += 2;
294 ** the trailing '\0' is there automatically as I allocated enough store
295 ** with MEMF_CLEAR
298 } /* while (FALSE == AllDone) */
301 ** Free the pattern since it has been distributed now
303 FreeMem(ParsedPattern, PatLength);
306 ** The AnchorChain to work with is the second one.
308 AP->ap_Base = AP->ap_Base->an_Child;
309 AC = AP->ap_Base;
311 AC->an_Lock = firstlock;
313 (void)Examine(AC->an_Lock, &AC->an_Info);
315 return followpattern(AP, AC, DOSBase);
317 } /* if (NULL != ParsedPattern) */
318 else
320 return ERROR_NO_FREE_STORE;
323 return 0;
325 AROS_LIBFUNC_EXIT
327 } /* MatchFirst */
334 matchnext.c:
343 Copyright © 1995-96, The AROS Development Team. All rights reserved.
344 $Id$
346 Desc:
347 Lang: english
349 #include <exec/memory.h>
350 #include <exec/types.h>
351 #include <dos/dos.h>
352 #include <proto/exec.h>
353 #include "dos_intern.h"
355 /*****************************************************************************
357 NAME */
358 #include <dos/dosasl.h>
359 #include <proto/dos.h>
361 AROS_LH1(LONG, MatchNext,
363 /* SYNOPSIS */
364 AROS_LHA(struct AnchorPath *, AP, D1),
366 /* LOCATION */
367 struct DosLibrary *, DOSBase, 138, Dos)
369 /* FUNCTION
370 Find next file or directory that matches a given pattern.
371 See <dos/dosasl.h> for more docs and how to control MatchNext().
374 INPUTS
375 AP - pointer to Anchor Path structure which had been passed to
376 MatchFirst() before.
378 RESULT
380 NOTES
382 EXAMPLE
384 BUGS
385 Copying of the relative path to ap_Buf is not implemented yet
388 SEE ALSO
389 MatchFirst() MatchEnd() CurrentDir() Examine() ExNext()
390 ParsePattern() <dos/dosasl.h>
392 INTERNALS
394 *****************************************************************************/
396 AROS_LIBFUNC_INIT
399 ** If the user says I am supposed to enter the directory then I first check
400 ** whether it is a directory...
403 struct AChain * AC = AP->ap_Current;
404 BOOL success;
405 struct Task * task = FindTask(NULL);
407 bug("matchnext\n");
409 AP->ap_BreakBits &= (SIGBREAKF_CTRL_C|
410 SIGBREAKF_CTRL_D|
411 SIGBREAKF_CTRL_E|
412 SIGBREAKF_CTRL_F);
414 if (0 != (AP->ap_Flags & APF_DODIR ))
416 bug("matchnext: APF_DODIR is set\n");
417 if (AC->an_Info.fib_DirEntryType >= 0 /* &&
418 AC->an_Info.fib_DirEntryType != ST_SOFTLINK */)
420 bug("matchnext: APF_DODIR is set. Is a directory.\n");
422 /* Ok, it seems to be a directory so I will enter it. */
423 /* See whether there's a AnchorChain for that dir... */
424 if (NULL == AC->an_Child)
426 bug("matchnext: APF_DODIR is set. Is a directory. Has no child. Creating temp AChain\n");
427 AC->an_Child = (struct AChain *)
428 AllocVec(sizeof(struct AChain)+1, MEMF_CLEAR);
430 if (AC->an_Child)
432 AC->an_Child->an_Parent = AC;
434 AC->an_Child->an_String[0] = P_ANY;
435 AC->an_Child->an_Flags = DDF_PatternBit;
438 bug("matchnext: Created temporary AChain structure: %x!\n", AC->an_Child);
441 if (NULL != AC->an_Child)
443 BPTR newdir;
445 bug("matchnext: APF_DODIR is set. Is a directory. Has child.\n");
447 /* Ok, we're all set. */
448 /* Lock the director by it's name. */
449 AP->ap_Current = AC->an_Child;
451 bug("matchnext: APF_DODIR is set. Is a directory. Has child. Locking \"%s\"\n", AC->an_Info.fib_FileName);
453 newdir = Lock(AC->an_Info.fib_FileName, ACCESS_READ);
454 bug("matchnext: APF_DODIR is set. Is a directory. Has child. Lock = %x\n", newdir);
456 if (!newdir) /* stegerg */
458 AC = AC->an_Child;
459 return IoErr();
460 } /* end stegerg */
462 //kprintf("CurrentDir()ing %x\n",AC->an_Info.fib_FileName);
463 (void)CurrentDir(newdir);
464 bug("matchnext: APF_DODIR is set. Is a directory. Has child. CurrentDir()ed to lock\n");
466 AC = AC->an_Child;
467 AC->an_Lock = newdir;
468 bug("matchnext: APF_DODIR is set. Is a directory. Has child. Calling Examine\n");
469 Examine(AC->an_Lock, &AC->an_Info);
470 bug("matchnext: APF_DODIR is set. Is a directory. Has child. Called Examine\n");
472 else
474 bug("matchnext: APF_DODIR is set. Could not alloc temp AChain. Returnin ERROR_NO_FREE_STORE\n");
475 return ERROR_NO_FREE_STORE;
478 } /* if (AC->an_Info.fib_DirEntryType >= 0 ... */
480 } /* if (0 != (AP->ap_Flags & APF_DODIR )) */
482 AP->ap_Flags &= ~(BYTE)(APF_DODIR|APF_DIDDIR);
484 bug("matchnext 2\n");
487 ** AC points to the current AnchorChain
489 while (TRUE)
493 ULONG breakbits;
495 ** Check for a break signal CTRL C/D/E/F
497 breakbits = (AP->ap_BreakBits & SetSignal(0, 0)); /* task->tc_SigRecvd */
499 if (0 != breakbits)
502 ** Finish right here... there might be a problem when/if the
503 ** algorithm is resumed the next time... Gotta test that.
505 AP->ap_FoundBreak = breakbits;
506 bug("matchnext 2: break bits were set. Returning ERROR_BREAK\n");
508 return ERROR_BREAK;
511 success = ExNext (AC->an_Lock, &AC->an_Info);
514 while (DOSTRUE == success &&
515 DOSFALSE == MatchPatternNoCase(AC->an_String,
516 AC->an_Info.fib_FileName));
519 if (DOSFALSE == success)
521 bug("matchnext 2: success == DOSFALSE (no matching file)\n");
523 ** No more entries in this dir that match. So I might have to
524 ** step back one directory. Unlock the current dir first.
527 //kprintf("Couldn't find a matching file.!\n");
529 if (AP->ap_Base == AC)
531 bug("matchnext 2: success == DOSFALSE (no matching file). Unlocking %x\n", AC->an_Lock);
532 UnLock(AC->an_Lock);
533 AP->ap_Current = AC->an_Parent;
534 bug("matchnext 2: success == DOSFALSE (no matching file). AP->ap_Current = %x\n", AP->ap_Current);
535 bug("matchnext 2: currentdiring to %x\n", AP->ap_Current->an_Lock);
536 CurrentDir(AP->ap_Current->an_Lock); /* stegerg */
537 bug("matchnext 2: Cannot step back dir. Returning ERROR_NO_MORE_ENTRIES\n");
538 return ERROR_NO_MORE_ENTRIES;
542 ** Are there any previous directories???
544 if (NULL != AC && NULL != AC->an_Parent)
546 LONG retval = 0;
548 bug("matchnext 2: success == DOSFALSE. There is a Parent and AC is *not* NULL. Unlocking %x\n", AC->an_Lock);
550 UnLock(AC->an_Lock);
551 AC->an_Lock = NULL;
553 AC = AC->an_Parent;
554 AP->ap_Current = AC;
556 bug("matchnext 2: success == DOSFALSE. There is a Parent and AC is *not* NULL. CurrentDir()ing %x\n", AC->an_Lock);
558 CurrentDir(AC->an_Lock);
560 if (AC->an_Child->an_Flags & DDF_PatternBit)
562 FreeVec(AC->an_Child);
563 AC->an_Child = NULL;
565 else
566 if (0 == (AC->an_Flags & DDF_PatternBit))
569 ** In this case I must silently follow the pattern again...
571 bug("matchnext 2: success == DOSFALSE. DDF_PatternBit is *not* set. Leaving matchnext with result from followpattern()\n");
572 return followpattern(AP, AC, DOSBase);
575 AP->ap_Flags |= APF_DIDDIR;
577 ** I show this dir again as I come back from searching it
580 retval = createresult(AP, AC, DOSBase);
583 ** Step back to this directory and go on searching here
586 CurrentDir(AC->an_Lock);
588 if (NULL == AC->an_Parent)
589 retval = ERROR_NO_MORE_ENTRIES;
591 bug("matchnext 2: returning retval\n", retval);
593 return retval;
595 } /* if (NULL != AC->an_Parent && NULL != AC) */
597 bug("matchnext 2: success == DOSFALSE. There is no Parent and/or AC is NULL. Returning ERROR_NO_MORE_ENTRIES\n");
600 ** No previous directory, so I am done here...
602 return ERROR_NO_MORE_ENTRIES;
604 } /* if (DOSFALSE == success) */
605 else
607 bug("matchnext 2: success == DOSTRUE (found a match). Leaving matchnext wth result from createresult()\n");
608 /* Alright, I found a match... */
609 return createresult(AP, AC, DOSBase);
612 } /* while (TRUE) */
614 bug("matchnext 2: returning 0.\n");
616 return 0;
618 AROS_LIBFUNC_EXIT
620 } /* MatchNext */
626 matchend.c:
634 Copyright © 1995-96, The AROS Development Team. All rights reserved.
635 $Id$
637 Desc:
638 Lang: english
640 #include <proto/exec.h>
641 #include "dos_intern.h"
643 /*****************************************************************************
645 NAME */
646 #include <dos/dosasl.h>
647 #include <proto/dos.h>
649 AROS_LH1(void, MatchEnd,
651 /* SYNOPSIS */
652 AROS_LHA(struct AnchorPath *, AP, D1),
654 /* LOCATION */
655 struct DosLibrary *, DOSBase, 139, Dos)
657 /* FUNCTION
658 Free the memory that was allocated by calls to MatchFirst() and
659 MatchNext()
661 INPUTS
662 AP - pointer to Anchor Path structure which had been passed to
663 MatchFirst() before.
665 RESULT
666 Allocated memory is returned and filelocks are freed.
668 NOTES
670 EXAMPLE
672 BUGS
674 SEE ALSO
676 INTERNALS
678 *****************************************************************************/
680 AROS_LIBFUNC_INIT
682 /* Free the AChain and unlock all locks that are still there */
683 struct AChain * AC = AP->ap_Current;
684 struct AChain * AC_tmp;
686 /* Unlock everything */
687 if (NULL == AC)
688 return;
690 while (NULL != AC->an_Parent)
692 bug("MatchEnd: unlocking %x\n", AC->an_Lock);
693 UnLock(AC->an_Lock);
694 AC = AC->an_Parent;
697 bug("MatchEnd: CurrentDir(%x)\n", AC->an_Lock);
699 CurrentDir(AC->an_Lock);
701 /* AC points to the very first AChain obj. in the list */
702 /* Free the AChain List */
703 while (NULL != AC)
705 AC_tmp = AC->an_Child;
706 FreeVec(AC);
707 AC = AC_tmp;
710 /* Cleanup AP */
711 AP->ap_Base = NULL;
712 AP->ap_Current = NULL;
714 AROS_LIBFUNC_EXIT
716 } /* MatchEnd */
726 match_misc.c:
728 #include <exec/types.h>
729 #include <proto/exec.h>
730 #include <proto/dos.h>
731 #include <dos/dosasl.h>
732 #include "dos_intern.h"
733 #include <string.h>
735 LONG followpattern(struct AnchorPath * AP,
736 struct AChain * AC,
737 struct DosLibrary * DOSBase)
739 LONG success;
741 bug("followpattern start\n");
744 ** If the user specified the pattern libs:#?/s#/
745 ** then I must enter that pattern before I return to the user.
747 while (TRUE)
751 success = ExNext (AC->an_Lock, &AC->an_Info);
753 while (DOSTRUE == success &&
754 DOSFALSE == MatchPatternNoCase(AC->an_String,
755 AC->an_Info.fib_FileName));
758 ** If no matching entry could be found here then I
759 ** step back one directory, unless this is the very
760 ** first directory already.
762 if (DOSFALSE == success)
764 bug("followpattern: success is DOSFALSE. Unlocking AC->an_Lock %x\n", AC->an_Lock);
765 UnLock(AC->an_Lock);
766 AC->an_Lock = NULL;
768 AC = AC->an_Parent;
769 bug("followpattern: success is DOSFALSE. AC now %x\n", AC);
771 AP->ap_Current = AC;
773 bug("followpattern: success is DOSFALSE. CurrentDir()ing to %x\n", AC->an_Lock);
775 CurrentDir(AC->an_Lock);
777 bug("followpattern: success is DOSFALSE. AC has parent = %s\n", AC->an_Parent ? "yes" : "no");
779 if (NULL == AC->an_Parent)
781 bug("followpattern: success is DOSFALSE. Has no parent. --> returning ERROR_NO_MORE_ENTRIES\n");
782 return ERROR_NO_MORE_ENTRIES;
785 else
787 bug("followpattern: success *not* DOSFALSE.\n");
788 if (AC->an_Info.fib_DirEntryType >= 0 /* &&
789 AC->an_Info.fib_DirEntryType != ST_SOFTLINK */)
791 bug("followpattern: success *not* DOSFALSE. Is a directory.\n");
793 ** I must silently enter this directory if there
794 ** are further patterns left, otherwise I return to the
795 ** user.
797 if (NULL != AC->an_Child)
800 ** Silently entering this dir according to the
801 ** pattern.
803 BPTR newdir;
805 bug("followpattern: success *not* DOSFALSE. Is a directory. Has a child. Entering\n");
807 AP->ap_Current = AC->an_Child;
809 bug("followpattern: success *not* DOSFALSE. Is a directory. Locking + CurrentDir()ing to %s\n", AC->an_Info.fib_FileName);
811 newdir = Lock(AC->an_Info.fib_FileName, ACCESS_READ);
812 bug("followpattern: success *not* DOSFALSE. Is a directory. Locking done. Lock = %x\n", newdir);
813 (void)CurrentDir(newdir);
815 bug("followpattern: success *not* DOSFALSE. Is a directory. CurrentDir()ing done\n");
817 AC = AC->an_Child;
818 AC->an_Lock = newdir;
820 bug("followpattern: success *not* DOSFALSE. Is a directory. Examining lock %x\n", newdir);
822 Examine(AC->an_Lock, &AC->an_Info);
823 bug("followpattern: success *not* DOSFALSE. Is a directory. Examining lock done\n");
825 else
827 bug("followpattern: success *not* DOSFALSE. Is a directory. Has now child. Leaving followpattern with result from createresult\n");
829 ** Ask the user whether to enter this dir or not
831 return createresult(AP, AC, DOSBase);
834 } /* is a directory */
835 else
838 ** This is a file. If there is pattern left to match then
839 ** I must not show this file because I must fulfill the pattern
840 ** first.
842 if (NULL == AC->an_Child)
844 bug("followpattern: is a file and has no child: leaving followpattern with result from createresult \n");
847 ** There's no pattern left!
849 return createresult(AP, AC, DOSBase);
851 else
852 bug("followpattern: Silently skipping file %s!\n",AC->an_Info.fib_FileName);
854 } /* is a file */
856 } /* if (DOSFALSE == success) */
858 } /* while (TRUE) */
860 #if 0
862 ** Hooray! A matching file was found. Also show the data in AP
864 createresult(AP, AC, DOSBase);
865 #endif
871 ** A file/directory has been found and now it must be written
872 ** into the relevant structures.
874 LONG createresult(struct AnchorPath * AP,
875 struct AChain * AC,
876 struct DosLibrary * DOSBase)
878 bug("createresult\n");
880 CopyMem(&AC->an_Info, &AP->ap_Info, sizeof(struct FileInfoBlock));
881 if (0 != AP->ap_Strlen)
883 if (FALSE == writeFullPath(AP))
885 bug("createresult: returning ERROR_BUFFER_OVERFLOW\n");
886 return ERROR_BUFFER_OVERFLOW;
890 bug("createresult: done\n");
892 return 0;
896 /* Function needed by MatchFirst/Next */
898 BOOL writeFullPath(struct AnchorPath * AP)
900 struct AChain * AC = AP->ap_Base;
901 BOOL end = FALSE;
902 char * LastPos = (char *)&AP->ap_Buf;
903 int copied = 0;
905 bug("writefullpath\n");
906 while (FALSE == end)
908 int len = strlen(AC->an_Info.fib_FileName);
909 if (copied+len > AP->ap_Strlen)
911 bug("writefullpath: not enough space\n");
912 return FALSE;
914 strcpy(&LastPos[copied], AC->an_Info.fib_FileName);
915 copied += len;
917 if (AC != AP->ap_Current)
919 /* also add a '/' */
920 if (copied+1 > AP->ap_Strlen)
922 bug("writefullpath: not enough space 2\n");
923 return FALSE;
925 LastPos[copied]='/';
926 copied++;
928 else
930 if (copied+1 > AP->ap_Strlen)
932 bug("writefullpath: not enough space 3\n");
933 return FALSE;
935 LastPos[copied]='\0';
936 end = TRUE;
939 AC = AC->an_Child;
942 bug("writefullpath: done\n");
944 return TRUE;