/* ** Find - AmigaDOS 2.04 commodities utility ** ** Copyright © 1991-1992 by Olaf `Olsen' Barthel ** All Rights Reserved */ #include "FindGlobal.h" /* DisableWindow(BYTE IncludeStart): * * Disable the gadgets in the window, include `Start' gadget * if desired. */ VOID __regargs DisableWindow(BYTE IncludeStart) { /* Block the menu bar. */ Window -> Flags |= WFLG_RMBTRAP; /* Set the wait pointer. */ SetWait(Window); /* Disable the remaining gadgets. */ GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHAREA],Window,NULL, GA_Disabled, TRUE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHFOR],Window,NULL, GA_Disabled, TRUE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_WILDCARDS],Window,NULL, GA_Disabled, TRUE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GA_Disabled, TRUE, TAG_DONE); /* Are we to disable the `Start' gadget? */ if(IncludeStart) { GT_SetGadgetAttrs(GadgetArray[GAD_START],Window,NULL, GA_Disabled, TRUE, TAG_DONE); } } /* EnableWindow(): * * Reenable the gadgets disabled by DisableWindow() and * restore menu and mouse pointer. */ VOID EnableWindow() { /* Enable the gadgets. */ GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHAREA],Window,NULL, GA_Disabled, FALSE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHFOR],Window,NULL, GA_Disabled, FALSE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_WILDCARDS],Window,NULL, GA_Disabled, FALSE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GA_Disabled, FALSE, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_START],Window,NULL, GA_Disabled, FALSE, TAG_DONE); /* Restore the mouse pointer. */ ClearPointer(Window); /* Enable the menu. */ Window -> Flags &= ~WFLG_RMBTRAP; } /* EditRoutine(): * * String gadget editing hook routine, called for each key pressed while * a string gadget is active. */ VOID __saveds __asm EditRoutine(register __a0 struct Hook *Hook,register __a1 ULONG *Msg,register __a2 struct SGWork *Work) { /* Did we receive a keystroke? */ if(Msg[0] == SGH_KEY) { /* Was the right Amiga key pressed? */ if(Work -> IEvent -> ie_Qualifier & IEQUALIFIER_RCOMMAND) { /* Did we get a `C' (copy gadget contents to clipboard)? */ if(ToUpper(Work -> Code) == 'C' && Work -> PrevBuffer[0]) { /* Don't put this keystroke into the buffer. */ Work -> Actions &= ~SGA_USE; /* Is the clipboard server running? */ if(ClipPort) { struct MsgPort *ReplyPort; /* Create a replyport. */ if(ReplyPort = CreateMsgPort()) { struct Message ClipMessage; /* Initialize the transport message. */ ClipMessage . mn_Node . ln_Name = Work -> PrevBuffer; ClipMessage . mn_ReplyPort = ReplyPort; ClipMessage . mn_Length = sizeof(struct Message); /* Tell the clipboard server to save the contents. */ PutMsg(ClipPort,&ClipMessage); /* Wait for reply... */ WaitPort(ReplyPort); /* Remove message from ReplyPort. */ GetMsg(ReplyPort); /* Delete the ReplyPort. */ DeleteMsgPort(ReplyPort); } } else Work -> Actions |= SGA_BEEP; } /* Did we get a `V' (insert clipboard contents)? */ if(ToUpper(Work -> Code) == 'V') { /* Don't put this keystroke into the buffer. */ Work -> Actions &= ~SGA_USE; /* Is the clipboard server running? */ if(ClipPort) { struct MsgPort *ReplyPort; /* Create a replyport. */ if(ReplyPort = CreateMsgPort()) { STATIC UBYTE Buffer[257]; struct Message ClipMessage; /* Mark the buffer as empty. */ Buffer[0] = 0; /* Initialize the transport message. */ ClipMessage . mn_Node . ln_Name = &Buffer[0]; ClipMessage . mn_ReplyPort = ReplyPort; ClipMessage . mn_Length = sizeof(struct Message); /* Tell the clipboard server to send us some data. */ PutMsg(ClipPort,&ClipMessage); /* Wait for reply... */ WaitPort(ReplyPort); /* Remove message from ReplyPort. */ GetMsg(ReplyPort); /* Delete the ReplyPort. */ DeleteMsgPort(ReplyPort); /* Did we get any text? */ if(Buffer[0]) { WORD Len = strlen(Buffer); /* Determine how many bytes the gadget * will be able to accept from the buffer. */ while(Len > 0 && Work -> NumChars + Len > Work -> StringInfo -> MaxChars) Len--; /* Are we able to insert any text? */ if(Len > 0) { STATIC UBYTE OtherBuffer[257]; /* Provide null-termination for * the (shrunken?) buffer. */ Buffer[Len] = 0; /* Copy the current string buffer * contents to the undo buffer. */ strcpy(Work -> StringInfo -> UndoBuffer,Work -> PrevBuffer); /* Adjust the undo cursor position. */ Work -> StringInfo -> UndoPos = --Work -> BufferPos; /* Copy the first bytes of the string * buffer contents to our private buffer. */ if(Work -> BufferPos) CopyMem(Work -> PrevBuffer,OtherBuffer,Work -> BufferPos); /* Provide null-termination. */ OtherBuffer[Work -> BufferPos] = 0; /* Append the new data. */ strcat(OtherBuffer,Buffer); /* Append the data to follow the cursor. */ strcat(OtherBuffer,&Work -> PrevBuffer[Work -> BufferPos]); /* Install the new buffer contents. */ strcpy(Work -> WorkBuffer,OtherBuffer); /* Adjust contents data accordingly... */ Work -> BufferPos += Len; Work -> NumChars += Len; /* Tell Intuition what to do with the buffer. */ Work -> Actions |= SGA_USE; Work -> EditOp = EO_BIGCHANGE; } else Work -> Actions |= SGA_BEEP; } } } else Work -> Actions |= SGA_BEEP; } } } } /* ClipServer(): * * The clipboard server process, waits for incoming load or save * requests and processes them. */ VOID __saveds ClipServer() { /* Try to create a MsgPort other processes will use to talk to us. */ if(ClipPort = CreateMsgPort()) { ULONG Mask; struct Message *ClipMsg; UBYTE *Buffer; BYTE Terminated = FALSE; /* Flag the main process to continue. */ Signal(MainProcess,SIG_REPLY); /* Go into loop waiting for messages... */ while(!Terminated) { /* Wait for message or termination signal. */ Mask = Wait(SIG_KILL | SIG_CLIP); /* Are we to remove ourselves? */ if(Mask & SIG_KILL) Terminated = TRUE; /* Are we to process a clipboard request? */ if(Mask & SIG_CLIP) { /* Process all messages. */ while(ClipMsg = GetMsg(ClipPort)) { /* Pick up the buffer to work on. */ Buffer = ClipMsg -> mn_Node . ln_Name; /* If there is data to be * dealt with, save the buffer. */ if(Buffer[0]) SaveClip(Buffer,strlen(Buffer)); else { WORD Len = LoadClip(Buffer,255); /* In any other case, * try to fill the buffer. */ Buffer[Len] = 0; } /* Reply the message. */ ReplyMsg(ClipMsg); } } } /* Delete the ReplyPort, at the time this is happening * the control panel has already been closed. */ DeleteMsgPort(ClipPort); } /* Don't quit before we are done. */ Forbid(); /* Ring back & fall through. */ Signal(MainProcess,SIG_REPLY); } /* SaveClip(UBYTE *Buffer,LONG Size): * * Save text data to the clipboard. */ BYTE __regargs SaveClip(UBYTE *Buffer,LONG Size) { struct IFFHandle *Handle; BYTE Success = FALSE; /* Allocate an IFFHandle... */ if(Handle = AllocIFF()) { /* Make it operate on the clipboard. */ if(Handle -> iff_Stream = (ULONG)OpenClipboard(PRIMARY_CLIP)) { /* Tell iffparse.library that it is to deal * with the clipboard, not with an AmigaDOS file. */ InitIFFasClip(Handle); /* Open the handle for writing. */ if(!OpenIFF(Handle,IFFF_WRITE)) { /* Say it's a formatted text form. */ if(!PushChunk(Handle,'FTXT','FORM',IFFSIZE_UNKNOWN)) { /* Create the text chunk. */ if(!PushChunk(Handle,0,'CHRS',Size)) { /* Write the actual data. */ if(WriteChunkBytes(Handle,Buffer,Size) == Size) { /* Did the chunk get written correctly? */ if(!PopChunk(Handle)) Success = TRUE; } } } /* Did our previous actions succeed? */ if(Success) { /* Did the chunk get written correctly? */ if(PopChunk(Handle)) Success = FALSE; } /* Close the iff stream. */ CloseIFF(Handle); } /* Flush the data out to the clipboard. */ CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream); } /* Free the IFFHandle data. */ FreeIFF(Handle); } /* Return whether our actions were successful or not. */ return(Success); } /* LoadClip(UBYTE *Buffer,LONG Size): * * Fill the buffer with up to `Size' bytes. */ LONG __regargs LoadClip(UBYTE *Buffer,LONG Size) { struct IFFHandle *Handle; LONG Bytes = 0; /* Allocate an IFFHandle... */ if(Handle = AllocIFF()) { /* Make it operate on the clipboard. */ if(Handle -> iff_Stream = (ULONG)OpenClipboard(PRIMARY_CLIP)) { /* Tell iffparse.library that it is to deal * with the clipboard, not with an AmigaDOS file. */ InitIFFasClip(Handle); /* Open the handle for reading. */ if(!OpenIFF(Handle,IFFF_READ)) { /* Tell the parser to stop at the * beginning of character data * inside formatted text chunks. */ if(!StopChunk(Handle,'FTXT','CHRS')) { /* Start the parser and process * the data encountered. */ if(!ParseIFF(Handle,IFFPARSE_SCAN)) { struct ContextNode *ContextNode; /* Determine the current chunk information * (we will need it in order to query the * size of it). */ if(ContextNode = CurrentChunk(Handle)) { LONG BytesRead; /* Don't read more data * than we will be able * to handle. */ if(Size > ContextNode -> cn_Size) Size = ContextNode -> cn_Size; /* Read as much data as required. */ BytesRead = ReadChunkBytes(Handle,Buffer,Size); /* If any data was available, * remember how much we were * able to read. */ if(BytesRead > 0) Bytes = BytesRead; } } } /* Close the iff stream. */ CloseIFF(Handle); } /* Free clipboard resources. */ CloseClipboard((struct ClipboardHandle *)Handle -> iff_Stream); } /* Free the IFFHandle data. */ FreeIFF(Handle); } /* Return the number of bytes we were actually able to read. */ return(Bytes); } /* ShowMessage(UBYTE *Text,...): * * Display text in the message line of the control panel. */ VOID __stdargs ShowMessage(UBYTE *Text,...) { va_list VarArgs; /* Fill the buffer with the data to be displayed. */ va_start(VarArgs,Text); VSPrintf(MessageBuffer,Text,VarArgs); va_end(VarArgs); /* If the control panel is still available, make the * text appear in the message line. */ if(Window) { GT_SetGadgetAttrs(GadgetArray[GAD_TEXT],Window,NULL, GTTX_Text, MessageBuffer, TAG_DONE); } } /* ShowRequest(UBYTE *Text,UBYTE *Gadgets,...): * * Display an Intuition EasyRequest. */ BOOL __stdargs ShowRequest(UBYTE *Text,UBYTE *Gadgets,...) { struct EasyStruct Easy; BOOL Result; ULONG IDCMP = NULL; va_list VarArgs; /* Initialize the EasyStruct structure with default values. */ Easy . es_StructSize = sizeof(struct EasyStruct); Easy . es_Flags = NULL; Easy . es_Title = (UBYTE *)"Find Request"; Easy . es_TextFormat = (UBYTE *)Text; Easy . es_GadgetFormat = (UBYTE *)Gadgets; /* Pick up the arguments passed to this routine and * put up the requester. */ va_start(VarArgs,Gadgets); Result = EasyRequestArgs(Window,&Easy,&IDCMP,VarArgs); va_end(VarArgs); /* Return the result. */ return(Result); } /* BuildBits(ULONG Protection): * * Build a protection bit string. */ UBYTE * __regargs BuildBits(ULONG Protection) { STATIC UBYTE Buffer[9], *Bits[2] = { "----apsh", "dewr----"} ; WORD i,j = 0; /* Count the bits down... */ for(i = 7 ; i >= 0 ; i--) { /* Is the bit set? */ if(Protection & (1 << i)) Buffer[j++] = Bits[0][i]; else Buffer[j++] = Bits[1][i]; } /* Provide null-termination. */ Buffer[8] = 0; /* Return the working buffer. */ return(Buffer); } /* BuildDate(struct DateStamp *Stamp): * * Build time and date strings from a DateStamp. */ VOID __regargs BuildDate(struct DateStamp *Stamp) { struct DateTime DateTime; /* Initialize conversion structure. */ DateTime . dat_Stamp = *Stamp; DateTime . dat_Flags = DTF_SUBST | FORMAT_DOS; DateTime . dat_StrDay = NULL; DateTime . dat_StrDate = Date; DateTime . dat_StrTime = Time; /* Convert the date. */ if(!DateToStr(&DateTime)) { /* If the conversion failed, provide default data. */ strcpy(Date,"----------"); strcpy(Time,"--:--:--"); } } /* BuildPathList(UBYTE *String): * * Build a list of nodes, representing a file search path from * a full path string. */ VOID __regargs BuildPathList(UBYTE *String) { UBYTE Buffer[256]; WORD i,j = 0; /* Copy the path string. */ strcpy(Buffer,String); /* Use the original string pointer as an index pointer into the buffer. */ String = Buffer; /* Reset the path list. */ NewList(&FileList); /* Scan the string looking for the colon terminating * the root directory name. */ while(String[j]) { if(String[j] == ':') { String[j] = 0; break; } else j++; } /* Copy the root directory name to the first node name. */ SPrintf(FileNames[0] . Name,"%s:",String); /* Add the node to list (oh well, since the list at this * point is empty, AddTail() would have accomplished * the same). */ AddHead(&FileList,&FileNames[0]); /* Proceed to the next path component. */ String = &String[j + 1]; /* Start at the beginning. */ i = 1; /* Process the remaining list. */ FOREVER { j = 0; /* Try to find the next slash terminating * the next directory name. */ while(String[j]) { if(String[j] == '/') break; else j++; } /* Did we reach the end of the path? */ if(String[j]) { /* Provide null-termination. */ String[j] = 0; /* Copy the directory name into the next node. */ SPrintf(FileNames[i] . Name," %s",String); /* Add the node to the end of the list. */ AddTail(&FileList,&FileNames[i++]); /* Proceed to the next path component. */ String = &String[j + 1]; } else { /* Now we are at the base file name. */ SPrintf(FileNames[i] . Name," %s",String); /* Add the node to the end of the list. */ AddTail(&FileList,&FileNames[i]); break; } } } /* ClearRect(WORD Len,WORD Top): * * Erase the remaining space in a line of the main display list. */ VOID __regargs ClearRect(WORD Len,WORD Top) { BYTE FgPen = RPort -> FgPen; SetAPen(RPort,RPort -> BgPen); RectFill(RPort,10 + 4 + Len * SystemFontWidth,ListTopLine + 2 + SystemFontHeight * Top,ListRightColumn - 4,ListTopLine + 2 + SystemFontHeight * (Top + 1) - 1); SetAPen(RPort,FgPen); } /* RefreshList(): * * Refresh the contents of the main display list. */ VOID RefreshList() { /* Are we to display text? */ if(!NumNames || Scanning) { BYTE FgPen = RPort -> FgPen; /* Obviously not, clear the main display area. */ SetAPen(RPort,0); RectFill(RPort,10 + 4,ListTopLine + 2,ListRightColumn - 4,ListTopLine + 2 + (10 * SystemFontHeight) - 1); SetAPen(RPort,FgPen); } else { WORD i; /* Draw all five lines. */ for(i = 0 ; i < 5 ; i++) { /* Are we still processing data in the list? */ if(ListTop + i < NumNames) { WORD Len = strlen(NameList[ListTop + i] -> NamePart); /* Move to the position to print the file name. */ Move(RPort,10 + 4,ListTopLine + 2 + SystemFontBase + (2 * SystemFontHeight) * i); /* If the current entry happens to be selected, * highlight it. */ if(NameList[ListTop + i] -> Selected) { /* Are we allowed to use more than two colours? */ if(NewLook) { SetBPen(RPort,2); /* Print the file name. */ Text(RPort,NameList[ListTop + i] -> NamePart,Len); /* Clear the area to the right of * the file name. */ ClearRect(Len,i * 2); /* Move one line down. */ Move(RPort,10 + 4,ListTopLine + 2 + SystemFontBase + SystemFontHeight + (2 * SystemFontHeight) * i); /* Is a file type available? */ if(FileTypes[NameList[ListTop + i] -> Type]) { /* Determine file type length. */ Len = strlen(FileTypes[NameList[ListTop + i] -> Type]); SetAPen(RPort,3); /* Display the file type. */ Text(RPort,FileTypes[NameList[ListTop + i] -> Type],Len); SetAPen(RPort,1); } else Len = 0; /* Clear the area to the right of * the file name. */ ClearRect(Len,i * 2 + 1); } else { /* Roughly the same as above, * designed for use with two * colours only. */ SetAPen(RPort,0); SetBPen(RPort,1); Text(RPort,NameList[ListTop + i] -> NamePart,Len); ClearRect(Len,i * 2); Move(RPort,10 + 4,ListTopLine + 2 + SystemFontBase + SystemFontHeight + (2 * SystemFontHeight) * i); if(FileTypes[NameList[ListTop + i] -> Type]) { Len = strlen(FileTypes[NameList[ListTop + i] -> Type]); Text(RPort,FileTypes[NameList[ListTop + i] -> Type],Len); } else Len = 0; ClearRect(Len,i * 2 + 1); SetAPen(RPort,1); } SetBPen(RPort,0); } else { /* Same as above, but text is not highlighted. */ Text(RPort,NameList[ListTop + i] -> NamePart,Len); ClearRect(Len,i * 2); Move(RPort,10 + 4,ListTopLine + 2 + SystemFontBase + SystemFontHeight + (2 * SystemFontHeight) * i); if(FileTypes[NameList[ListTop + i] -> Type]) { Len = strlen(FileTypes[NameList[ListTop + i] -> Type]); SetAPen(RPort,3); Text(RPort,FileTypes[NameList[ListTop + i] -> Type],Len); SetAPen(RPort,1); } else Len = 0; ClearRect(Len,i * 2 + 1); } } else { /* Clear any remaining lines. */ SetAPen(RPort,0); RectFill(RPort,14,ListTopLine + 2 + (2 * SystemFontHeight) * i,ListRightColumn - 4,ListTopLine + 2 + (10 * SystemFontHeight) - 1); SetAPen(RPort,1); break; } } } } /* SelectSearchArea(): * * Puts up a file requester and allows the user to select * the directory the user wishes the search to begin at. */ BYTE SelectSearchArea() { /* If no path name is available, use the current directory name. */ if(!AreaName[0]) { if(!NameFromLock(FindProcess -> pr_CurrentDir,AreaName,256)) AreaName[0] = 0; } /* Open up the file requester. */ if(AslRequestTags(FileRequest, ASL_Window, Window, ASL_Dir, AreaName, TAG_DONE)) { /* Did we get a directory name? */ if(FileRequest -> rf_Dir[0]) { /* Copy the directory name. */ strcpy(AreaName,FileRequest -> rf_Dir); return(TRUE); } } return(FALSE); } /* RefreshFile(): * * Refresh the file info field. */ VOID RefreshFile() { /* Build the file creation time and date. */ BuildDate(&NameList[LastSelected] -> Date); /* Draw the text headers. */ DrawFileInfo( 0,0,0,"Creation Date:"); DrawFileInfo( 9,2,0,"Size:"); DrawFileInfo( 7,3,0,"Blocks:"); DrawFileInfo( 3,5,0,"Attributes:"); /* Draw the data. */ DrawFileInfo(15,0,1,Date); DrawFileInfo(15,1,1,Time); DrawFileInfo(15,5,1,BuildBits(NameList[LastSelected] -> Protection)); /* If the current file is in fact a directory or a link to * a directory, don't show its size. */ if(NameList[LastSelected] -> Type == TYPE_DIR || NameList[LastSelected] -> Type == TYPE_LINK) { DrawFileInfo(15,2,1,"-"); DrawFileInfo(15,3,1,"-"); } else { /* Show the file size and the number of blocks it occupies. */ DrawFileInfo(15,2,1,"%ld",NameList[LastSelected] -> Size); DrawFileInfo(15,3,1,"%ld",NameList[LastSelected] -> Blocks); } /* Detach the list from the path list display. */ GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, ~0, TAG_DONE); /* Build the path name list... */ BuildPathList(&NameList[LastSelected] -> Name[0]); /* Attach the path name list to the display. */ GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, &FileList, TAG_DONE); /* Enable the `copy path to clipboard' menu item. */ OnMenu(Window,FULLMENUNUM(1,0,0)); } /* RefreshGfx(): * * Refresh the contents of the window. */ VOID RefreshGfx() { /* Refresh the file information display. */ if(NumNames && LastSelected != -1 && LastSelected < NumNames) { if(NameList[LastSelected] -> Selected) RefreshFile(); } /* Draw the main display list border. */ DrawBevelBox(RPort,10,ListTopLine,WindowWidth - 20 - 2 * SystemFontWidth,SystemFontHeight * 10 + 4, GT_VisualInfo, VisualInfo, TAG_DONE); /* Draw the file information display border. */ DrawBevelBox(RPort,10,PathTopLine,(WindowWidth - 20 - INTERWIDTH) / 2,6 * SystemFontHeight + 4, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE); /* Refresh the gadget list. */ RefreshGList(GadgetList,Window,NULL,(UWORD)-1); /* Refresh the remaining imagery. */ GT_RefreshWindow(Window,NULL); /* Activate a string gadget, depends on the state of the * string gadgets. */ if(!(GT_STRING(GadgetArray[GAD_SEARCHAREA]))[0]) ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHAREA],Window,NULL); else { if(!(GT_STRING(GadgetArray[GAD_SEARCHFOR]))[0]) ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHFOR],Window,NULL); } /* Refresh the main display list. */ RefreshList(); } /* Iconify(BYTE Complain): * * Iconify the window. */ BYTE __regargs Iconify(BYTE Complain) { struct DiskObject *Icon = NULL; BYTE ClosedGfx = FALSE, Success = FALSE; /* If we have a window, save the string gadgets contents. */ if(Window) { DisableWindow(TRUE); strcpy(AreaName,GT_STRING(GadgetArray[GAD_SEARCHAREA])); strcpy(SearchString,GT_STRING(GadgetArray[GAD_SEARCHFOR])); UseWildcards = GT_CHECKED(GadgetArray[GAD_WILDCARDS]); } /* Get the program icon. */ if(WBenchMsg) { if(WBenchMsg -> sm_ArgList[0] . wa_Name) Icon = GetDiskObjectNew(WBenchMsg -> sm_ArgList[0] . wa_Name); } /* No icon? Use the default name. */ if(!Icon) Icon = GetDiskObjectNew("Find"); /* Did we get any icon? */ if(Icon) { /* Not a tool icon? */ if(Icon -> do_Type != WBTOOL) { /* Get rid of it... */ FreeDiskObject(Icon); /* Get the default tool icon. */ Icon = GetDefDiskObject(WBTOOL); } } /* Did we get an icon? */ if(Icon) { struct MsgPort *IconPort; /* Default icon position. */ Icon -> do_CurrentX = NO_ICON_POSITION; Icon -> do_CurrentY = NO_ICON_POSITION; /* Create the Workbench reply port. */ if(IconPort = CreateMsgPort()) { struct AppIcon *AppIcon; /* Add the application icon. */ if(AppIcon = AddAppIcon(0,0,"Find Files",IconPort,NULL,Icon,NULL)) { struct AppMessage *AppMessage; BYTE GotName = FALSE; ULONG Mask; /* Close the control panel. */ CloseGfx(); /* Set some flags. */ ClosedGfx = TRUE; WasIconified = TRUE; IconTerminated = FALSE; Success = TRUE; /* Wait for messages. */ while(!IconTerminated) { Mask = Wait(SIG_CX | SIG_ICON | SIG_KILL); /* Are we to quit? */ if(Mask & SIG_KILL) IconTerminated = Terminated = TRUE; /* Pick up application messages. */ if(Mask & SIG_ICON) { while(AppMessage = (struct AppMessage *)GetMsg(IconPort)) { /* If we did not get a name yet, * try to get it from the AppMessage. */ if(!GotName) { LONG i; /* Run down the list of entries... */ for(i = 0 ; i < AppMessage -> am_NumArgs ; i++) { /* Does it have a lock attached? */ if(AppMessage -> am_ArgList[i] . wa_Lock) { /* Turn it into a name. */ if(NameFromLock(AppMessage -> am_ArgList[i] . wa_Lock,AreaName,256)) { struct FileInfoBlock __aligned FileInfo; /* Examine the type. */ if(Examine(AppMessage -> am_ArgList[i] . wa_Lock,&FileInfo)) { /* Does the lock refer to a file? */ if(FileInfo . fib_DirEntryType < 0) { UBYTE *Stop; /* Take the path part. */ Stop = PathPart(AreaName); /* Cut off the file name. */ *Stop = 0; GotName = TRUE; break; } else GotName = TRUE; } else AreaName[0] = 0; } else AreaName[0] = 0; } } } /* As soon as the AppMessage come in, leave * the iconified state. */ IconTerminated = TRUE; ReplyMsg(AppMessage); } } /* Check for commodities messages. */ if(Mask & SIG_CX) { CxMsg *Message; while(Message = (CxMsg *)GetMsg(CxPort)) HandleCxMsg(Message); } } /* Remove the application icon. */ RemoveAppIcon(AppIcon); /* Reply pending messages. */ while(AppMessage = (struct AppMessage *)GetMsg(IconPort)) ReplyMsg(AppMessage); } else { if(Complain) ShowRequest("Failed to add application icon\n(is Workbench running?).","Continue"); } DeleteMsgPort(IconPort); } else { if(Complain) ShowRequest("Failed to create MsgPort.","Continue"); } FreeDiskObject(Icon); } else { if(Complain) ShowRequest("Failed to open tool icon.","Continue"); } /* If we did in fact close the window, reopen it. */ if(ClosedGfx) { if(!Terminated) { OpenGfx(); RefreshGfx(); } } else { if(Window) EnableWindow(); } return(Success); } /* ClearFileInfo(): * * Clear the file information area. */ VOID ClearFileInfo() { BYTE FgPen = RPort -> FgPen; SetAPen(RPort,0); RectFill(RPort,10 + 2,PathTopLine + 2,10 + 2 + ((WindowWidth - 20 - INTERWIDTH) / 2) - 5,PathTopLine + 2 + 6 * SystemFontHeight - 1); SetAPen(RPort,FgPen); } /* DrawFileInfo(WORD X,WORD Y,BYTE Cut,UBYTE *Format,...): * * Draw text in the file info area. */ VOID __stdargs DrawFileInfo(WORD X,WORD Y,BYTE Cut,UBYTE *Format,...) { STATIC UBYTE Buffer[100]; va_list VarArgs; /* Fill the buffer with the text. */ va_start(VarArgs,Format); VSPrintf(Buffer,Format,VarArgs); va_end(VarArgs); /* Move to the approriate position. */ Move(RPort,14 + SystemFontWidth * X,PathTopLine + 2 + SystemFontBase + SystemFontHeight * Y); /* If desired, add a few blank spaces and cut off the leading * eleven characters. */ if(Cut) { strcat(Buffer," "); Buffer[11] = 0; } /* Print the text. */ Text(RPort,Buffer,strlen(Buffer)); } /* FreeNameList(): * * Free the linked list of names. */ VOID FreeNameList() { /* Do we have a list to free? */ if(NameList) { LONG i; /* Free each list entry. */ for(i = 0 ; i < NumNames ; i++) FreeVec(NameList[i]); /* Free the name list itself. */ FreeVec(NameList); NameList = NULL; } /* Reset the counters. */ NumNames = MaxNames = 0; } /* AddNameList(UBYTE *Name): * * Add another name to the list. */ struct NameString * __regargs AddNameList(UBYTE *Name) { WORD Len; /* Will we need to extend the list? */ if(NumNames + 1 > MaxNames) { struct NameString **NewList; /* Allocate space for ten more list entries. */ if(NewList = (struct NameString **)AllocVec(sizeof(struct NameString *) * (MaxNames + 10),MEMF_CLEAR)) { /* Move the contents of the original name list * to the newly created name list and free * the old list. */ if(NameList) { LONG i; for(i = 0 ; i < NumNames ; i++) NewList[i] = NameList[i]; FreeVec(NameList); } /* Update counter and data. */ MaxNames += 10; NameList = NewList; } else return(NULL); } /* Determine length of the string to add. */ Len = strlen(Name); /* Is the name longer than the longest name? */ if(Len > MaxNameLen) MaxNameLen = Len; /* Allocate space for the new string. */ if(NameList[NumNames] = (struct NameString *)AllocVec(sizeof(struct NameString) + Len,MEMF_CLEAR)) { /* Copy the name. */ strcpy(NameList[NumNames] -> Name,Name); /* Determine the file part. */ NameList[NumNames] -> NamePart = FilePart(NameList[NumNames] -> Name); /* Return the new name list entry. */ return(NameList[NumNames++]); } else return(NULL); } /* MatchSetup(): * * Set up for pattern matching (either through AmigaDOS wildcards * or using the Boyer-Moore algorithm). */ VOID __regargs MatchSetup(UBYTE *Pattern,BYTE Wildcards) { /* Save the flag. */ UseWildcards = Wildcards; /* Set up for the desired pattern matching method. */ if(Wildcards) ParsePatternNoCase(Pattern,MatchData,256); else { WORD i; /* Determine pattern width. */ PatternWidth = strlen(Pattern); /* Convert the pattern to upper case. */ for(i = 0 ; i <= PatternWidth ; i++) NewPattern[i] = ToUpper(Pattern[i]); /* Initialize the default distance values. */ for(i = 0 ; i < 256 ; i++) PatternDistance[i] = PatternWidth; /* Now take care of the pattern contents. */ for(i = 0 ; i < PatternWidth - 1 ; i++) PatternDistance[NewPattern[i]] = PatternWidth - i - 1; } } /* MatchString(UBYTE *String): * * Match a string against a previously defined pattern. */ BYTE __regargs MatchString(UBYTE *String) { /* Use the selected pattern matching mode. */ if(UseWildcards) return((BYTE)MatchPatternNoCase(MatchData,String)); else { WORD j = PatternWidth,k,l,SearchWidth = strlen(String); /* Perform Boyer-Moore search... */ do { k = PatternWidth; l = j; do { k--; l--; } while(k >= 0 && NewPattern[k] == ToUpper(String[l])); j += PatternDistance[ToUpper(String[j - 1])]; } while(k >= 0 && j <= SearchWidth); if(k < 0) return(TRUE); else return(FALSE); } } /* CheckAbort(): * * Check for `abort' condition. */ BYTE CheckAbort() { /* Did we get a message from the window? */ if(SetSignal(0,0) & SIG_WINDOW) { struct IntuiMessage *Massage; struct Gadget *Gadget; UWORD Code; ULONG Class; /* Process all messages. */ while(Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort)) { Class = Massage -> Class; Code = Massage -> Code; Gadget = (struct Gadget *)Massage -> IAddress; GT_ReplyIMsg(Massage); /* Refresh the window contents? */ if(Class == IDCMP_REFRESHWINDOW) RefreshGfx(); /* Did the user press the `Stop' button? */ if(Class == IDCMP_GADGETUP) { switch(Gadget -> GadgetID) { case GAD_START: Aborted = TRUE; break; default: break; } } /* Did the user press the `Stop' key? */ if(Class == IDCMP_VANILLAKEY) { switch(ToUpper((UBYTE)Code)) { case 'S': case '\r': Aborted = TRUE; break; default: break; } } } SetSignal(0,SIG_WINDOW); } /* Did we get a `Stop' signal? */ if(SetSignal(0,0) & SIG_KILL) { Aborted = TRUE; Terminated = TRUE; SetSignal(0,SIG_KILL); } return(Aborted); } /* StartSearch(BPTR Dir,UBYTE *Name,UBYTE Levels): * * This is the recursive directory scanner, the search * process is actually done here. */ VOID __regargs StartSearch(BPTR Dir,UBYTE *Name,UBYTE Levels) { /* Run until finished or aborted. */ if(!Aborted && !CheckAbort()) { struct FileInfoBlock __aligned FileInfo; UBYTE NewName[256]; /* Examine the directory. */ if(Examine(Dir,&FileInfo)) { WORD Len = strlen(Name); /* Remember the name. */ strcpy(NewName,Name); /* Scan the entire directory. */ while(ExNext(Dir,&FileInfo)) { /* Check for abort condition. */ if(Aborted || CheckAbort()) break; /* Add the file name to the base name. */ if(AddPart(NewName,FileInfo . fib_FileName,256)) { /* Did we get a directory? */ if(FileInfo . fib_DirEntryType > 0) { BYTE IsLink = (FileInfo . fib_DirEntryType == 3 || FileInfo . fib_DirEntryType == 4) ? TRUE : FALSE; /* Does the name match the pattern? */ if(MatchString(FileInfo . fib_FileName)) { struct NameString *NameString = AddNameList(NewName); /* If the name fits into the list, fill in * the data connected with it. */ if(NameString) { NameString -> Type = IsLink ? TYPE_LINK : TYPE_DIR; NameString -> Protection = FileInfo . fib_Protection; NameString -> Date = FileInfo . fib_Date; NameString -> Blocks = FileInfo . fib_NumBlocks; /* Update the counters. */ if(IsLink) NumLinks++; else NumDirs++; } } /* So we found a directory, we will enter * it only if we did not enter the eighth * recursion level yet and the directory * is not a link to another directory. */ if(Levels < 8 && !IsLink) { BPTR FileLock; /* Obtain a lock on the directory to enter * and enter it. */ if(FileLock = Lock(FileInfo . fib_FileName,ACCESS_READ)) { BPTR OldDir = CurrentDir(FileLock); /* Continue searching... */ StartSearch(FileLock,NewName,Levels + 1); /* Get back to the original directory. */ CurrentDir(OldDir); /* Unlock the directory. */ UnLock(FileLock); } } } else { /* So we got a file, does its name match * the pattern? */ if(MatchString(FileInfo . fib_FileName)) { struct NameString *NameString = AddNameList(NewName); /* If the name fits into the list, fill in * the data connected with it. */ if(NameString) { NameString -> Type = Identify(NewName); NameString -> Protection = FileInfo . fib_Protection; NameString -> Size = FileInfo . fib_Size; NameString -> Blocks = FileInfo . fib_NumBlocks; NameString -> Date = FileInfo . fib_Date; /* Update the counter. */ NumFiles++; } } } } /* Cut off the file name we had appended to the directory name. */ NewName[Len] = 0; } } } } /* Compare(struct NameString **A,struct NameString **B): * * The element comparison routine, qsort() requires it. */ LONG __stdargs Compare(struct NameString **A,struct NameString **B) { return(Stricmp((*A) -> NamePart,(*B) -> NamePart)); } /* IsAssign(UBYTE *Name): * * Checks if a device/volume name refers in fact to an assignment. */ BYTE __regargs IsAssign(UBYTE *Name) { WORD NameLen = strlen(Name) - 1; BYTE Result = FALSE; /* Does the name have a colon in the last character? */ if(Name[NameLen] == ':') { struct DosList *DosList; /* Open the DosList for reading assignments. */ if(DosList = AttemptLockDosList(LDF_ASSIGNS | LDF_READ)) { UBYTE *AssignName; /* Scan the list for assignments... */ while(DosList = NextDosEntry(DosList,LDF_ASSIGNS)) { /* Make it a real pointer. */ AssignName = (UBYTE *)BADDR(DosList -> dol_Name); /* Is it as long as the name we are looking for? */ if(AssignName[0] == NameLen) { /* Compare the names. */ if(!Strnicmp(&AssignName[1],Name,NameLen)) { Result = TRUE; break; } } } /* Unlock the list again. */ UnLockDosList(LDF_ASSIGNS | LDF_READ); } } return(Result); } /* MultiSearch(UBYTE *Name,UBYTE *TempName): * * Search along the path connected with a multi-volume assignment. */ VOID __regargs MultiSearch(UBYTE *Name,UBYTE *TempName) { struct DevProc *DevProc = NULL; struct MsgPort *FileSysTask = GetFileSysTask(); /* Remember the base name. */ strcpy(TempName,Name); /* Scan along all paths... */ do { /* Get the FileLock referring to the assignment. */ if(DevProc = GetDeviceProc(Name,DevProc)) { /* Compensate for ZERO locks. */ SetFileSysTask(DevProc -> dvp_Port); /* Turn the FileLock into a name. */ if(NameFromLock(DevProc -> dvp_Lock,TempName,256)) { BPTR DirLock = Lock(TempName,ACCESS_READ); /* If we got a valid name, enter the * directory associated with it. */ if(DirLock) { BYTE Levels, Len = strlen(TempName); BPTR OldLock = CurrentDir(DirLock); /* Determine the directory * level this name refers to. */ if(TempName[Len - 1] == ':') Levels = 0; else { BYTE i; Levels = 1; for(i = 0 ; i < Len ; i++) { if(TempName[i] == '/') Levels++; } } /* If possible, scan the directory. */ if(Levels < 8) StartSearch(DirLock,TempName,Levels); /* Get back to the original directory. */ CurrentDir(OldLock); /* Unlock the directory. */ UnLock(DirLock); } } } else break; } while(!Aborted && !CheckAbort() && DevProc && (DevProc -> dvp_Flags & DVPF_ASSIGN)); /* Get back to the original default filing system task. */ SetFileSysTask(FileSysTask); /* Free any data allocated with the DeviceProc structure. */ if(DevProc) FreeDeviceProc(DevProc); } /* ShowInfo(): * * Show an information message concerning the number of * files, directories and linked directories found. */ VOID ShowInfo() { UBYTE *Files = (NumFiles > 1) ? "files" : "file", *Dirs = (NumDirs > 1) ? "directories" : "directory", *Links = (NumLinks > 1) ? "links" : "link"; if(NumFiles == 0 && NumDirs == 0 && NumLinks == 0) ShowMessage("No matching files were found."); else { if(NumFiles) { if(NumDirs) { if(NumLinks) ShowMessage("Found %ld %s, %ld %s and %ld %s.",NumFiles,Files,NumDirs,Dirs,NumLinks,Links); else ShowMessage("Found %ld %s and %ld %s.",NumFiles,Files,NumDirs,Dirs); } else { if(NumLinks) ShowMessage("Found %ld %s and %ld %s.",NumFiles,Files,NumLinks,Links); else ShowMessage("Found %ld %s.",NumFiles,Files); } } else { if(NumDirs) { if(NumLinks) ShowMessage("Found %ld %s and %ld %s.",NumDirs,Dirs,NumLinks,Links); else ShowMessage("Found %ld %s.",NumDirs,Dirs); } else ShowMessage("Found %ld %s.",NumLinks,Links); } } } /* FindFile(): * * This is the big one. Set up for file search. */ VOID FindFile() { /* Disable all gadgets we do not really require. */ DisableWindow(FALSE); /* Remember the contents of the string gadgets. */ strcpy(AreaName, GT_STRING(GadgetArray[GAD_SEARCHAREA])); strcpy(SearchString, GT_STRING(GadgetArray[GAD_SEARCHFOR])); /* Do we have an area to search? */ if(AreaName[0]) { /* Do we have a pattern to search for? */ if(SearchString[0]) { BPTR DirLock; /* Set up match pattern. */ MatchSetup(SearchString,GT_CHECKED(GadgetArray[GAD_WILDCARDS])); /* Get a lock on the search area. */ if(DirLock = Lock(AreaName,ACCESS_READ)) { STATIC UBYTE Name[256]; /* Does the search area name refer to * a multivolume-assignment? */ if(IsAssign(AreaName)) { /* Reset the abort flag. */ Aborted = FALSE; /* Free any previously allocated * name list. */ FreeNameList(); /* Start at the top. */ ListTop = 0; /* Clear the main display area. */ RefreshList(); /* Clear the file information area. */ ClearFileInfo(); /* There is no longer any data in * the list. */ GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, 0, GTSC_Total, 0, TAG_DONE); /* Detach the path name list. */ GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, ~0, TAG_DONE); /* Attach an empty list. */ GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, &EmptyList, TAG_DONE); /* Yes, we are scanning. */ Scanning = TRUE; /* Nothing has been selected yet. */ LastSelected = -1; /* Reset the counters. */ NumFiles = NumDirs = NumLinks = 0; /* Show what we will do. */ ShowMessage("Searching..."); /* Reset the maximum file name length. */ MaxNameLen = 0; /* Start the search... */ MultiSearch(AreaName,Name); /* We are no longer scanning. */ Scanning = FALSE; /* Adjust the slider to represent the * number of entries in the list. */ GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Total, NumNames, TAG_DONE); /* Turn off the `Save list...' and * `Copy path to clipboard' menu * items. */ OffMenu(Window,FULLMENUNUM(1,0,0)); OffMenu(Window,FULLMENUNUM(0,0,NOSUB)); /* Did we find any files? */ if(NumNames) { /* Turn the `Save list...' back on. */ OnMenu(Window,FULLMENUNUM(0,0,NOSUB)); /* Show what we are doing. */ ShowMessage("Sorting..."); /* Sort the list... */ qsort(NameList,NumNames,sizeof(struct NameString *),Compare); /* Clear the main display window. */ SetAPen(RPort,0); RectFill(RPort,14,ListTopLine + 2,ListRightColumn - 4,ListTopLine + 2 + (10 * SystemFontHeight) - 1); SetAPen(RPort,1); /* Redraw the main display window. */ RefreshList(); } /* Show how many files/directories/links we got. */ ShowInfo(); } else { /* Same as above, just for a single directory. */ if(NameFromLock(DirLock,Name,256)) { BYTE Levels, Len = strlen(Name); BPTR OldLock = CurrentDir(DirLock); if(Name[Len - 1] == ':') Levels = 0; else { BYTE i; Levels = 1; for(i = 0 ; i < Len ; i++) { if(Name[i] == '/') Levels++; } } if(Levels < 8) { Aborted = FALSE; FreeNameList(); ListTop = 0; RefreshList(); ClearFileInfo(); GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, 0, GTSC_Total, 0, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, ~0, TAG_DONE); GT_SetGadgetAttrs(GadgetArray[GAD_FILELIST],Window,NULL, GTLV_Labels, &EmptyList, TAG_DONE); Scanning = TRUE; LastSelected = -1; NumFiles = NumDirs = NumLinks = 0; ShowMessage("Searching..."); MaxNameLen = 0; StartSearch(DirLock,Name,Levels); Scanning = FALSE; GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Total, NumNames, TAG_DONE); OffMenu(Window,FULLMENUNUM(1,0,0)); OffMenu(Window,FULLMENUNUM(0,0,NOSUB)); if(NumNames) { OnMenu(Window,FULLMENUNUM(0,0,NOSUB)); ShowMessage("Sorting..."); qsort(NameList,NumNames,sizeof(struct NameString *),Compare); SetAPen(RPort,0); RectFill(RPort,14,ListTopLine + 2,ListRightColumn - 4,ListTopLine + 2 + (10 * SystemFontHeight) - 1); SetAPen(RPort,1); RefreshList(); } ShowInfo(); CurrentDir(OldLock); } else ShowRequest("Sorry, path name too long.","Continue"); } else ShowRequest("Failed to build path name.","Continue"); } UnLock(DirLock); } else { UBYTE Buffer[100]; /* Display the error. */ if(Fault(IoErr(),"",Buffer,100)) { WORD Len = strlen(Buffer) - 1; if(Buffer[Len] == '\n') Buffer[Len] = 0; ShowRequest("Error accessing \"%s\"%s.","Continue",AreaName,Buffer); } else ShowRequest("Error accessing \"%s\".","Continue",AreaName); } } else ShowRequest("You forgot to specify a search pattern.","Continue"); } else ShowRequest("You forgot to specify the search area.","Continue"); /* Enable the window. */ EnableWindow(); /* Remove all pending AppMessages. */ if(WorkbenchPort) { struct Message *Massage; while(Massage = GetMsg(WorkbenchPort)) ReplyMsg(Massage); } } /* CreateAllGadgets(): * * Create all the gadgets required by the control panel. */ struct Gadget * __regargs CreateAllGadgets(struct Gadget **GadgetArray,struct Gadget **GadgetList,APTR VisualInfo,UWORD TopEdge) { struct Gadget *Gadget; struct NewGadget NewGadget; WORD Counter = 0, NewTop, NewLeft; memset(&NewGadget,0,sizeof(struct NewGadget)); if(Gadget = CreateContext(GadgetList)) { NewGadget . ng_Width = 29 * SystemFontWidth + 12; NewGadget . ng_Height = SystemFontHeight + 6; NewGadget . ng_GadgetText = "Search _Area"; NewGadget . ng_TextAttr = &SystemFont; NewGadget . ng_VisualInfo = VisualInfo; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = PLACETEXT_LEFT; NewGadget . ng_LeftEdge = 10 + 12 * SystemFontWidth; NewGadget . ng_TopEdge = INTERHEIGHT + TopEdge; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GTST_String, AreaName, GTST_MaxChars, 256, GTST_EditHook, &StringHook, GT_Underscore, '_', TAG_DONE); NewGadget . ng_GadgetText = "Search _For"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_TopEdge = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT; GadgetArray[Counter++] = Gadget = CreateGadget(STRING_KIND,Gadget,&NewGadget, GTST_MaxChars, 256, GTST_String, SearchString, GTST_EditHook, &StringHook, GT_Underscore, '_', TAG_DONE); NewTop = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT; NewGadget . ng_GadgetText = "_Wildcards"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = PLACETEXT_RIGHT; NewGadget . ng_LeftEdge = NewGadget . ng_LeftEdge + NewGadget . ng_Width + INTERWIDTH; NewGadget . ng_TopEdge = NewGadget . ng_TopEdge + (NewGadget . ng_Height - 12) / 2; NewGadget . ng_Height = 12; NewGadget . ng_Width = 26; GadgetArray[Counter++] = Gadget = CreateGadget(CHECKBOX_KIND,Gadget,&NewGadget, GT_Underscore, '_', GTCB_Checked, UseWildcards, TAG_DONE); if((NewLeft = NewGadget . ng_LeftEdge + NewGadget . ng_Width + 10 * SystemFontWidth + INTERWIDTH) > WindowWidth - NewGadget . ng_Width - 10) { UWORD More = (NewLeft - (WindowWidth - NewGadget . ng_Width - 10) + SystemFontWidth - 1) / SystemFontWidth; WindowWidth += More * SystemFontWidth; } NewGadget . ng_GadgetText = "?"; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_TextAttr = &SystemFont; NewGadget . ng_Height = (SystemFontHeight + 6) * 2 + INTERHEIGHT; NewGadget . ng_Width = (SystemFontWidth * 3) + 4; NewGadget . ng_LeftEdge = WindowWidth - NewGadget . ng_Width - 10; NewGadget . ng_TopEdge = INTERHEIGHT + TopEdge; GadgetArray[Counter++] = Gadget = CreateGadget(BUTTON_KIND,Gadget,&NewGadget, TAG_DONE); if(NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT > NewTop) NewTop = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT; NewGadget . ng_GadgetText = ""; NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_TextAttr = &SystemFont; NewGadget . ng_Height = SystemFontHeight + 6; NewGadget . ng_Width = WindowWidth - 20; NewGadget . ng_TopEdge = NewTop; NewGadget . ng_LeftEdge = 10; GadgetArray[Counter++] = Gadget = CreateGadget(TEXT_KIND,Gadget,&NewGadget, GTTX_Border, TRUE, GTTX_Text, MessageBuffer, TAG_DONE); NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_TopEdge = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT; NewGadget . ng_Height = SystemFontHeight * 10 + 4; NewGadget . ng_Width = 2 * SystemFontWidth; NewGadget . ng_LeftEdge = WindowWidth - NewGadget . ng_Width - 10; ListTopLine = NewGadget . ng_TopEdge; ListRightColumn = NewGadget . ng_LeftEdge - 1; GadgetArray[Counter++] = Gadget = CreateGadget(SCROLLER_KIND,Gadget,&NewGadget, GTSC_Top, ListTop, GTSC_Visible, 5, GTSC_Arrows, SystemFontHeight, GTSC_Total, NumNames, PGA_Freedom, LORIENT_VERT, GA_Immediate, TRUE, GA_RelVerify, TRUE, TAG_DONE); NewGadget . ng_GadgetID = Counter; NewGadget . ng_Flags = 0; NewGadget . ng_TopEdge = NewGadget . ng_TopEdge + NewGadget . ng_Height + INTERHEIGHT; NewGadget . ng_Height = 6 * SystemFontHeight + 4; NewGadget . ng_Width = (WindowWidth - 20 - INTERWIDTH) / 2; NewGadget . ng_LeftEdge = 10 + INTERWIDTH + NewGadget . ng_Width; PathTopLine = NewGadget . ng_TopEdge; GadgetArray[Counter] = Gadget = CreateGadget(LISTVIEW_KIND,Gadget,&NewGadget, GTLV_ReadOnly, TRUE, GTLV_ScrollWidth, 2 * SystemFontWidth, TAG_DONE); } return(Gadget); } /* CloseGfx(): * * Close all the graphics data. */ VOID CloseGfx() { /* Shut down the Workbench interface. */ if(WorkbenchWindow) { RemoveAppWindow(WorkbenchWindow); WorkbenchWindow = NULL; } /* Remove the Workbench interface port. */ if(WorkbenchPort) { struct Message *Massage; while(Massage = GetMsg(WorkbenchPort)) ReplyMsg(Massage); DeleteMsgPort(WorkbenchPort); WorkbenchPort = NULL; } /* Close the window. */ if(Window) { Window -> Flags |= WFLG_RMBTRAP; ClearMenuStrip(Window); CloseWindow(Window); Window = NULL; } /* Reset the zoom box data. */ ZoomBox . Left = -1; /* Free the menu. */ if(FindMenu) { FreeMenus(FindMenu); FindMenu = NULL; } /* Free the DrawInfo data. */ if(DrawInfo) { FreeScreenDrawInfo(DefaultScreen,DrawInfo); DrawInfo = NULL; } /* Release the screen our window was residing on. */ if(DefaultScreen) { UnlockPubScreen(NULL,DefaultScreen); DefaultScreen = NULL; } /* Close the default text font. */ if(DefaultFont) { CloseFont(DefaultFont); DefaultFont = NULL; } /* Free the VisualInfo data. */ if(VisualInfo) { FreeVisualInfo(VisualInfo); VisualInfo = NULL; } /* Free the gadget list. */ if(GadgetList) { FreeGadgets(GadgetList); GadgetList = NULL; } } /* CentreWindow(): * * Centre the window to be opened somewhere below the * mouse pointer. */ VOID __regargs CentreWindow(struct Screen *Screen,WORD *LeftEdge,WORD *TopEdge,WORD Left,WORD Top) { (*LeftEdge) = Screen -> MouseX - Left; (*TopEdge) = Screen -> MouseY - Top; while((*LeftEdge) + WindowWidth > Screen -> Width) (*LeftEdge)--; while((*LeftEdge) < 0) (*LeftEdge)++; while((*TopEdge) + WindowHeight > Screen -> Height) (*TopEdge)--; while((*TopEdge) < 0) (*TopEdge)++; } /* OpenGfx(): * * Open all graphics data. */ BYTE OpenGfx() { WORD Left,Top; /* If no public screen has been specified, gain access * to the default screen. */ if(!DefaultScreen) { if(!(DefaultScreen = LockPubScreen(NULL))) return(FALSE); } /* Inquire the drawing pen information. */ if(!(DrawInfo = GetScreenDrawInfo(DefaultScreen))) return(FALSE); /* Determine whether we are to use more than two colours for * text rendering. */ if((DrawInfo -> dri_Flags & DRIF_NEWLOOK) && DrawInfo -> dri_Depth > 1) NewLook = TRUE; else NewLook = FALSE; /* Get the VisualInfo data required for gadtools objects. */ if(!(VisualInfo = GetVisualInfo(DefaultScreen,TAG_DONE))) return(FALSE); /* Turn the currently active system default font information * into a TextAttr structure fit to submit to gadtools. */ Forbid(); strcpy(SystemFontName,GfxBase -> DefaultFont -> tf_Message . mn_Node . ln_Name); SystemFontWidth = GfxBase -> DefaultFont -> tf_XSize; SystemFontHeight = GfxBase -> DefaultFont -> tf_YSize; SystemFontBase = GfxBase -> DefaultFont -> tf_Baseline; SystemFont . ta_Name = SystemFontName; SystemFont . ta_YSize = GfxBase -> DefaultFont -> tf_YSize; SystemFont . ta_Style = GfxBase -> DefaultFont -> tf_Style; SystemFont . ta_Flags = GfxBase -> DefaultFont -> tf_Flags & ~FPF_REMOVED; strcpy(BigSystemFontName,SystemFontName); BigSystemFont . ta_Name = SystemFontName; BigSystemFont . ta_YSize = SystemFont . ta_YSize * 2; BigSystemFont . ta_Style = SystemFont . ta_Style; BigSystemFont . ta_Flags = SystemFont . ta_Flags & ~FPF_DESIGNED; Permit(); /* Calculate the window width. */ WindowWidth = 20 + 58 * SystemFontWidth + 4 + 2 * SystemFontWidth; /* Make sure that the font we just prepared will be available lateron. */ if(!(DefaultFont = OpenFont(&SystemFont))) return(FALSE); /* Create all the gadgets for the control panel. */ if(!CreateAllGadgets(&GadgetArray[0],&GadgetList,VisualInfo,DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1)) return(FALSE); /* Taking a look at the gadgets in the window to be opened, * calculate the height of the window. */ WindowHeight = GadgetArray[GAD_FILELIST] -> TopEdge + GadgetArray[GAD_FILELIST] -> Height + INTERHEIGHT + DefaultScreen -> WBorBottom; /* Will the window fit on the screen? */ if(WindowWidth > DefaultScreen -> Width || WindowHeight > DefaultScreen -> Height) { ShowRequest("The window to be opened would be\ntoo large to fit on the screen.","Sorry"); return(FALSE); } /* Create the window menus. */ if(!(FindMenu = CreateMenus(FindMenuConfig, GTMN_FrontPen, 0, TAG_DONE))) return(FALSE); /* Perform menu layout. */ if(!LayoutMenus(FindMenu,VisualInfo, GTMN_TextAttr, DefaultScreen -> Font, TAG_DONE)) return(FALSE); /* Initialize the window zoom box data if not already done. */ if(ZoomBox . Left == -1) { ZoomBox . Left = 0; ZoomBox . Top = 0; ZoomBox . Width = WindowWidth / 2; ZoomBox . Height = DefaultScreen -> WBorTop + DefaultScreen -> Font -> ta_YSize + 1; } /* Centre the window so that it will open with the mouse pointer * below the `Start' gadget. */ CentreWindow(DefaultScreen,&Left,&Top,GadgetArray[GAD_START] -> LeftEdge + GadgetArray[GAD_START] -> Width / 2,GadgetArray[GAD_START] -> TopEdge + GadgetArray[GAD_START] -> Height / 2); /* The window is not iconified yet. */ IconTerminated = TRUE; /* Prepare the window title. */ if(Broker) SPrintf(WindowTitle,"Find Files: HotKey=%s",HotkeyBuffer); else strcpy(WindowTitle,"Find Files"); /* Finally, open the new window. */ if(!(Window = OpenWindowTags(NULL, WA_Width, WindowWidth, WA_Height, WindowHeight, WA_Left, Left, WA_Top, Top, WA_Activate, TRUE, WA_DragBar, TRUE, WA_DepthGadget, TRUE, WA_CloseGadget, TRUE, WA_RMBTrap, TRUE, WA_Zoom, &ZoomBox, WA_IDCMP, IDCMP_CLOSEWINDOW | IDCMP_RAWKEY | IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS | IDCMP_MENUPICK | IDCMP_REFRESHWINDOW | IDCMP_ACTIVEWINDOW | STRINGIDCMP | ARROWIDCMP | SCROLLERIDCMP | CHECKBOXIDCMP | LISTVIEWIDCMP | BUTTONIDCMP, WA_Title, WindowTitle, WA_CustomScreen,DefaultScreen, TAG_DONE))) return(FALSE); /* Create the Workbench interface MsgPort. */ if(WorkbenchPort = CreateMsgPort()) WorkbenchWindow = AddAppWindow(0,0,Window,WorkbenchPort,NULL); /* A handy shortcut to the window's RastPort. */ RPort = Window -> RPort; /* Set the wait pointer for the window. */ SetWait(Window); /* Make AmigaDOS requesters come up on the current screen. */ FindProcess -> pr_WindowPtr = (APTR)Window; /* Make sure that the string gadgets will use the desired font. */ SetFont(RPort,DefaultFont); /* Draw the main display area border. */ DrawBevelBox(RPort,10,ListTopLine,WindowWidth - 20 - 2 * SystemFontWidth,SystemFontHeight * 10 + 4, GT_VisualInfo, VisualInfo, TAG_DONE); /* Draw the file information area border. */ DrawBevelBox(RPort,10,PathTopLine,(WindowWidth - 20 - INTERWIDTH) / 2,6 * SystemFontHeight + 4, GT_VisualInfo, VisualInfo, GTBB_Recessed, TRUE, TAG_DONE); /* Add the gadgets we just created and make them appear. */ AddGList(Window,GadgetList,(UWORD)-1,(UWORD)-1,NULL); RefreshGList(GadgetList,Window,NULL,(UWORD)-1); GT_RefreshWindow(Window,NULL); /* Set the default rendering pen to 1 and the rendering mode to overwrite. */ SetAPen(RPort,1); SetDrMd(RPort,JAM2); /* Refresh the main display area. */ RefreshList(); /* Attach the menu to the window. */ SetMenuStrip(Window,FindMenu); /* Make the menu strip available to the user. */ Window -> Flags &= ~WFLG_RMBTRAP; /* Restore the mouse pointer. */ ClearPointer(Window); /* Return success. */ return(TRUE); } /* CloseAll(LONG ReturnCode): * * Close and free all resources not directly associated with OpenGfx(). */ VOID __regargs CloseAll(LONG ReturnCode) { /* Free the list of file names. */ FreeNameList(); /* Tell the clipboard process to quit. */ if(ClipProcess) { Signal(ClipProcess,SIG_KILL); Wait(SIG_REPLY); } /* Free the handshake signal. */ if(ReplySignal != -1) FreeSignal(ReplySignal); /* Free both file requester structures. */ if(FileRequest) FreeAslRequest(FileRequest); if(SaveFileRequest) FreeAslRequest(SaveFileRequest); /* Close commodities.library. */ if(CxBase) CloseLibrary(CxBase); /* Close iffparse.library. */ if(IFFParseBase) CloseLibrary(IFFParseBase); /* Close workbench.library. */ if(WorkbenchBase) CloseLibrary(WorkbenchBase); /* Close icon.library. */ if(IconBase) CloseLibrary(IconBase); /* Close asl.library. */ if(AslBase) CloseLibrary(AslBase); /* Close utility.library. */ if(UtilityBase) CloseLibrary(UtilityBase); /* Close gadtools.library. */ if(GadToolsBase) CloseLibrary(GadToolsBase); /* Close graphics.library. */ if(GfxBase) CloseLibrary(GfxBase); /* Close intuition.library. */ if(IntuitionBase) CloseLibrary(IntuitionBase); /* Terminate the program. */ exit(ReturnCode); } /* OpenAll(): * * Opens and initialize the basic resources required by the program. */ VOID OpenAll() { WORD i; /* Initialize the path name node list with correct name buffers. */ for(i = 0 ; i < 10 ; i++) FileNames[i] . VanillaNode . ln_Name = FileNames[i] . Name; /* Clear the list to remain empty. */ NewList(&EmptyList); /* Open all the libraries we need. */ if(!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",37))) CloseAll(RETURN_FAIL + 0); if(!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",37))) CloseAll(RETURN_FAIL + 1); if(!(GadToolsBase = OpenLibrary("gadtools.library",37))) CloseAll(RETURN_FAIL + 2); if(!(UtilityBase = OpenLibrary("utility.library",37))) CloseAll(RETURN_FAIL + 3); if(!(AslBase = OpenLibrary("asl.library",37))) CloseAll(RETURN_FAIL + 4); if(!(IconBase = OpenLibrary("icon.library",37))) CloseAll(RETURN_FAIL + 5); if(!(IFFParseBase = OpenLibrary("iffparse.library",37))) CloseAll(RETURN_FAIL + 6); if(!(WorkbenchBase = OpenLibrary("workbench.library",37))) CloseAll(RETURN_FAIL + 7); /* Try to open commodities.library, but don't worry if * the open fails. */ CxBase = OpenLibrary("commodities.library",37); /* Allocate the first file requester structure. */ if(!(FileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASL_Hail, "Select Search Area", ASL_FuncFlags, FILF_PATGAD, ASL_Pattern, "#?", ASL_OKText, "Select", ASL_ExtFlags1, FIL1F_NOFILES | FIL1F_MATCHDIRS, TAG_DONE))) CloseAll(RETURN_FAIL + 8); /* Allocate the second file requester structure. */ if(!(SaveFileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest, ASL_FuncFlags, FILF_SAVE, ASL_OKText, "Save", TAG_DONE))) CloseAll(RETURN_FAIL + 9); /* Allocate a handshake signal bit. */ if((ReplySignal = AllocSignal(-1)) == -1) CloseAll(RETURN_FAIL + 10); /* Try to create the clipboard server, but don't worry if * the creation fails. */ ClipProcess = CreateNewProcTags( NP_Entry, ClipServer, NP_Name, "Clipboard Server", NP_WindowPtr, -1, NP_Priority, 20, TAG_DONE); /* Wait for handshake signal. */ Wait(SIG_REPLY); /* Initialize the information message buffer. */ strcpy(MessageBuffer,"Find Files v1.7 © Copyright 1991-92 by MXM"); /* Initialize the callback hook required by the string gadgets. */ StringHook . h_Entry = (APTR)EditRoutine; StringHook . h_SubEntry = NULL; StringHook . h_Data = 0; } /* ShutdownCx(): * * Shuts down the commodities.library interface. */ VOID ShutdownCx() { /* Did the situation allow us to create the signal port? */ if(CxPort) { struct Message *Message; /* Remove the input event broker. */ if(Broker) DeleteCxObjAll(Broker); /* Remove the port from the public list. */ RemPort(CxPort); /* Accept and reply all pending messages. */ while(Message = GetMsg(CxPort)) ReplyMsg(Message); /* Delete the signal port. */ DeleteMsgPort(CxPort); /* Clear the pointers to avoid confusion. */ CxPort = NULL; Broker = NULL; } } /* SetupCx(): * * Set up the commodities.library interface. */ BYTE SetupCx() { /* Close down previous installation. */ ShutdownCx(); /* Did the startup code succeed in opening commodities.library? */ if(CxBase) { /* Create a signal port. */ if(CxPort = CreateMsgPort()) { /* Give the port a name. */ CxPort -> mp_Node . ln_Name = NewBroker . nb_Name; /* Add the port to the public list. */ AddPort(CxPort); /* Stuff the interface port into the NewBroker definition. */ NewBroker . nb_Port = CxPort; /* If started from Workbench, process the tooltype entries. */ if(ToolTypes) { /* Install the hotkey definition, the default * being `shift help'. */ strcpy(HotkeyBuffer,ArgString(ToolTypes,"CX_POPKEY","shift help")); /* Install the commodities priority. */ NewBroker . nb_Pri = ArgInt(ToolTypes,"CX_PRIORITY",0); } else { /* Do the same setups for Shell startup, * first take card of the hotkey buffer. */ if(!HotkeyBuffer[0]) strcpy(HotkeyBuffer,"shift help"); /* Install the commodities priority. */ NewBroker . nb_Pri = CxPriority; } /* Create the broker. */ if(Broker = CxBroker(&NewBroker,NULL)) { /* Attach the hotkey. */ AttachCxObj(Broker,HotKey(HotkeyBuffer,CxPort,NULL)); /* Did the setup succeed? */ if(!CxObjError(Broker)) { /* Activate the broker. */ ActivateCxObj(Broker,TRUE); /* Return success. */ return(TRUE); } } /* Something went wrong, shut down * the installation. */ ShutdownCx(); } } /* Return failure. */ return(FALSE); } /* SetupWindow(): * * Do something sensible with the window, bring it to the front and * activate it or move it to the frontmost screen in case the screen * happens to be a public screen. */ VOID SetupWindow() { struct Screen *FirstScreen,*NewDefaultScreen = NULL; UBYTE PubName[MAXPUBSCREENNAME + 1]; ULONG IntuiLock; struct List *PubScreenList; struct PubScreenNode *ScreenNode; BYTE IsPublic = FALSE; /* Lock IntuitionBase... */ IntuiLock = LockIBase(NULL); /* ...extract the frontmost screen... */ FirstScreen = IntuitionBase -> FirstScreen; /* ...and unlock IntuitionBase again. */ UnlockIBase(IntuiLock); /* Lock the public screen list. */ PubScreenList = LockPubScreenList(); /* Search the public screen list for the frontmost screen. */ for(ScreenNode = (struct PubScreenNode *)PubScreenList -> lh_Head ; ScreenNode -> psn_Node . ln_Succ ; ScreenNode = (struct PubScreenNode *)ScreenNode -> psn_Node . ln_Succ) { /* Does the screen match the frontmost screen and * has it been enabled for public access? */ if(ScreenNode -> psn_Screen == FirstScreen && !(ScreenNode -> psn_Flags & PSNF_PRIVATE)) { /* Yes, this is a public screen. */ IsPublic = TRUE; /* Copy the name to refer to it. */ strcpy(PubName,ScreenNode -> psn_Node . ln_Name); break; } } /* Unlock the public screen list again. */ UnlockPubScreenList(); /* Is the window still open? */ if(Window) { /* Is the window residing on the front screen? */ if(FirstScreen == Window -> WScreen) { /* Move the screen up if necessary. */ if(FirstScreen -> TopEdge > 0) MoveScreen(FirstScreen,0,-FirstScreen -> TopEdge); /* Move the window to the front. */ WindowToFront(Window); /* Wait a few ticks to allow Intuition to bring * the screen to the front. */ Delay(5); /* Don't let the user change the window size for * a moment. */ Forbid(); /* If the window happens to be smaller than the * original size we specified, it must be in * `zoomed' state. If so, `unzoom' it. */ if(Window -> Width < WindowWidth) { Permit(); ZipWindow(Window); } else Permit(); /* Activate the window and return. */ ActivateWindow(Window); return; } } /* If we have a public screen our window is to appear on, * make our window jump to it. To do this, gain access to * the public screen we got before. */ if(IsPublic) { /* Try to access the first screen by using its name. */ NewDefaultScreen = LockPubScreen(PubName); } /* Now it's time to decide what to do. If the program * is still in iconified state, get back to normal. If * not, reopen the window. */ if(!IconTerminated) { IconTerminated = TRUE; if(NewDefaultScreen) { /* Unlock the previous public screen. */ UnlockPubScreen(NULL,DefaultScreen); if(DrawInfo) { FreeScreenDrawInfo(DefaultScreen,DrawInfo); DrawInfo = NULL; } /* Take over the new identifier. */ DefaultScreen = NewDefaultScreen; } } else { CloseGfx(); DefaultScreen = NewDefaultScreen; if(OpenGfx()) RefreshGfx(); } } /* HandleCxMsg(CxMsg *Message): * * Handle a commodities toolkit message. */ VOID __regargs HandleCxMsg(CxMsg *Message) { ULONG MessageID = CxMsgID(Message), MessageType = CxMsgType(Message); /* Reply the message, having extracted ID and type first. */ ReplyMsg((struct Message *)Message); /* Check for the message type... */ switch(MessageType) { /* The hotkey was pressed, deal with the window. */ case CXM_IEVENT: SetupWindow(); break; /* It's an internal commodities command. */ case CXM_COMMAND: switch(MessageID) { /* Disable the broker. */ case CXCMD_DISABLE: ActivateCxObj(Broker,FALSE); break; /* Enable the broker again. */ case CXCMD_ENABLE: ActivateCxObj(Broker,TRUE); break; /* Make the window appear. */ case CXCMD_APPEAR: case CXCMD_UNIQUE: if(!Window) IconTerminated = TRUE; else SetupWindow(); break; /* Cause the window to appear. */ case CXCMD_DISAPPEAR: if(Window) DoIconify = TRUE; break; /* Terminate execution. */ case CXCMD_KILL: Terminated = TRUE; if(!Window) IconTerminated = TRUE; break; } break; } } /* ListName(BPTR File,LONG Index): * * Write the information associated with a name list entry to a file * using a `List' style format. */ LONG __regargs ListName(BPTR File,LONG Index) { UBYTE SizeBuffer[20]; /* Build date and time strings. */ BuildDate(&NameList[Index] -> Date); /* Initialize the size/type buffer. */ switch(NameList[Index] -> Type) { case TYPE_DIR: strcpy(SizeBuffer,"Dir"); break; case TYPE_LINK: strcpy(SizeBuffer,"Link"); break; default: SPrintf(SizeBuffer,"%ld",NameList[Index] -> Size); break; } /* Output the formatted string. */ return(FPrintf(File,MaxNameFormat,NameList[Index] -> Name,SizeBuffer,BuildBits(NameList[Index] -> Protection),Date,Time)); } /* SaveList(LONG Mode): * * Save the current file name list to a disk file. */ VOID __regargs SaveList(LONG Mode) { /* The three file requester hail texts. */ STATIC UBYTE *HailText[3] = { "Save full path names", "Save names only", "Save in `List' style format" }; /* Temporary storage. */ UBYTE DummyBuffer[512],*Dummy; /* Block and byte counters. */ ULONG NumBlocks = 0,NumBytes = 0; /* If no file name has been selected yet, initialize * the directory name buffer with the name of the * current directory. */ Start: if(!FullFileName[0]) { if(!NameFromLock(FindProcess -> pr_CurrentDir,FullFileName,512)) LastFileName[0] = FullFileName[0] = 0; else LastFileName[0] = 0; } /* Save the file name. */ strcpy(DummyBuffer,FullFileName); /* Look for the path name part. */ Dummy = PathPart(DummyBuffer); /* Cut off the file name. */ *Dummy = 0; /* Open the file requester. */ if(AslRequestTags(SaveFileRequest, ASL_Window, Window, ASL_Dir, DummyBuffer, ASL_File, LastFileName, ASL_Hail, HailText[Mode - MEN_FULL], TAG_DONE)) { /* Did we get a file name to deal with? */ if(SaveFileRequest -> rf_File[0]) { /* Save the directory name. */ strcpy(FullFileName,SaveFileRequest -> rf_Dir); /* Add the file name part. */ if(AddPart(FullFileName,SaveFileRequest -> rf_File,512)) { BPTR File = NULL, FileLock; LONG Error = 0, Written = 1, i; /* Save the file name separately. */ strcpy(LastFileName,SaveFileRequest -> rf_File); /* Try to get lock on the file name in * question and try to examine it. */ if(FileLock = Lock(FullFileName,ACCESS_READ)) { struct FileInfoBlock __aligned FileInfo; /* Examine the file in question. */ if(Examine(FileLock,&FileInfo)) { /* Does the name refer to a directory instead of a file? */ if(FileInfo . fib_DirEntryType > 0) { ShowRequest("Destination \"%s\" is directory, not a file.","Continue",LastFileName); UnLock(FileLock); goto Start; } else { /* Can we delete (overwrite) it? */ if(FileInfo . fib_Protection & FIBF_DELETE) { ShowRequest("File \"%s\" is protected from deletion and\ncannot be overridden.","Continue",LastFileName); UnLock(FileLock); goto Start; } else { /* Can we write any data to it? */ if(FileInfo . fib_Protection & FIBF_WRITE) { ShowRequest("File \"%s\" is not write-enabled and\ncannot be overridden.","Continue",LastFileName); UnLock(FileLock); goto Start; } } } /* Is there already data in the file which * we may overwrite? */ if(FileInfo . fib_Size > 0) { /* Ask the user what to do with the file. */ switch(ShowRequest("Destination file \"%s\" already exists,\ndo you still want to save the file list?","Override file|Append file|Abort",LastFileName)) { /* Overwrite the file. */ case 1: break; /* Append data to the file; * release the filelock first. */ case 2: UnLock(FileLock); FileLock = NULL; /* Open the file for mixed read and write access. */ if(!(File = Open(FullFileName,MODE_READWRITE))) goto OpenError; else { /* Seek to the end of the file.*/ if(Seek(File,0,OFFSET_END) == -1) { /* Query error condition. */ Error = IoErr(); /* Close the file. */ Close(File); /* Clear the ID to avoid confusion. */ File = NULL; } } break; /* Abort the process. */ case 0: UnLock(FileLock); return; } } } else Error = IoErr(); /* Unlock the filelock again. */ if(FileLock) UnLock(FileLock); } else { Error = IoErr(); /* If unable to find the object, don't * treat it as an error. */ if(Error == ERROR_OBJECT_NOT_FOUND) Error = 0; } /* Display an error message. */ if(Error) { /* Get the AmigaDOS error message. */ if(Fault(Error,"",DummyBuffer,512)) { ShowRequest("An error occured while accessing file \"%s\":%s","Continue",LastFileName,DummyBuffer); goto Start; } else { DisplayBeep(Window -> WScreen); return; } } /* If not already open, create a new file. */ if(!File) { if(!(File = Open(FullFileName,MODE_NEWFILE))) { /* Query error condition. */ OpenError: Error = IoErr(); /* Get the AmigaDOS error message. */ if(Fault(Error,"",DummyBuffer,512)) { ShowRequest("An error occured while opening file \"%s\":%s","Continue",LastFileName,DummyBuffer); goto Start; } else { DisplayBeep(Window -> WScreen); return; } } } /* In which mode are we to write the name list? */ switch(Mode) { /* Write full names only. */ case MEN_FULL: for(i = 0 ; i < NumNames ; i++) { /* Write the full file name. */ if(FPrintf(File,"%s\n",NameList[i] -> Name) < 1) { Error = IoErr(); if(Fault(Error,"",DummyBuffer,512)) { if(!ShowRequest("An error occured while writing to file \"%s\":%s","Continue|Abort",LastFileName,DummyBuffer)) break; } else { DisplayBeep(Window -> WScreen); break; } } } break; /* Write the base file names only. */ case MEN_FILE: for(i = 0 ; i < NumNames ; i++) { /* Write the base file name. */ if(FPrintf(File,"%s\n",NameList[i] -> NamePart) < 1) { Error = IoErr(); if(Fault(Error,"",DummyBuffer,512)) { if(!ShowRequest("An error occured while writing to file \"%s\":%s","Continue|Abort",LastFileName,DummyBuffer)) break; } else { DisplayBeep(Window -> WScreen); break; } } } break; /* Write it in `List' style format, set up the * formatting string. */ case MEN_LIST: SPrintf(MaxNameFormat,"%%-%ld%s %%8s %%-8s %%-8s %%-8s\n",(MaxNameLen < 25) ? 25 : MaxNameLen + 1,"s"); /* Run down the list of names. */ for(i = 0 ; i < NumNames ; i++) { /* Add the number of blocks and bytes for * the current file. */ NumBytes += NameList[i] -> Size; NumBlocks += NameList[i] -> Blocks; /* Write the data. */ if((Written = ListName(File,i)) < 1) { Error = IoErr(); if(Fault(Error,"",DummyBuffer,512)) { if(!ShowRequest("An error occured while writing to file \"%s\":%s","Continue|Abort",LastFileName,DummyBuffer)) break; } else { DisplayBeep(Window -> WScreen); break; } } } /* Add the number of files if possible. */ if(NumFiles && Written > 0) Written = FPrintf(File,"%ld %s - ",NumFiles,(NumFiles > 1) ? "files" : "file"); /* Add the number of directories if possible. */ if(NumDirs && Written > 0) Written = FPrintf(File,"%ld %s - ",NumDirs,(NumDirs > 1) ? "directories" : "directory"); /* Add the number of links if possible. */ if(NumLinks && Written > 0) Written = FPrintf(File,"%ld %s - ",NumLinks,(NumLinks > 1) ? "links" : "link"); /* Add the number of blocks and bytes. */ if(Written > 0) FPrintf(File,"%ld blocks - %ld bytes\n",NumBlocks,NumBytes); break; } /* Close the file we opened. */ Close(File); /* Take a look at the file we dealt with. */ if(FileLock = Lock(FullFileName,ACCESS_READ)) { struct FileInfoBlock __aligned FileInfo; /* Examine the file... */ if(Examine(FileLock,&FileInfo)) { /* Did it remain empty? */ if(!FileInfo . fib_Size) { /* Ask the user what to do with it. */ if(ShowRequest("Do you wish the incomplete file \"%s\"\nto be removed?","Yes|No",LastFileName)) { /* Free the filelock referring to it. */ UnLock(FileLock); FileLock = NULL; /* Delete the file. */ DeleteFile(FullFileName); } } } /* Free the filelock if still available. */ if(FileLock) UnLock(FileLock); } } } } } /* FindServer(): * * The `find' main program, implemented as a subprocess to allow us to * specify the stack size to use. */ VOID __saveds FindServer() { struct IntuiMessage *Massage; ULONG Class,Code,Qualifier,Mask; WORD MouseX,MouseY; struct Gadget *Gadget; /* Reset flags. */ DoIconify = FALSE; Terminated = FALSE; /* Set up the commodities.library interface. */ SetupCx(); /* Look what to do next, are we to start up in iconified state * or are we to open the control panel? */ if(SelectWhich == GAD_NONE_ICONIFY) Iconify(TRUE); else { /* Open the control panel. */ if(OpenGfx()) { /* Are we to activate any string gadget? */ if(SelectWhich != GAD_NONE) ActivateGadget(LastActiveGadget = GadgetArray[SelectWhich],Window,NULL); } } /* Process the messages. */ while(Window && !Terminated) { /* Wait for a couple of messages. */ Mask = Wait(SIG_WORKBENCH | SIG_WINDOW | SIG_CX | SIG_KILL); /* Did we get a Workbench message? */ if(Mask & SIG_WORKBENCH) { struct AppMessage *AppMessage; BYTE GotName = FALSE; /* Process all application messages. */ while(AppMessage = (struct AppMessage *)GetMsg(WorkbenchPort)) { /* Did we get a new name already? */ if(!GotName) { LONG i; /* Run down the list of arguments. */ for(i = 0 ; i < AppMessage -> am_NumArgs ; i++) { /* Does the argument sport a filelock? */ if(AppMessage -> am_ArgList[i] . wa_Lock) { /* Try to turn the filelock into a name. */ if(NameFromLock(AppMessage -> am_ArgList[i] . wa_Lock,AreaName,256)) { struct FileInfoBlock __aligned FileInfo; /* Take a look at the object referenced * by the filelock. */ if(Examine(AppMessage -> am_ArgList[i] . wa_Lock,&FileInfo)) { /* Does the filelock refer to * a file instead of a directory? */ if(FileInfo . fib_DirEntryType < 0) { UBYTE *Stop; /* Look for the path name part. */ Stop = PathPart(AreaName); /* Cut off the file name. */ *Stop = 0; /* Now we've got a name to work with. */ GotName = TRUE; break; } else GotName = TRUE; } else AreaName[0] = 0; } else AreaName[0] = 0; } } } /* Reply the application message. */ ReplyMsg(AppMessage); } /* Did we get a name to work with? */ if(GotName) { /* Set the area name string accordingly. */ GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHAREA],Window,NULL, GTST_String, AreaName, TAG_DONE); /* The user will probably want to change * the name to search for as he already * has given a new area to search by * dropping an icon on the window. */ LastActiveGadget = GadgetArray[GAD_SEARCHFOR]; /* If the pattern gadget still contains * no text, activate the window which * will also activate the pattern gadget. */ if(!(GT_STRING(GadgetArray[GAD_SEARCHFOR]))[0]) ActivateWindow(Window); } } /* Did we get a window message? */ if(Mask & SIG_WINDOW) { /* Process all messages. */ while(Window && !Terminated && (Massage = (struct IntuiMessage *)GT_GetIMsg(Window -> UserPort))) { /* Extract the data we will need. */ Class = Massage -> Class; Code = Massage -> Code; Qualifier = Massage -> Qualifier; Gadget = (struct Gadget *)Massage -> IAddress; MouseX = Massage -> MouseX; MouseY = Massage -> MouseY; /* Reply the message. */ GT_ReplyIMsg(Massage); /* Refresh the window contents. */ if(Class == IDCMP_REFRESHWINDOW) RefreshGfx(); /* Activate a string gadget. */ if(Class == IDCMP_ACTIVEWINDOW && LastActiveGadget) ActivateGadget(LastActiveGadget,Window,NULL); /* Process a cursor keypress. */ if(Class == IDCMP_RAWKEY) { switch(Code) { case CURSORUP: if(Qualifier & (IEQUALIFIER_LALT|IEQUALIFIER_RALT)) { if(NumNames > 0 && LastSelected == -1) LastSelected = NumNames; if(LastSelected > 0) { BYTE Selected; if(LastSelected < NumNames) { Selected = NameList[LastSelected] -> Selected; NameList[LastSelected] -> Selected = FALSE; } else Selected = TRUE; if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) { if(LastSelected > 5) LastSelected -= 5; else LastSelected = 0; } else { if(Qualifier & IEQUALIFIER_CONTROL) LastSelected = 0; else LastSelected--; } if(LastSelected < ListTop) ListTop = LastSelected; if(ListTop + 5 <= LastSelected) ListTop = LastSelected - 4; GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, ListTop, TAG_DONE); NameList[LastSelected] -> Selected = Selected; RefreshList(); RefreshFile(); } } else { if(ListTop) { if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) { if(ListTop > 5) ListTop -= 5; else ListTop = 0; } else { if(Qualifier & IEQUALIFIER_CONTROL) ListTop = 0; else ListTop--; } GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, ListTop, TAG_DONE); RefreshList(); } } break; case CURSORDOWN:if(Qualifier & (IEQUALIFIER_LALT|IEQUALIFIER_RALT)) { if(NumNames > 0 && LastSelected == -1) { LastSelected = 0; if(LastSelected < ListTop) ListTop = LastSelected; if(ListTop + 5 <= LastSelected) ListTop = LastSelected - 4; GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, ListTop, TAG_DONE); NameList[LastSelected] -> Selected = TRUE; RefreshList(); RefreshFile(); } else { if(LastSelected != -1 && LastSelected < NumNames - 1) { BYTE Selected = NameList[LastSelected] -> Selected; NameList[LastSelected] -> Selected = FALSE; if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) { if(LastSelected + 5 < NumNames - 5) LastSelected += 5; else { if(NumNames >= 5) LastSelected = NumNames - 5; else { if(NumNames) LastSelected = NumNames - 1; else LastSelected = NumNames; } } } else { if(Qualifier & IEQUALIFIER_CONTROL) { if(NumNames >= 5) LastSelected = NumNames - 5; else { if(NumNames) LastSelected = NumNames - 1; else LastSelected = NumNames; } } else LastSelected++; } if(LastSelected < ListTop) ListTop = LastSelected; if(ListTop + 5 <= LastSelected) ListTop = LastSelected - 4; GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, ListTop, TAG_DONE); NameList[LastSelected] -> Selected = Selected; RefreshList(); RefreshFile(); } } } else { if(ListTop < NumNames - 5) { if(Qualifier & (IEQUALIFIER_LSHIFT|IEQUALIFIER_RSHIFT)) { if(ListTop + 5 < NumNames - 5) ListTop += 5; else ListTop = NumNames - 5; } else { if(Qualifier & IEQUALIFIER_CONTROL) ListTop = NumNames - 5; else ListTop++; } GT_SetGadgetAttrs(GadgetArray[GAD_SCROLLER],Window,NULL, GTSC_Top, ListTop, TAG_DONE); RefreshList(); } } break; default: break; } } /* Did the user move the scroller at the * right hand side of the main display area? */ if(Class == IDCMP_MOUSEMOVE) { switch(Gadget -> GadgetID) { case GAD_SCROLLER: ListTop = Code; RefreshList(); break; default: break; } } /* Did the user press a gadget? */ if(Class == IDCMP_GADGETUP) { switch(Gadget -> GadgetID) { /* The return or tab key was pressed * while the cursor was inside the * `Search Area' gadget. */ case GAD_SEARCHAREA: ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHFOR],Window,NULL); break; /* If the tab key was pressed while the * cursor was inside the `Search For' * gadget, the message code will reflect * it. In any other case, the return * key must have been pressed. */ case GAD_SEARCHFOR: if(Code == '\t') LastActiveGadget = GadgetArray[GAD_SEARCHAREA]; else LastActiveGadget = NULL; break; /* The user clicked the scroller * at the right hand side of * the main display area. */ case GAD_SCROLLER: ListTop = Code; RefreshList(); break; /* The user started the search * process. */ case GAD_START: FindFile(); break; default: break; } } /* The user pressed a mouse button. */ if(Class == IDCMP_MOUSEBUTTONS) { if(Code == SELECTDOWN) { LastActiveGadget = NULL; /* Was the mouse within the `natural' * borders of the main display area? */ if(MouseX >= 14 && MouseX <= ListRightColumn && MouseY > ListTopLine + 1 && MouseY < ListTopLine + 2 + 10 * SystemFontHeight) { WORD Line = (MouseY - ListTopLine - 2) / (SystemFontHeight * 2); /* Does the line selected * cover the existing list * entries? */ if(ListTop + Line < NumNames) { /* Clear previous selection. */ if(LastSelected != -1) NameList[LastSelected] -> Selected = FALSE; /* Make new selection. */ LastSelected = ListTop + Line; /* Set the selection flag. */ NameList[LastSelected] -> Selected = TRUE; /* Redraw the name list. */ RefreshList(); /* Show the file information. */ RefreshFile(); } } } } /* Are we to close the window? */ if(Class == IDCMP_CLOSEWINDOW) { /* If we had just returned from * iconified state, return to it. */ if(WasIconified) DoIconify = TRUE; else Terminated = TRUE; break; } /* The user pressed a non-cursor key. */ if(Class == IDCMP_VANILLAKEY) { /* Convert the key code to upper case. */ switch(ToUpper((UBYTE)Code)) { /* Activate the `Search Area' string gadget. */ case 'A': ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHAREA],Window,NULL); break; /* Activate the `Search For' string gadget. */ case 'F': ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHFOR],Window,NULL); break; /* Toggle the state of the `Wildcards' button. */ case 'W': GT_SetGadgetAttrs(GadgetArray[GAD_WILDCARDS],Window,NULL, GTCB_Checked, !GT_CHECKED(GadgetArray[GAD_WILDCARDS]), TAG_DONE); break; /* Start the search process. */ case 'S': case '\r': FindFile(); break; /* Terminate the program or * return to iconified state, * similar to the IDCMP_CLOSEWINDOW * message. */ case 'Q': case '\33': if(WasIconified) DoIconify = TRUE; else Terminated = TRUE; break; default: break; } } /* A menu item has been selected. */ if(Class == IDCMP_MENUPICK) { struct MenuItem *Item; /* Process all menu items selected. */ while(Code != MENUNULL) { /* Query the menu item selected. */ if(Item = ItemAddress(FindMenu,Code)) { /* Take a look at the menu item selected. */ switch((LONG)GTMENUITEM_USERDATA(Item)) { /* The file name list is to be saved. */ case MEN_FULL: case MEN_FILE: case MEN_LIST: DisableWindow(TRUE); SaveList((LONG)GTMENUITEM_USERDATA(Item)); EnableWindow(); break; /* Show the `About...' requester. */ case MEN_ABOUT: DisableWindow(TRUE); ShowRequest(" Find Files v1.7\nWritten by Olaf Barthel\n © 1991-92 by MXM\n All Rights Reserved","Continue"); EnableWindow(); break; /* Terminate the program. */ case MEN_QUIT: Terminated = TRUE; break; /* Copy the full path name of the currently * selected file to the clipboard. */ case MEN_COPY: if(LastSelected != -1 && LastSelected < NumNames) { if(NameList[LastSelected] -> Selected) SaveClip(NameList[LastSelected] -> Name,strlen(NameList[LastSelected] -> Name)); } break; /* Use a file requester to select the search area. */ case MEN_SELECTAREA: DisableWindow(TRUE); /* Save the current contents of the `Search Area' gadget. */ strcpy(AreaName,GT_STRING(GadgetArray[GAD_SEARCHAREA])); /* Select a new directory... */ if(SelectSearchArea()) { /* Set the new name. */ GT_SetGadgetAttrs(GadgetArray[GAD_SEARCHAREA],Window,NULL, GTST_String, AreaName, TAG_DONE); /* The user may want to change the search pattern. */ ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHFOR],Window,NULL); } else { /* Determine which string gadget to activate. */ if(!(GT_STRING(GadgetArray[GAD_SEARCHAREA]))[0]) ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHAREA],Window,NULL); else { if(!(GT_STRING(GadgetArray[GAD_SEARCHFOR]))[0]) ActivateGadget(LastActiveGadget = GadgetArray[GAD_SEARCHFOR],Window,NULL); } } EnableWindow(); break; /* Iconify the program. */ case MEN_ICONIFY: DoIconify = TRUE; break; default: break; } /* Proceed to the next menu item selected. */ Code = Item -> NextSelect; } else break; } /* If a string gadget had been activated * before the menu selection was processed, * reactivate it. */ if(LastActiveGadget) ActivateGadget(LastActiveGadget,Window,NULL); } } /* Are we to iconify the window? */ if(DoIconify) { Iconify(TRUE); DoIconify = FALSE; } } /* Did we get a commodities toolkit message? */ if(Mask & SIG_CX) { CxMsg *Message; /* Process all messages. */ while(Message = (CxMsg *)GetMsg(CxPort)) HandleCxMsg(Message); /* Are we to iconify the window? */ if(DoIconify) { /* Try to put an icon on the Workbench main window. */ if(!Iconify(FALSE)) { /* It didn't seem to work, * try to shrink the window * then. */ Forbid(); if(Window -> Width == WindowWidth) { Permit(); ZipWindow(Window); } else Permit(); } DoIconify = FALSE; } } /* Did we receive a termination signal? */ if(Mask & SIG_KILL) Terminated = TRUE; } /* Close the control panel. */ CloseGfx(); /* Shut down the commodities toolkit interface. */ ShutdownCx(); /* Lock the system... */ Forbid(); /* ...and wave goodbye. */ Signal(MainProcess,SIG_REPLY); } /* main(int argc,char **argv): * * The classical main program. */ VOID __stdargs main(int argc,char **argv) { /* Are we running under control of Kickstart 2.0 or higher? */ if(SysBase -> LibNode . lib_Version < 37) exit(20); /* Look who we are. */ MainProcess = (struct Process *)SysBase -> ThisTask; /* Were we started from Shell? */ if(argc) { UBYTE **ArgArray; /* Allocate space for six arguments. */ if(ArgArray = (UBYTE **)AllocVec(sizeof(UBYTE *) * 6,MEMF_CLEAR)) { struct RDArgs *ArgsPtr; /* Read the arguments... */ if(ArgsPtr = ReadArgs("Area,Pattern,N=NoWildcards/S,K=CX_POPKEY/K,P=CX_PRIORITY/K/N,U=CX_POPUP/K",(LONG *)ArgArray,NULL)) { /* Did the user specify a search area to be used? */ if(ArgArray[ARG_AREA]) { /* Is the path name valid? */ if(ArgArray[ARG_AREA][0]) { strcpy(AreaName,ArgArray[ARG_AREA]); SelectWhich = GAD_SEARCHFOR; } else { /* Take the current directory name instead. */ if(NameFromLock(MainProcess -> pr_CurrentDir,AreaName,256)) SelectWhich = GAD_SEARCHFOR; else AreaName[0] = 0; } } /* Did the user specify a pattern to be used? */ if(ArgArray[ARG_PATTERN]) { /* Copy the pattern. */ strcpy(SearchString,ArgArray[ARG_PATTERN]); /* Are we to select a string gadget * or do we already have enough * data to work with? */ if(ArgArray[ARG_AREA] && AreaName[0]) SelectWhich = GAD_NONE; } /* Are wildcard patterns to be used? */ if(ArgArray[ARG_NOWILDCARDS]) UseWildcards = FALSE; /* Did the user specify a commodities * toolkit hotkey? */ if(ArgArray[ARG_POPKEY]) strcpy(HotkeyBuffer,ArgArray[ARG_POPKEY]); /* Did the user specify a commodities toolkit * broker priority? */ if(ArgArray[ARG_PRI]) CxPriority = *((LONG *)ArgArray[ARG_PRI]); /* Did the user want the program to come * up in iconified state. */ if(ArgArray[ARG_POPUP]) { if(!Stricmp(ArgArray[ARG_POPUP],"no")) SelectWhich = GAD_NONE_ICONIFY; } /* Free the argument data. */ FreeArgs(ArgsPtr); } else { LONG Error = IoErr(); /* Complain about the error. */ PrintFault(Error,"Find"); /* Free the argument array. */ FreeVec(ArgArray); /* Remember the error code. */ SetIoErr(Error); /* Terminate with failure code. */ exit(RETURN_FAIL); } /* Free the argument array. */ FreeVec(ArgArray); } /* Get the program running. */ OpenAll(); } else { struct DiskObject *Icon; /* Allocate all resources we need. */ OpenAll(); /* Parse the tooltypes for use with the commodities * toolkit interface. */ if(CxBase) { ToolTypes = ArgArrayInit(argc,argv); if(!Stricmp(ArgString(ToolTypes,"CX_POPUP","yes"),"no")) SelectWhich = GAD_NONE_ICONIFY; } /* Did we get any arguments passed in? */ if(WBenchMsg -> sm_NumArgs > 1) { LONG i; /* Run down the list of arguments. */ for(i = 1 ; i < WBenchMsg -> sm_NumArgs ; i++) { /* Does the argument have a filelock attached? */ if(WBenchMsg -> sm_ArgList[i] . wa_Lock) { /* Turn the filelock into a file name. */ if(NameFromLock(WBenchMsg -> sm_ArgList[i] . wa_Lock,AreaName,256)) { struct FileInfoBlock __aligned FileInfo; /* Examine object referenced by * the filelock... */ if(Examine(WBenchMsg -> sm_ArgList[i] . wa_Lock,&FileInfo)) { /* Does the name refer * to a file instead of * a directory? */ if(FileInfo . fib_DirEntryType < 0) { UBYTE *Stop; /* Determine the path part. */ Stop = PathPart(AreaName); /* Cut off the file name. */ *Stop = 0; } /* Determine the gadget to activate * when opening the control panel. */ if(SelectWhich != GAD_NONE_ICONIFY) SelectWhich = GAD_SEARCHFOR; break; } } } } } /* Try to read the icon for our program. */ if(Icon = GetDiskObject(WBenchMsg -> sm_ArgList[0] . wa_Name)) { /* If the `ICONIFY' tooltype is present, * come up in iconified state. */ if(FindToolType(Icon -> do_ToolTypes,"ICONIFY")) SelectWhich = GAD_NONE_ICONIFY; /* Release the icon data. */ FreeDiskObject(Icon); } } /* Create the actual find process. */ if(FindProcess = CreateNewProcTags( NP_Entry, FindServer, NP_StackSize, 20000, NP_Name, "Find Server", TAG_DONE)) { FOREVER { /* Wait for termination or reply signal. */ ULONG Mask = Wait(SIG_REPLY | SIG_KILL); /* Abort if the reply signal comes in and * flag the find process to terminate if * the termination signal arrives. */ if(Mask & SIG_REPLY) break; else Signal(FindProcess,SIG_KILL); } } /* That's all folks. */ CloseAll(RETURN_OK); }