/*
**	UpdateIcon - Icon control utility
**
**	© Copyright 1992 by Olaf `Olsen' Barthel
**		All Rights Reserved
**
**	Public-domain, both commercial and noncommercial use
**	of this program are permitted.
*/

	/* System includes. */

#include <workbench/workbench.h>
#include <exec/execbase.h>
#include <dos/dosextens.h>
#include <exec/memory.h>
#include <dos/dosasl.h>

	/* Library prototypes. */

#include <clib/utility_protos.h>
#include <clib/exec_protos.h>
#include <clib/icon_protos.h>
#include <clib/dos_protos.h>

	/* Argument vector offsets. */

enum	{	ARG_NAME,ARG_ADD,ARG_UPDATE,ARG_REPLACE,ARG_DEFAULTOOL,ARGCOUNT };

	/* Version tag identifier. */

STATIC UBYTE *Version = "\0$VER: UpdateIcon 1.0 (18.4.92)";

	/* Shared library identifiers. */

struct ExecBase		*SysBase;
struct DosLibrary	*DOSBase;
struct Library		*IconBase;
struct Library		*UtilityBase;

	/* Main():
	 *
	 *	The one and only main routine.
	 */

LONG __saveds
Main()
{
	struct Process	*ThisProcess;
	LONG		 Result = RETURN_FAIL;

		/* Set up ExecBase pointer. */

	SysBase = *(struct ExecBase **)4;

		/* Obtain current process identifier. */

	ThisProcess = (struct Process *)SysBase -> ThisTask;

		/* Did we get started from Shell? */

	if(ThisProcess -> pr_CLI)
	{
			/* Open dos.library */

		if(DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",37))
		{
				/* Open icon.library */

			if(IconBase = OpenLibrary("icon.library",37))
			{
					/* Open utility.library */

				if(UtilityBase = OpenLibrary("utility.library",37))
				{
					struct AnchorPath *Anchor;

						/* Allocate pattern matching data. */

					if(Anchor = (struct AnchorPath *)AllocVec(sizeof(struct AnchorPath) + 256,MEMF_ANY | MEMF_CLEAR))
					{
						STRPTR *Args;

							/* Allocate argument vector. */

						if(Args = (STRPTR)AllocVec(sizeof(STRPTR) * ARGCOUNT,MEMF_ANY | MEMF_CLEAR))
						{
							struct RDArgs *ArgsPtr;

								/* Allocate argument parser data. */

							if(ArgsPtr = (struct RDArgs *)AllocDosObjectTags(DOS_RDARGS,TAG_DONE))
							{
									/* Provide extra help infocmation. */

								ArgsPtr -> RDA_ExtHelp = "\nUsage: UpdateIcon <Name pattern> [Add] [Update]\n\
                  [Replace <Tool name to replace>] [DefaultTool <Name>]\n\n\
                          `Add' adds  an  icon  to a file which does not yet\n\
                                have an icon attached.\n\n\
                       `Update' updates the position of an icon.\n\n\
                      `Replace' replaces the default tool name of an icon by\n\
                                the name specified using `DefaultTool'.\n\n\
                  `DefaultTool' can be used in conjunction with `Replace' or\n\
                                alone  by  itself.   In the latter case, any\n\
                                icon  in question will have the default tool\n\
                                set to this name.\n";

									/* Allow the pattern matching process to
									 * be aborted by pressing ^C.
									 */
	
								Anchor -> ap_BreakBits	= SIGBREAKF_CTRL_C;
								Anchor -> ap_Strlen	= 256;
	
									/* Read the command arguments. */
	
								if(ReadArgs("NAME,A=ADD/S,U=UPDATE/S,R=REPLACE/K,T=DEFAULTTOOL/K",(LONG *)Args,ArgsPtr))
								{
										/* Did we get a name pattern? */
	
									if(Args[ARG_NAME])
									{
										struct DiskObject	*Icon		= NULL;
										BYTE			 Continue	= TRUE,
													 Match		= FALSE;
										WORD			 Len;
	
											/* Look for the first matching file name. */
	
										if(!MatchFirst(Args[ARG_NAME],Anchor))
										{
											STRPTR Name = Anchor -> ap_Buf;
	
												/* So far, we have been pretty successful. */
	
											Result	= RETURN_OK;
	
												/* At least a single match has been made. */
	
											Match	= TRUE;
	
												/* Scan until no matches remain. */
	
											for(;;)
											{
												Len = strlen(Name);
	
													/* Is the name likely to
													 * have `.info' appended?
													 */
	
												if(Len > 5)
												{
														/* Check for `.info' suffix,
														 * we don't wish to attach
														 * icons to icon files.
														 */
	
													if(!Stricmp(&Name[Len - 5],".info"))
													{
															/* Look for the next matching file. */
	
														if(MatchNext(Anchor))
														{
															LONG Error = IoErr();
	
															if(Error != ERROR_NO_MORE_ENTRIES)
																PrintFault(Error,"UpdateIcon");
	
															break;
														}
	
														continue;
													}
												}
	
													/* Did we get a proper name? */
	
												if(Name[0])
												{
														/* Are we to add icons to files
														 * which do not yet have an icon
														 * attached?
														 */
	
													if(Args[ARG_ADD])
													{
															/* Try to read the icon file if any. */
	
														if(!(Icon = GetDiskObject(Name)))
														{
																/* No icon file present,
																 * try to obtain a default
																 * icon image.
																 */
	
															if(Icon = GetDiskObjectNew(Name))
															{
																	/* No fixed position for the
																	 * new icon, please.
																	 */
	
																Icon -> do_CurrentX = NO_ICON_POSITION;
																Icon -> do_CurrentY = NO_ICON_POSITION;
	
																	/* The icon file will be saved only
																	 * if there are no other actions
																	 * to execute using the icon data.
																	 */
	
																if(!Args[ARG_UPDATE] && !Args[ARG_REPLACE] && !Args[ARG_DEFAULTOOL])
																{
																		/* Try to save the new icon
																		 * to disk...
																		 */
	
																	if(!PutDiskObject(Name,Icon))
																	{
																		Printf("UpdateIcon: Could not save icon for \"%s\"!\a\n",Name);
	
																		Continue = FALSE;
																	}
	
																		/* Free the icon data. */
	
																	FreeDiskObject(Icon);
	
																	Icon = NULL;
																}
															}
															else
															{
																Printf("UpdateIcon: Could not get icon for \"%s\"!\a\n",Name);
	
																Continue = FALSE;
															}
														}
														else
														{
																/* The file already has a proper icon
																 * attached. If not to be used later,
																 * free it.
																 */
	
															if(!Args[ARG_UPDATE] && !Args[ARG_REPLACE] && !Args[ARG_DEFAULTOOL])
															{
																FreeDiskObject(Icon);
	
																Icon = NULL;
															}
														}
													}
	
														/* Are we to update the icon
														 * position?
														 */
	
													if(Args[ARG_UPDATE] && Continue)
													{
															/* Do we already have an
															 * icon to work upon?
															 */
	
														if(!Icon)
														{
																/* Try to read the icon. */
	
															if(!(Icon = GetDiskObject(Name)))
															{
																Printf("UpdateIcon: Could not get icon for \"%s\"!\a\n",Name);
	
																Continue = FALSE;
															}
														}
	
															/* Reset the icon position. */
	
														if(Icon)
														{
															Icon -> do_CurrentX = NO_ICON_POSITION;
															Icon -> do_CurrentY = NO_ICON_POSITION;
														}
													}
	
														/* Are we to replace the default
														 * tool of an icon with a different
														 * tool name?
														 */
	
													if(Args[ARG_REPLACE] && !Continue)
													{
															/* Did the user give a
															 * proper replacement
															 * tool name?
															 */
	
														if(!Args[ARG_DEFAULTOOL])
														{
															PrintFault(ERROR_REQUIRED_ARG_MISSING,"UpdateIcon");
	
															Result = RETURN_ERROR;
	
															Continue = FALSE;
														}
														else
														{
																/* Do we already have an
																 * icon to play with?
																 */
	
															if(!Icon)
															{
																if(!(Icon = GetDiskObject(Name)))
																{
																	Printf("UpdateIcon: Could not get icon for \"%s\"!\a\n",Name);
	
																	Continue = FALSE;
																}
															}
	
															if(Icon)
															{
																	/* Does this icon have
																	 * a default tool?
																	 */
	
																if(Icon -> do_DefaultTool)
																{
																		/* If the tool name matches the one
																		 * we are to replace, replace it
																		 * with the new name.
																		 */
	
																	if(!Stricmp(Icon -> do_DefaultTool,Args[ARG_REPLACE]))
																		Icon -> do_DefaultTool = (char *)Args[ARG_DEFAULTOOL];
																}
															}
														}
													}
													else
													{
															/* Are we to supply a new default tool
															 * for an existing icon?
															 */
	
														if(Args[ARG_DEFAULTOOL] && Continue)
														{
																/* Do we already have an
																 * icon to work upon?
																 */
	
															if(!Icon)
															{
																if(!(Icon = GetDiskObject(Name)))
																{
																	Printf("UpdateIcon: Could not get icon for \"%s\"!\a\n",Name);
	
																	Continue = FALSE;
																}
															}
	
																/* Supply the new default tool name. */
	
															if(Icon)
																Icon -> do_DefaultTool = (char *)Args[ARG_DEFAULTOOL];
														}
													}
	
														/* That's all folks:
														 * save the icon back to
														 * disk.
														 */
	
													if(Icon)
													{
															/* Try to save the icon... */
	
														if(!PutDiskObject(Name,Icon))
														{
															Printf("UpdateIcon: Could not save icon for \"%s\"!\a\n",Name);
	
															Continue = FALSE;
														}
														else
															Result = RETURN_OK;
	                                                                                                            
															/* Release the icon data. */
	
														FreeDiskObject(Icon);
	
														Icon = NULL;
													}
	                                                                                                 
														/* Did we get an error? */
	
													if(!Continue)
													{
														Result = RETURN_FAIL;
	
														break;
													}
												}
	
													/* Look for the next matching name. */
	
												if(MatchNext(Anchor))
												{
													LONG Error = IoErr();
	
													if(Error != ERROR_NO_MORE_ENTRIES)
														PrintFault(Error,"UpdateIcon");
	
													break;
												}
											}
										}
	
											/* If no match has been
											 * made, tell it to the
											 * user.
											 */
	
										if(!Match)
										{
											Printf("UpdateIcon: No applicable objects.\n");
	
											Result = RETURN_WARN;
										}
	
											/* Free pattern matching info. */
	
										MatchEnd(Anchor);
									}
									else
									{
										PrintFault(ERROR_REQUIRED_ARG_MISSING,"UpdateIcon");
	
										Result = RETURN_ERROR;
									}
								}
								else
								{
									PrintFault(IoErr(),"UpdateIcon");
	
									Result = RETURN_ERROR;
								}
	
									/* Free argument data. */
	
								FreeArgs(ArgsPtr);
							}
							else
								Printf("UpdateIcon: Could not allocate argument data!\a\n");

							/* Free argument vector data. */
	
							FreeVec(Args);
						}
						else
							Printf("UpdateIcon: Could not allocate argument data!\a\n");

							/* Free pattern matching data. */

						FreeVec(Anchor);
					}
					else
						Printf("UpdateIcon: Could not allocate AnchorPath!\a\n","icon.library");

						/* Close the remaining libraries... */

					CloseLibrary(UtilityBase);
				}
				else
					Printf("UpdateIcon: Could not open \"%s\"!\a\n","utility.library");

				CloseLibrary(IconBase);
			}
			else
				Printf("UpdateIcon: Could not open \"%s\"!\a\n","icon.library");

			CloseLibrary(DOSBase);
		}
	}
	else
	{
			/* Wait for startup message... */

		WaitPort(&ThisProcess -> pr_MsgPort);

			/* Disable multitasking. */

		Forbid();

			/* Reply startup message. */

		ReplyMsg(GetMsg(&ThisProcess -> pr_MsgPort));
	}

	return(Result);
}
