/* CompactPlayer CD title editor, based on EnvEdit */

#include <exec/types.h>
#include <exec/memory.h>
#include <dos/exall.h>
#include <intuition/intuition.h>
#include <intuition/gadgetclass.h>
#include <intuition/imageclass.h>
#include <intuition/icclass.h>
#include <utility/tagitem.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/icon.h>
#include <proto/intuition.h>
#include <classact.h>
#include <strings.h>
#include <stdio.h>
#include <stdlib.h>

/* #define D(x) x to compile with debugging output.
 */
#define D(x)

#ifdef _DCC
#define SAVEDS __geta4
#define ASM
#define REG_A0 __A0
#define REG_A1 __A1
#else
#define SAVEDS __saveds
#define ASM __asm
#define REG_A0 register __a0
#define REG_A1 register __a1
#endif

enum { GAD_LIST = 1, GAD_EDIT, GAD_SAVE, GAD_DEL, GAD_CANCEL };

/* ARexx command IDs
 */
enum { REXX_NAME, REXX_VERSION, REXX_AUTHOR, REXX_ACTIVATE, REXX_DEACTIVATE,
		REXX_QUIT, REXX_WINDOWTOBACK, REXX_WINDOWTOFRONT };



/* Some additional info we put in listbrowser node userdata field.
 */
struct LBUserData
{
	UBYTE lbud_FileName[255];
	BOOL lbud_Changed;
	BOOL lbud_Deleted;
	STRPTR lbud_Buf;
	ULONG lbud_BufSize;
};


/* Function prototypes.
 */
VOID load_text(struct Window *);
LONG file_size(char *);
VOID save_changed(struct List *, BOOL);
BOOL read_files(struct List *, STRPTR, WORD);
VOID bstrcpy(STRPTR, BSTR);
VOID free_list(struct List *);
LONG easy_req(struct Window *, char *, char *, char *, ...);
VOID ASM rexx_name(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_version(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_author(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_activate(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_deactivate(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_quit(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_about(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_windowtoback(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);
VOID ASM rexx_windowtofront(REG_A0 struct ARexxCmd *, REG_A1 struct RexxMsg *);

/* Global variables.
 */
struct List file_list;
struct Gadget *layout, *list_gad, *edit_gad;
struct DrawInfo *drinfo;
Object *window_obj;
struct Window *win;
BOOL ok = TRUE;

struct ColumnInfo ci[] =
{
	{ 40, "Artist", 0 },
	{ 40, "Record", 0 },
	{ 20, "ID", 0 },
	{ -1, (STRPTR)~0, -1 }
};

/* ARexx command table.  These commands may not seem terribly useful at first,
 * but these are a basic set of commands that every app should support.
 */
struct ARexxCmd arexx_cmds[] =
{
	{ "NAME",			REXX_NAME,			rexx_name,			NULL,		NULL, },
	{ "VERSION",		REXX_VERSION,		rexx_version,		NULL,		NULL, },
	{ "AUTHOR",			REXX_AUTHOR,		rexx_author,		NULL,		NULL, },
	{ "ACTIVATE",		REXX_ACTIVATE,		rexx_activate,		NULL,		NULL, },
	{ "DEACTIVATE",		REXX_DEACTIVATE,	rexx_deactivate,	NULL,		NULL, },
	{ "QUIT",			REXX_QUIT,			rexx_quit,			NULL,		NULL, },
	{ "WINDOWTOBACK",	REXX_WINDOWTOBACK,	rexx_windowtoback,	NULL,		NULL, },
	{ "WINDOWTOFRONT",	REXX_WINDOWTOFRONT,	rexx_windowtofront,	NULL,		NULL, },
	{ NULL,				NULL,				NULL,				NULL,		NULL, }
};


/* This is the start of our programme.
 */
#ifdef _DCC
wbmain() { main(); }
#endif

int main(int ac, char **av)
{
	struct Screen *screen = NULL;

	if (!ButtonBase) return(20);

	/* We'll just open up on the default public screen, and use its screen font.
	 */
	if (screen = LockPubScreen(NULL))
	{
		UWORD mapping[4];

		drinfo = GetScreenDrawInfo(screen);

		NewList(&file_list);
		read_files(&file_list, ac > 1 ? av[1] : "Disks", 1);

		/* Setup a simple mapping.
		 */
		mapping[0] = drinfo->dri_Pens[BACKGROUNDPEN];
		mapping[1] = drinfo->dri_Pens[SHADOWPEN];
		mapping[2] = drinfo->dri_Pens[SHINEPEN];
		mapping[3] = drinfo->dri_Pens[FILLPEN];

		/* Do the layout.
		 */
		if (layout = LayoutObject,
							GA_DrawInfo, drinfo,
							ICA_TARGET, ICTARGET_IDCMP,
							LAYOUT_DeferLayout, TRUE,

							LAYOUT_SpaceOuter, TRUE,
							LAYOUT_Orientation, LAYOUT_ORIENT_VERT,
							LAYOUT_HorizAlignment, LAYOUT_ALIGN_CENTER,

							LAYOUT_AddChild, list_gad = ListBrowserObject,
								GA_ID, GAD_LIST,
								GA_RelVerify, TRUE,
								LISTBROWSER_Labels, (ULONG)&file_list,
								LISTBROWSER_ColumnInfo, (ULONG)&ci,
								LISTBROWSER_ColumnTitles, TRUE,
								LISTBROWSER_ShowSelected, TRUE,
								LISTBROWSER_Separators, FALSE,
								LISTBROWSER_Hierarchical, TRUE,
								LISTBROWSER_AutoFit, TRUE,
								ListBrowserEnd,
							CHILD_WeightedHeight, 100,

							LAYOUT_AddChild, edit_gad = TextFieldObject,
								GA_ID, GAD_EDIT,
								GA_RelVerify, TRUE,
								TEXTFIELD_Border, TEXTFIELD_BORDER_DOUBLEBEVEL,
								TextFieldEnd,
							CHILD_MinHeight, screen->Font->ta_YSize + 6,
							CHILD_WeightedHeight, 50,

							LAYOUT_AddChild, LayoutObject,
								LAYOUT_Orientation, LAYOUT_ORIENT_HORIZ,
								LAYOUT_EvenSize, TRUE,
	
								LAYOUT_AddChild, ButtonObject,
									GA_ID, GAD_SAVE,
									GA_Text, "_Save",
									GA_RelVerify, TRUE,
									ButtonEnd,
								CHILD_NominalSize, TRUE,
								CHILD_WeightedWidth, 0,

								LAYOUT_AddChild, ButtonObject,
									GA_ID, GAD_DEL,
									GA_Text, "_Delete",
									GA_RelVerify, TRUE,
									ButtonEnd,
								CHILD_NominalSize, TRUE,
								CHILD_WeightedWidth, 0,

								LAYOUT_AddChild, ButtonObject,
									GA_ID, GAD_CANCEL,
									GA_Text, " _Cancel ",
									GA_RelVerify, TRUE,
									ButtonEnd,
								CHILD_NominalSize, TRUE,
								CHILD_WeightedWidth, 0,

								LayoutEnd,
							CHILD_WeightedHeight, 0,
							LayoutEnd)
		{
			struct MsgPort *app_port;

			/* Create a message port for App* messages.  This is needed for
			 * iconification.  We're being a touch naughty by not checking
			 * the return code, but that just means that iconification won't
			 * work, nothing really bad will happen.
			 */
			app_port = CreateMsgPort();

			/* Create the window object.
			 */
			if (window_obj = WindowObject,
								WA_Left, 0,
								WA_Top, screen->Font->ta_YSize + 3,
								WA_CustomScreen, screen,
								WA_IDCMP, IDCMP_CLOSEWINDOW,
								WA_Flags, WFLG_DRAGBAR | WFLG_DEPTHGADGET | WFLG_CLOSEGADGET |
											WFLG_SIZEGADGET | WFLG_ACTIVATE | WFLG_SMART_REFRESH,
								WA_Title, "Environmental Variable Editor",
								WA_NewLookMenus, TRUE,
								WINDOW_ParentGroup, layout,
								WINDOW_IconifyGadget, TRUE,
								WINDOW_Icon, GetDiskObject("PROGDIR:EnvEdit"),
								WINDOW_IconTitle, "EnvEdit",
								WINDOW_AppPort, app_port,
								TAG_DONE))
			{
				/* Increase the initial hieght.
				 */
				SetAttrs(window_obj,
					WA_InnerHeight, screen->Font->ta_YSize * 15,
					TAG_DONE);

				/*  Open the window.
				 */
				if (win = (struct Window *)CA_OpenWindow(window_obj))
				{
					Object *arexx_obj;

					/* Create host object.
					 */
					if (arexx_obj = ARexxObject,
										AREXX_HostName, "INDEXEDIT",
										AREXX_Commands, arexx_cmds,
										End)
					{
						/* Input Event Loop
						 */
						while (ok)
						{
							ULONG signal, winsig, rxsig;
							ULONG result;
	
							/* Obtain the window and ARexx wait signal masks.
							 */
							GetAttr(WINDOW_SigMask, window_obj, &winsig);
							GetAttr(AREXX_SigMask, arexx_obj, &rxsig);		
	
							signal = Wait(rxsig | winsig | (1L << app_port->mp_SigBit) | SIGBREAKF_CTRL_C);
	
							/* ARexx event?
							 */
							if (signal & rxsig)
								CA_HandleRexx(arexx_obj);

							/* Window event?
							 */
							if (signal & winsig)
							{
								/* CA_HandleInput() returns the gadget ID of a clicked
								 * gadget, or one of several pre-defined values.  For
								 * this demo, we're only actually interested in a
								 * close window and a couple of gadget clicks.
								 */
								while ((result = CA_HandleInput(window_obj, NULL)) != WMHI_LASTMSG)
								{
									switch(result & WMHI_CLASSMASK)
									{
										case WMHI_CLOSEWINDOW:
											ok = FALSE;
											break;
		
										case WMHI_GADGETUP:
											switch (result & WMHI_GADGETMASK)
											{
												case GAD_LIST:
													D( PutStr("Load text\n"); )
													load_text(win);
													break;
		
												case GAD_EDIT:
													D( PutStr("Text edited\n"); )
													{
														struct Node *node;
		
														GetAttr(LISTBROWSER_SelectedNode, list_gad, (ULONG *)&node);
														if (node)
														{
															struct LBUserData *lbud;
															ULONG flags;
		
															/* Gotta change a flag in
															 * our special user data
															 * structure.
															 */
															GetListBrowserNodeAttrs(node,
																LBNA_Flags, &flags,
																LBNA_UserData, &lbud,
																TAG_DONE);
															if (lbud && !(flags & LBFLG_HASCHILDREN))
																lbud->lbud_Changed = TRUE;
														}
													}
													break;
		
												case GAD_SAVE:
													save_changed(&file_list, TRUE);
													ok = FALSE;
													break;
													
												case GAD_DEL:
													D( PutStr("Marking file as deleted\n"); )
													{
														struct Node *node;
		
														GetAttr(LISTBROWSER_SelectedNode, list_gad, (ULONG *)&node);
														if (node)
														{
															struct LBUserData *lbud;
															ULONG flags;
		
															SetGadgetAttrs(list_gad, win, NULL, LISTBROWSER_Labels, ~0, TAG_END);
															
															GetListBrowserNodeAttrs( node, LBNA_UserData, &lbud, LBNA_Flags, &flags, TAG_END);
															flags |= LBFLG_CUSTOMPENS;
															if (lbud)
																lbud->lbud_Deleted = TRUE;
															SetListBrowserNodeAttrs( node, LBNCA_FGPen, drinfo->dri_Pens[HIGHLIGHTTEXTPEN], LBNA_Flags, flags, TAG_END);
		
															if (SetGadgetAttrs(list_gad, win, NULL, LISTBROWSER_Labels, &file_list, LISTBROWSER_Selected, -1, TAG_END))
																RefreshGList(list_gad, win, NULL, 1);

															if (SetGadgetAttrs(edit_gad, win, NULL, TEXTFIELD_Text, "", TAG_END))
																RefreshGList(edit_gad, win, NULL, 1);
														}
													}
													break;
		
												case GAD_CANCEL:
													ok = FALSE;
													break;
		
												default:
													break;
											}
											break;
		
										case WMHI_ICONIFY:
											if (CA_Iconify(window_obj))
												win = NULL;
											break;
									 
										case WMHI_UNICONIFY:
											win = CA_OpenWindow(window_obj);
											break;
		
										default:
											break;
									}
								}
							}
							/* CTRL-C should quit.
							 */
							if (signal & SIGBREAKF_CTRL_C)
							{
								ok = FALSE;
							}
						}
						/* Free up ARexx.
						 */
						DisposeObject(arexx_obj);
					}
					else
						easy_req(NULL, "EnvEdit failed to start\nCouldn't create ARexx host", "Quit", "");
 				}
				else
					easy_req(NULL, "EnvEdit failed to start\nCouldn't open window", "Quit", "");

				/* Disposing of the window object will also close the
				 * window if it is already opened and it will dispose of
				 * all objects attached to it.
				 */
				DisposeObject(window_obj);
			}
			else
				easy_req(NULL, "EnvEdit failed to start\nCouldn't create window", "Quit", "");

			/* Lose the App* message port.
			 */
			if (app_port)
				DeleteMsgPort(app_port);
		}
		else
			easy_req(NULL, "EnvEdit failed to start\nCouldn't create layout", "Quit", "");

		free_list(&file_list);

		if (drinfo)
			FreeScreenDrawInfo(screen, drinfo);

	    UnlockPubScreen(0, screen);
	}
	else
		easy_req(NULL, "EnvEdit failed to start\nCouldn't lock destination screen", "Quit", "");

	exit(0);
}


/* Load text for the currently selected item in the variable list into the
 * textfield gadget.
 */
VOID load_text(struct Window *win)
{
	struct Node *node;

	SetGadgetAttrs(edit_gad, win, NULL,
		TEXTFIELD_Text, "",
		TAG_DONE);

	/* Get the selected node.
	 */
	GetAttr(LISTBROWSER_SelectedNode, list_gad, (ULONG *)&node);
	if (node)
	{
		struct LBUserData *lbud;
		ULONG flags;

		/* We stashed some important info in the userdata, so get that.
		 */
		GetListBrowserNodeAttrs(node,
			LBNA_Flags, &flags,
			LBNA_UserData, &lbud,
			TAG_DONE);
		if (lbud && !(flags & LBFLG_HASCHILDREN))
		{
			/* Open up the file for read.
			 */
			if (lbud->lbud_FileName)
			{
				LONG size;

				/* Found out how big the file is.
				 */
				if (size = file_size(lbud->lbud_FileName))
				{
					BPTR fh;

					/* Open up the file for read.
					 */
					if (fh = Open(lbud->lbud_FileName, MODE_OLDFILE))
					{
						/* Allocate a buffer large enough to load the whole
						 * file into, if we don't already have one big enough.
						 */
						if (size > lbud->lbud_BufSize)
						{
							if (lbud->lbud_Buf)
								FreeVec(lbud->lbud_Buf);
							lbud->lbud_Buf = (STRPTR)AllocVec(size + 1, MEMF_ANY);
							lbud->lbud_BufSize = size + 1;
						}
						
						if (lbud->lbud_Buf)
						{
							/* Go ahead and load our text in.
							 */
							lbud->lbud_BufSize = Read(fh, lbud->lbud_Buf, size);
							lbud->lbud_Buf[lbud->lbud_BufSize] = '\0';

							/* Tell the edit gadget to display it.
							 */
							SetGadgetAttrs(edit_gad, win, NULL,
								TEXTFIELD_Text, lbud->lbud_Buf,
								TAG_DONE);
						}
						else
						{
							D( PutStr("No buffer\n"); )
							lbud->lbud_BufSize = 0;
						}
						
						Close(fh);
					}
					D( else PutStr("Can't open file\n"); )
				}
				D( else PutStr("No file size\n"); )
			}
			D( else PutStr("No filename\n"); )
		}
		else if (flags & LBFLG_HASCHILDREN)
		{
			ULONG relevent;

			GetAttr(LISTBROWSER_RelEvent, list_gad, &relevent);
			if (relevent != LBRE_SHOWCHILDREN && relevent != LBRE_HIDECHILDREN)
			{
				SetGadgetAttrs(list_gad, win, NULL,
					LISTBROWSER_Labels, ~0,
					TAG_DONE);

				if (flags & LBFLG_SHOWCHILDREN)
					HideListBrowserNodeChildren(node);
				else
					ShowListBrowserNodeChildren(node, 1);

				SetGadgetAttrs(list_gad, win, NULL,
					LISTBROWSER_Labels, &file_list,
					TAG_DONE);
			}
		}
	}
	D( else PutStr("No selected node\n"); )
}

/* Get the file size (in bytes) of a file.
 */
LONG file_size(char *filename)
{
	BPTR lock;
	LONG size = -1;

	if (lock = Lock(filename, ACCESS_READ))
	{
		struct FileInfoBlock *fib;

		if (fib = (struct FileInfoBlock *)AllocDosObject(DOS_FIB,TAG_END))
		{
			if (Examine(lock, fib))
				size = fib->fib_Size;
			FreeDosObject(DOS_FIB, fib);
		}
		UnLock(lock);
	}
	return(size);
}


/* Save all changed variables to the specified directory.
 */
VOID save_changed(struct List *list, BOOL nochange)
{
	struct Node *node;

	/* Peruse all nodes.
	 */
	for (node = list->lh_Head; node->ln_Succ; node = node->ln_Succ)
	{
		struct LBUserData *lbud;
		ULONG flags;

		/* Get our user data structure.
		 */
		GetListBrowserNodeAttrs(node,
			LBNA_Flags, &flags,
			LBNA_UserData, &lbud,
			TAG_DONE);
		if (lbud && !(flags & LBFLG_HASCHILDREN))
		{
			/* See if the node has changed and if we have a filename
			 * and if we have a buffer.
			 */
			if (lbud->lbud_Deleted && lbud->lbud_FileName)
				DeleteFile( lbud->lbud_FileName );
			else
			if (lbud->lbud_Changed && lbud->lbud_FileName)
			{
				BPTR fh;

				/* Convert the filename.
				 */
				/* Try and open the file for write.
				 */
				if (fh = Open(lbud->lbud_FileName, MODE_NEWFILE))
				{
					if (lbud->lbud_BufSize == Write(fh, lbud->lbud_Buf, lbud->lbud_BufSize))
						lbud->lbud_Changed = nochange;
					Close(fh);
				}
			}
		}
	}
}


/* Read files in a directory to a listbrowser list.
 */
BOOL read_files(struct List *list, STRPTR dir, WORD generation)
{
	BPTR lock, file, old;

	D( Printf("Read directory: %s\n", dir); )

	if (lock = Lock(dir, ACCESS_READ))
	{
		char *eadata;
		
		old = CurrentDir(lock);

		if (eadata = (char *)AllocVec(sizeof(struct ExAllData) * 200, MEMF_CLEAR))
		{
			struct ExAllControl *eac;

			if (eac = (struct ExAllControl *)AllocDosObject(DOS_EXALLCONTROL, NULL))
			{
				BOOL more;

				eac->eac_LastKey = 0;
				do
				{
					struct ExAllData *ead;

					more = ExAll(lock, eadata, sizeof(struct ExAllData) * 200, ED_TYPE, eac);
					if (!more && IoErr() != ERROR_NO_MORE_ENTRIES)
						return(FALSE);

					if (eac->eac_Entries == 0)
						return(FALSE);

					ead = (struct ExAllData *)eadata;
					do
					{
						struct Node *node;
						char temp1[255];
						
						if (ead->ed_Type >= 0)
							continue;

						if (file = Open(ead->ed_Name, MODE_OLDFILE))
						{
							int l;
							FGets(file, temp1, 120);
							if (l = strlen(temp1)) 
								temp1[l-1] = 0;
							FGets(file, temp1+120, 120);
							if (l = strlen(temp1+120))
								temp1[l-1+120] = 0;
							Close(file);
						}

						if (node = AllocListBrowserNode(4,
										LBNA_Column, 0,
											LBNCA_CopyText, TRUE,
											LBNCA_Text, temp1,
										LBNA_Column, 1,
											LBNCA_CopyText, TRUE,
											LBNCA_Text, temp1+120,
										LBNA_Column, 2,
											LBNCA_CopyText, TRUE,
											LBNCA_Text, ead->ed_Name,
										TAG_DONE))
						{
							struct LBUserData *lbud;

							AddTail(list, (struct Node *)node);

							strcpy(temp1, dir);
							AddPart(temp1, ead->ed_Name, sizeof(temp1));

							if (lbud = (struct LBUserData *)AllocVec(sizeof(struct LBUserData), MEMF_CLEAR))
							{
								stccpy(lbud->lbud_FileName, temp1, sizeof(lbud->lbud_FileName));

								SetListBrowserNodeAttrs(node,
									LBNA_UserData, lbud,
									TAG_DONE);
							}
						}

						ead = ead->ed_Next;
					} while (ead);
				} while (more);

				FreeDosObject(DOS_EXALLCONTROL, eac);
			}
			else
				return(FALSE);
			FreeVec(eadata);
		}
		else
			return(FALSE);
			
		CurrentDir(old);
		UnLock(lock);
	}
	else
		return(FALSE);

	return(TRUE);
}


/* Copy a B string to a C string.
 */
VOID bstrcpy(STRPTR cstr, BSTR bstr)
{
	strncpy(cstr, (char *)BADDR(bstr) + 1, ((char *)BADDR(bstr))[0]);
	cstr[((char *)BADDR(bstr))[0]] = '\0';
}


/* Function to free an Exec List.
 */
VOID free_list(struct List *list)
{
	struct Node *node, *nextnode;

	node = list->lh_Head;
	while (nextnode = node->ln_Succ)
	{
		struct LBUserData *lbud;

		GetListBrowserNodeAttrs(node,
			LBNA_UserData, &lbud,
			TAG_DONE);
		if (lbud)
		{
			if (lbud->lbud_Buf);
				FreeVec(lbud->lbud_Buf);
			FreeVec(lbud);
		}

		FreeListBrowserNode(node);
		node = nextnode;
	}
	NewList(list);
}


/* Do an easy requester.
 */
LONG easy_req(struct Window *win, char *reqtext, char *reqgads, char *reqargs, ...)
{
	struct EasyStruct general_es =
	{
		sizeof(struct EasyStruct),
		0,
		"SBGen",
		NULL,
		NULL
	};

	general_es.es_TextFormat = reqtext;
	general_es.es_GadgetFormat = reqgads;

	return(EasyRequestArgs(win, &general_es, NULL, &reqargs));
}

/* NAME
 */
VOID SAVEDS ASM rexx_name(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	ac->ac_Result = "IndexEdit";
}

/* VERSION
 */
VOID SAVEDS ASM rexx_version(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	ac->ac_Result = "1.0";
}

/* AUTHOR
 */
VOID SAVEDS ASM rexx_author(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	ac->ac_Result = "Osma Ahvenlampi";
}

/* DEACTIVATE
 */
VOID SAVEDS ASM rexx_deactivate(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	if (CA_Iconify(window_obj))
		win = NULL;
}

/* ACTIVATE
 */
VOID SAVEDS ASM rexx_activate(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	win = CA_OpenWindow(window_obj);
}

/* QUIT
 */
VOID SAVEDS ASM rexx_quit(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	ok = FALSE;
}

/* 
 */
VOID SAVEDS ASM rexx_windowtoback(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	WindowToBack(win);
}

/* WINDOWTOFRONT
 */
VOID SAVEDS ASM rexx_windowtofront(REG_A0 struct ARexxCmd *ac, REG_A1 struct RexxMsg *rxm)
{
	WindowToFront(win);
}
