summaryrefslogtreecommitdiff
path: root/ShowIFF
diff options
context:
space:
mode:
authorChristian A. Weber <chris@gna.ch>1993-02-04 22:35:18 +0000
committerChristian A. Weber <chris@gna.ch>1993-02-04 22:35:18 +0000
commit9c3b4ce6277fb302baa785bd4c84740e53963c0a (patch)
treecd3fd3c102cce1dd6da9ce7660eca94d61287d81 /ShowIFF
parent4f318af8445dc55f6873832ff6f19c80e1aff0ec (diff)
downloadiff-library-9c3b4ce6277fb302baa785bd4c84740e53963c0a.tar.gz
iff-library-9c3b4ce6277fb302baa785bd4c84740e53963c0a.tar.bz2
iff-library-9c3b4ce6277fb302baa785bd4c84740e53963c0a.zip
Bug in ScrollRaster() call removed
Diffstat (limited to 'ShowIFF')
-rw-r--r--ShowIFF/ShowIFF.c1522
1 files changed, 1522 insertions, 0 deletions
diff --git a/ShowIFF/ShowIFF.c b/ShowIFF/ShowIFF.c
new file mode 100644
index 0000000..20acec5
--- /dev/null
+++ b/ShowIFF/ShowIFF.c
@@ -0,0 +1,1522 @@
+/*
+**
+** $Id: $
+** $Revision: $
+**
+** $Filename: ShowIFF/ShowIFF.c $
+** $Author: Christian A. Weber $
+** $Release: $
+** $Date: $
+**
+** NAME
+** ShowIFF - a fast IFF picture viewer for Workbench and Shell
+**
+** >>>> For full documentation, see ShowIFF.doc <<<<
+**
+** DESCRIPTION
+** ShowIFF can display any Amiga IFF pictures with up to 24 bitplanes
+** (24 bit pictures are displayed in "true color" with max. colors).
+** All known formats (HAM, HAM8, Halfbrite) and all display modes
+** like NTSC, PAL, VGA, A2024, ... are supported.
+** If a picture is larger than the screen, you can use the mouse to
+** scroll around.
+** ShowIFF can be used from Workbench or Shell, it can create an
+** AppIcon. It can display single files or whole drawers or disks.
+**
+** REQUIREMENTS
+** - iff.library V22+
+** - Amiga OS 2.0 or newer (3.0 for AGA modes)
+** - Original, Enhanced or AGA chipset
+** - to compile: SAS/C compiler V6
+**
+** AUTHOR
+** Christian A. Weber
+**
+** Internet: weber@amiga.icu.net.ch
+** UUCP: chris@limmat.net.ch
+** CBMNET: chris@mighty.adsp.sub.org
+** Snail mail: Bruggerweg 2, CH-8037 Zürich, Switzerland.
+**
+** Suggestions, bug reports or donations are welcome.
+**
+** COPYRIGHT (C) 1992 BY CHRISTIAN A. WEBER. ALL RIGHTS RESERVED.
+** COPYRIGHT (C) 1987-1993 BY CHRISTIAN A. WEBER. ALL RIGHTS RESERVED.
+** THIS PROGRAM MAY BE DISTRIBUTED FOR NON PROFIT PURPOSES ONLY.
+** NO WARRANTY. USE AT YOUR OWN RISK.
+**
+** HISTORY
+**
+** 15-Oct-87 CHW V1.0 Created this file!
+** 30-Jun-88 CHW V1.4 Directory scan fixed for FFS, cleaned up
+** 16-Nov-88 CHW V1.5 Overscan implemented
+** 28-Nov-88 CHW V1.6 Minimal screen size is now 64x64 pixels
+** 02-Jan-89 CHW V1.7 Double-buffering implemented
+** 25-Sep-89 CHW V2.01 Changed to Lattice C and ARP library
+** 27-Sep-89 CHW V2.02 Screen scrolling implemented
+** 22-Nov-89 CHW V2.03 Rejects Non-ILBM files correctly
+** 21-Feb-90 CHW V2.04 'NoMemForGfx' bug fixed, overscan fixed
+** 28-Feb-90 CHW V2.10 SHAM support code added
+** 14-Mar-90 CHW V2.11 Memory fragmentation workaround, cleanup
+** 08-Apr-90 CHW V2.12 Pics with more than 6 planes don't guru
+** 22-Apr-90 CHW V2.14 New startup code, WB cleanup works now.
+** 16-Jul-90 CHW V2.15 Works now properly with MoreRows & OS 2.0
+** 16-Sep-90 CHW V2.16 Scrolling SHAM pictures implemented
+** 03-Oct-90 CHW V2.17 MaxX0 divided by 2 because of a 2.0 bug
+** 30-Oct-90 MAB V2.20 ShowIFF can be turned into an appicon
+** 11-Jan-91 CHW V2.21 SHAM color errors fixed
+** 11-Jan-91 CHW V2.22 AppIcon image/pos are taken from .info file
+** 13-Jan-91 CHW V2.23 COMMAND mode added, overscan bug fixed (?)
+** 14-Jan-91 CHW V2.24 Icon tooltypes added, code moved around
+** 24-Jan-91 CHW V2.25 Minor bug fixes
+** 03-May-91 CHW V2.26 Vertical centering and NOCENTER option added
+** 23-May-91 CHW V2.27 Pointer option added
+** 27-May-91 CHW V2.28 True Color Table fixed and extended
+** 23-Jun-91 CHW V2.29 AppIcon's image can be specified (ICON=...)
+** 23-Apr-92 CHW V2.30 RasInfo-bug workaround only under V36-38
+** 29-Jul-92 CHW V2.31 Compiles with new IFF includes, 8 bitplanes
+** 15-Oct-92 SG V3.00 New display code, true AGA support
+** 01-Dec-92 CHW V3.1 ARP support removed, substancial rewrite
+** 04-Feb-92 CHW V3.4 Bug in ScrollRaster() call removed (would crop)
+*/
+
+// #define VERBOSE
+
+#include <hardware/custom.h> /* For SHAM/DYNA support ONLY */
+#include <proto/exec.h>
+#include <exec/memory.h>
+#include <exec/execbase.h>
+#include <proto/utility.h>
+#include <utility/utility.h>
+#include <proto/graphics.h>
+#include <graphics/gfxbase.h>
+#include <graphics/gfxmacros.h>
+#include <graphics/displayinfo.h>
+#include <proto/intuition.h>
+#include <intuition/intuitionbase.h>
+#include <proto/icon.h>
+#include <workbench/icon.h>
+#include <proto/wb.h>
+#include <workbench/startup.h>
+#include <proto/dos.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <libraries/iff.h>
+
+#include "showiff_rev.h"
+
+
+/****************************************************************************
+** Some useful macros
+*/
+
+#define MAX(a,b) ((a)>(b)?(a):(b))
+#define OSVERSION(ver) (IntuitionBase->LibNode.lib_Version >= (ver))
+#define HAS_AGA (GfxBase->ChipRevBits0 & GFXF_AA_ALICE)
+
+#define PICF_DYNA 1
+
+#define MAXCOLORS 256
+
+#define XOSCAN 0 /* Scroll if picture is bigger than screen + XOSCAN */
+#define YOSCAN 16 /* Scroll if picture is bigger than screen + YOSCAN */
+
+
+/****************************************************************************
+** Stuctures
+*/
+
+typedef struct
+{
+ UBYTE R, G, B; /* Red, Green, Blue values (0..255) */
+} RGBColor;
+
+
+struct Picture
+{
+ struct Screen *Screen; /* The picture's screen */
+ struct Window *Window; /* Window for mouse handling */
+ struct BitMap *BitMap; /* BitMap, can be larger than screen */
+ UWORD *SHAMColors; /* SHAM color table array or NULL */
+ WORD Y0; /* Y of picture relative to screen */
+ UWORD PicW, PicH; /* Total image dimensions */
+ UWORD ColorCount; /* # of colors in color palette */
+ RGBColor Palette[MAXCOLORS]; /* The picture's color palette */
+ UBYTE Flags; /* See PICF_... */
+};
+
+struct SHAMChunk
+{
+ struct IFFL_Chunk Chunk;
+ UWORD Version;
+ UWORD Colors[1]; /* open array */
+};
+
+
+/****************************************************************************
+** Tooltypes and other constant strings
+*/
+
+#define OPTIONSTOOLTYPE "OPTIONS"
+#define ICONTOOLTYPE "ICON"
+#define XPOSTOOLTYPE "ICONXPOS"
+#define YPOSTOOLTYPE "ICONYPOS"
+#define ICONNAMETOOLTYPE "ICONNAME"
+#define APPICONPORTNAME "ShowIFF-AppIcon"
+#define DEFAULTAPPICONNAME "IFF Picture Viewer"
+
+
+/****************************************************************************
+** External references
+*/
+
+extern struct Process *ProcessBase; /* Pointer to our process */
+extern struct Custom __far custom; /* For SHAM/DYNA copper list */
+
+
+/****************************************************************************
+** Global variables
+*/
+
+struct Library *UtilityBase, *IconBase, *WorkbenchBase;
+struct GfxBase *GfxBase;
+struct IntuitionBase *IntuitionBase;
+struct Library *IFFBase; /* Nothing goes without that */
+
+struct DiskObject *dobj; /* Our icon */
+IFFL_HANDLE ifffile; /* IFF file handle */
+struct Picture pic1, pic2; /* 2 pictures for double buffering */
+BPTR wbwindow; /* Output window for Workbench mode */
+BPTR oldcos; /* Old output file handle */
+LONG delay = 0x7fffffff; /* Time (in jiffies) for each picture */
+LONG monitorid; /* Monitor ID or 0 if no specific monitor */
+
+UWORD __chip emptysprite[8]; /* ShowIFF's mouse pointer sprite */
+
+
+static char VersionString[] =
+ VERSTAG " by Christian A. Weber and Peter W. Simeon\n\r";
+
+static char WindowTitle[] =
+ "CON:10/24/600/92/" VERS " (" DATE ")/AUTO/CLOSE";
+
+char StdWindowName[] = "NIL:"; /* Default Workbench window name */
+
+
+/*
+** CLI_Template and argv are used for ArgsStartup20.o. Argv receives the
+** arguments from a ReadArgs() call in the startup code. CLI_Help will
+** be printed if no arguments are specified on the command line.
+*/
+
+char CLI_Template[] =
+ "Patterns/M,ALL/S,D=DELAY/N,L=LOOP/S,MONITOR/K,NB=NOBREAK/S,NOCENTER/S,"
+ "NO=NOOVERSCAN/S,POINTER/S,CMD=COMMAND/K";
+
+static char CLI_Help[] =
+ "Usage: ShowIFF [files or patterns] [ALL] [DELAY delay] [LOOP] [MONITOR id]\n"
+ "\t[NOBREAK] [NOCENTER] [NOOVERSCAN] [POINTER] [COMMAND \"Command %s args\"]\n";
+
+struct
+{
+ char **Patterns;
+ LONG AllFlag;
+ LONG *DelayPtr;
+ LONG LoopFlag;
+ char *Monitor;
+ LONG NoBreakFlag;
+ LONG NoCenterFlag;
+ LONG NoOverscanFlag;
+ LONG PointerFlag;
+ char *Command;
+} argv;
+
+
+/****************************************************************************
+** Make sure a value is between two borders
+*/
+
+LONG SetBounds(LONG is, LONG min, LONG max)
+{
+ if (is > max) is = max;
+ if (is < min) is = min;
+ return is;
+}
+
+
+/****************************************************************************
+** Get a positive integer in hex ($1234 or 0x1A2b) or decimal
+*/
+
+static ULONG GetNumber(char *string)
+{
+ ULONG result = 0;
+ char c;
+
+ if ((string[0] == '0') && (string[1] == 'x'))
+ {
+ string++;
+ goto hex;
+ }
+ else if (string[0] == '$')
+ {
+hex:
+ string++;
+ while (c = *string++)
+ {
+ if (c >= '0' && c <= '9')
+ result = result * 16 + c - '0';
+ else if (c >= 'a' && c <= 'f')
+ result = result * 16 + 10 + c - 'a';
+ else if (c >= 'A' && c <= 'F')
+ result = result * 16 + 10 + c - 'A';
+ }
+ }
+ else
+ {
+ while (*string >= '0' && *string <= '9')
+ result = result * 10 + (*string++ - '0');
+ }
+
+ return result;
+}
+
+
+/***************************************************************************
+** Get the secondary error from iff.library and display an error text
+*/
+
+static void PrintIFFError(void)
+{
+ char *text;
+
+ switch (IFFL_IFFError() )
+ {
+ case IFFL_ERROR_OPEN:
+ text = "Can't open file";
+ break;
+
+ case IFFL_ERROR_READ:
+ text = "Error reading file";
+ break;
+
+ case IFFL_ERROR_NOMEM:
+ text = "Not enough memory";
+ break;
+
+ case IFFL_ERROR_NOTIFF:
+ text = "Not an IFF file";
+ break;
+
+ case IFFL_ERROR_NOBMHD:
+ text = "No IFF BMHD found";
+ break;
+
+ case IFFL_ERROR_NOBODY:
+ text = "No IFF BODY found";
+ break;
+
+ case IFFL_ERROR_BADCOMPRESSION:
+ text = "Unsupported compression mode";
+ break;
+
+ default:
+ text = "Unspecified error";
+ break;
+ }
+
+ Printf("%s\n", text);
+}
+
+
+/***************************************************************************
+** V37 replacement for FreeBitMap()
+*/
+
+void MyFreeBitMap(struct BitMap *bm)
+{
+ if (OSVERSION(39) )
+ {
+ FreeBitMap(bm);
+ }
+ else /* Running under V37 */
+ {
+ LONG planesize = bm->BytesPerRow * bm->Rows;
+ int i;
+
+ for (i = 0; i < bm->Depth; ++i)
+ {
+ if (bm->Planes[i])
+ {
+ FreeMem(bm->Planes[i], planesize);
+ }
+ }
+ FreeVec(bm);
+ }
+}
+
+
+/***************************************************************************
+** Allocate a BitMap structure and allocate CHIP memory for the planes.
+*/
+
+struct BitMap *MyAllocBitMap(LONG depth, LONG width, LONG height)
+{
+ struct BitMap *bm;
+
+ if (OSVERSION(39) )
+ {
+ bm = AllocBitMap(width, height, depth, BMF_CLEAR | BMF_DISPLAYABLE, NULL);
+ }
+ else
+ {
+ LONG planesize, bmsize = sizeof(struct BitMap);
+
+ /*
+ ** If the bitmap has more than 8 planes, we add the size of the
+ ** additional plane pointers to the amount of memory we allocate
+ ** for the bitmap structure.
+ */
+ if (depth > 8)
+ bmsize += sizeof(PLANEPTR) * (depth-8);
+
+ if (bm = AllocVec(bmsize, MEMF_PUBLIC | MEMF_CLEAR) )
+ {
+ int i;
+
+ InitBitMap(bm, depth, width, height);
+ planesize = bm->BytesPerRow * bm->Rows;
+
+ for (i = 0; i < depth; ++i)
+ {
+ if (bm->Planes[i] = AllocMem(planesize, MEMF_CHIP | MEMF_CLEAR) )
+ {
+ }
+ else
+ {
+ MyFreeBitMap(bm);
+ bm = NULL;
+ return bm;
+}
+
+
+/****************************************************************************
+** Load a color palette (24 bit resolution)
+*/
+
+static void LoadRGB8(struct ViewPort *vp, RGBColor *color, int count)
+{
+ int i;
+
+ /*
+ ** Avoid crash under V39
+ */
+ if (count > vp->ColorMap->Count)
+ count = vp->ColorMap->Count;
+
+ for (i=0; i < count; ++color, ++i)
+ {
+ if (OSVERSION(39) )
+ {
+ SetRGB32(vp, i, color->R<<24, color->G<<24, color->B<<24);
+ }
+ else
+ {
+ SetRGB4(vp, i, color->R>>4, color->G>>4, color->B>>4);
+ }
+ }
+}
+
+
+/****************************************************************************
+** Create a truecolor 24bit palette with <1 << totalbits> entries.
+** The bitplanes will have the order G6G7R7B7 or G4G5G6G7R6R7B6B7 ...
+** Plane#: 0 1 2 3 0 1 2 3 4 5 6 7
+** The result is the number of green planes (red and blue have always the
+** same number and can be calculated as (totalbits-greenbits)/2).
+*/
+
+static int CreateTrueColorPalette(RGBColor *palette, int totalbits)
+{
+ int numcolors, i, rbits, gbits, bbits, rlevels, glevels, blevels;
+
+ numcolors = 1 << totalbits;
+
+ /*
+ ** Divide the total number of bits into the bits for r/g/b. Green is
+ ** the most important color, so it gets the remaining bits as well.
+ */
+ rbits = gbits = bbits = totalbits / 3;
+ gbits += totalbits % 3;
+
+ rlevels = 1 << rbits;
+ glevels = 1 << gbits;
+ blevels = 1 << bbits;
+
+ for (i=0; i<numcolors; ++palette, ++i)
+ {
+ palette->G = (( i % glevels) * 0xFF) / (glevels-1);
+ palette->R = (((i >> gbits) % rlevels) * 0xFF) / (rlevels-1);
+ palette->B = (((i >> (gbits+rbits)) % blevels) * 0xFF) / (blevels-1);
+ }
+
+ return gbits;
+}
+
+
+/****************************************************************************
+** Create intermediate SHAM copper list if this is an SHAM picture.
+** This feature will probably be removed; with AGA it's useless anyway.
+*/
+
+void MakeSHAMCopList(struct Picture *pic)
+{
+ struct UCopList *ucop;
+
+ if (!pic->SHAMColors) return; /* Not an SHAM picture, no work to do */
+
+ if (ucop = AllocMem(sizeof(*ucop), MEMF_PUBLIC | MEMF_CLEAR) )
+ {
+ struct Screen *s = pic->Screen;
+ LONG i, j, step = (s->ViewPort.Modes&LACE) ? 2:1;
+ UWORD copx = GfxBase->ActiView->DxOffset + s->Width;
+ UWORD y0 = s->ViewPort.RasInfo->RyOffset;
+
+ if (pic->Flags & PICF_DYNA) step = 1;
+
+ for (i=1; i < (s->Height/step); ++i)
+ {
+ CWAIT(ucop, pic->Y0 + (i-1)*step, (UWORD)((copx>>1) % (UWORD)228))
+ for(j=1; j<16; ++j)
+ CMOVE(ucop, custom.color[j], pic->SHAMColors[16*(y0+i)+j])
+ }
+ CEND(ucop)
+// FreeVPortCopLists(&s->ViewPort);
+ s->ViewPort.UCopIns = ucop;
+// pic->SHAMColors[16*y0] = pic->ColorTab[0]; /* Fix some weird SHAM pics */
+ LoadRGB4(&s->ViewPort, &pic->SHAMColors[16*y0], 16);
+ }
+}
+
+
+/****************************************************************************
+** Free a picture (that is a window, screen and a custom BitMap)
+*/
+
+void ClosePicture(struct Picture *pic)
+{
+ if (pic->Window)
+ {
+ ScreenToBack(pic->Screen);
+ ClearPointer(pic->Window);
+ CloseWindow(pic->Window);
+ pic->Window = NULL;
+ }
+
+ if (pic->Screen)
+ {
+ CloseScreen(pic->Screen);
+ pic->Screen = NULL;
+ }
+
+ if (pic->BitMap)
+ {
+ MyFreeBitMap(pic->BitMap);
+ pic->BitMap = NULL;
+ }
+
+ RemakeDisplay(); /* remake copper list to increase MEMF_LARGEST */
+}
+
+
+/****************************************************************************
+** Get the view mode for a picture. If there is a CAMG chunk, we just
+** return its contents. If there is none, we ask the graphics library for
+** help. If it can't help us (<3.0), we calculate a view mode by hand.
+*/
+
+static ULONG GetBestViewMode(IFFL_HANDLE iff, struct IFFL_BMHD *bmhd)
+{
+ ULONG viewmode;
+
+ /*
+ ** We don't want iff.library to give us a default viewmode if no
+ ** CAMG is present, so we must check first for a CAMG, and only
+ ** if it's there we can call IFFL_GetViewModes()
+ */
+ if (IFFL_FindChunk(iff, ID_CAMG) )
+ {
+ viewmode = IFFL_GetViewModes(iff);
+#ifdef VERBOSE
+ Printf("CAMG: $%08lx ", viewmode);
+#endif
+ }
+ else
+ {
+ viewmode = INVALID_ID;
+
+ if (OSVERSION(39) )
+ {
+ viewmode = BestModeID(
+ BIDTAG_NominalWidth, bmhd->w,
+ BIDTAG_NominalHeight, bmhd->h,
+ BIDTAG_DesiredWidth, bmhd->w,
+ BIDTAG_DesiredHeight, bmhd->h,
+ BIDTAG_Depth, bmhd->nPlanes,
+
+// BIDTAG_MonitorID, monitorid,
+
+ monitorid ? BIDTAG_MonitorID : TAG_IGNORE,
+ monitorid,
+ TAG_DONE
+ );
+#ifdef VERBOSE
+ Printf("BESTID: $%08lx ", viewmode);
+#endif
+ }
+ }
+
+ /*
+ ** If we don't have a valid viewmode by now, let's handcraft it...
+ */
+ if (viewmode == INVALID_ID)
+ {
+#if 0
+ /*
+ ** $$$ This is for non-aga only!!! fix!!
+ */
+ viewmode = 0;
+ if((bmhd->nPlanes <=4) || (bmhd->nPlanes == 24))
+ {
+ if(bmhd->w > 400) viewmode |= HIRES_KEY;
+ }
+ else if(bmhd->nPlanes == 6) viewmode |= HAM_KEY;
+
+ if(bmhd->h > 320) viewmode |= LORESLACE_KEY;
+#else
+ viewmode = monitorid; // Test
+#endif
+
+#ifdef VERBOSE
+ Printf("MY GUESS: $%08lx ", viewmode);
+#endif
+ }
+
+ return viewmode;
+}
+
+
+/****************************************************************************
+** Allocate a picture (Allocate custom BitMap, open screen and window)
+*/
+
+BOOL OpenPicture(struct Picture *pic)
+{
+ struct DimensionInfo di;
+ struct IFFL_BMHD *bmhd;
+ ULONG viewmode, overscan;
+ int xpos, ypos, width, height, depth;
+
+ /*
+ ** If this picture was already loaded, free it.
+ */
+ ClosePicture(pic);
+ memset(pic, 0, sizeof(*pic));
+
+
+ /*
+ ** First, we get the BMHD chunk from the file. If there is none,
+ ** we show an error message and return.
+ */
+ if ( !(bmhd = IFFL_GetBMHD(ifffile)) )
+ {
+ PrintIFFError();
+ return FALSE;
+ }
+
+ Printf("%ld x %ld x %ld ", bmhd->w, bmhd->h, bmhd->nPlanes);
+ Flush(Output());
+
+
+ /*
+ ** Get the viewmodes and its monitor dimension info, and calculate
+ ** the screen position, width and height. If the picture is larger
+ ** than the max overscan area, it is displayed with OSCAN_TEXT, and
+ ** can be scrolled with the mouse.
+ */
+ viewmode = GetBestViewMode(ifffile, bmhd);
+
+ if (GetDisplayInfoData(NULL,(UBYTE *)&di, sizeof(di), DTAG_DIMS, viewmode) )
+ {
+ BOOL scroll = FALSE;
+
+ int maxwidth = di.VideoOScan.MaxX - di.VideoOScan.MinX + 1;
+ int maxheight = di.VideoOScan.MaxY - di.VideoOScan.MinY + 1;
+
+ int stdwidth = di.TxtOScan.MaxX - di.TxtOScan.MinX + 1;
+ int stdheight = di.TxtOScan.MaxY - di.TxtOScan.MinY + 1;
+
+ width = SetBounds(bmhd->w, di.MinRasterWidth, maxwidth+XOSCAN);
+ height = SetBounds(bmhd->h, stdheight, maxheight+YOSCAN);
+ depth = SetBounds(bmhd->nPlanes, 1, di.MaxDepth);
+
+ if (bmhd->w > (maxwidth+XOSCAN)) /* Too wide, scroll horizontally */
+ {
+ width = stdwidth;
+ scroll = TRUE;
+ }
+
+ if (bmhd->h > (maxheight+YOSCAN)) /* Too high, scroll vertically */
+ {
+ height = stdheight;
+ scroll = TRUE;
+ }
+
+ if (((bmhd->w > stdwidth) || (bmhd->h > stdheight)) && !scroll)
+ {
+ overscan = OSCAN_VIDEO;
+ }
+ else overscan = OSCAN_TEXT;
+
+ pic->PicW = bmhd->w;
+ pic->PicH = bmhd->h;
+ pic->Y0 = SetBounds((height - bmhd->h) / 2, 0, height);
+
+ if (!argv.NoCenterFlag)
+ {
+ xpos = (stdwidth - width) / 2;
+ ypos = (stdheight - height) / 2;
+ }
+ else
+ {
+ xpos = ypos = pic->Y0 = 0;
+ }
+
+#ifdef VERBOSE
+ Printf("\nScr(%ld x %ld x %ld) Max(%ld x %ld x %ld) ",
+ width, height, depth, maxwidth, maxheight, di.MaxDepth);
+#endif
+ }
+ else
+ {
+ switch (ModeNotAvailable(viewmode) )
+ {
+ case DI_AVAIL_NOCHIPS:
+ Printf("You need a better chipset for view mode $%08lx\n", viewmode);
+ break;
+
+ case DI_AVAIL_NOMONITOR:
+ Printf("The required monitor ($%08lx) is not available\n", viewmode);
+ break;
+
+ case DI_AVAIL_NOTWITHGENLOCK:
+ Printf("The monitor $%08lx does not support genlocks\n", viewmode);
+ break;
+
+ default:
+ Printf("View mode $%08lx not available.\n", viewmode);
+ break;
+ }
+
+ return FALSE;
+ }
+
+
+ /*
+ ** Allocate the screen's bitmap
+ */
+ if (pic->BitMap = MyAllocBitMap(
+ bmhd->nPlanes, MAX(bmhd->w, width), MAX(bmhd->h, height)) )
+ {
+ ULONG oserror;
+
+ pic->BitMap->Depth = depth; /* Make OpenScreen() work */
+
+ /*
+ ** Now open the screen
+ */
+ if (pic->Screen = OpenScreenTags(NULL,
+ SA_Left, xpos,
+ SA_Top, ypos,
+ SA_Width, width,
+ SA_Height, height,
+ SA_Depth, depth,
+ SA_BitMap, pic->BitMap,
+ SA_Behind, TRUE,
+ SA_Quiet, TRUE,
+ SA_Type, CUSTOMSCREEN,
+ SA_DisplayID, viewmode,
+ SA_Overscan, overscan,
+ SA_ErrorCode, &oserror,
+ TAG_DONE
+ ))
+ {
+ UBYTE *colortab;
+
+ pic->BitMap->Depth = bmhd->nPlanes; /* Undo cheat */
+
+ /*
+ ** Create the color palette (read from CMAP chunk, if any)
+ */
+ if (bmhd->nPlanes == 24)
+ {
+ /*
+ ** If we have a 24bit true color picture, we calculate a
+ ** "true color" palette and use the screen's most significant
+ ** bitplanes for our reduced true color picture. This doesn't
+ ** look perfect, but is FAST. Feel free to enhance this.
+ */
+ int greenbits, rbbits, i;
+
+// depth = 3;
+
+ greenbits = CreateTrueColorPalette(pic->Palette, depth);
+ rbbits = (depth-greenbits)/2;
+
+ /*
+ ** Rearrange the bitplane pointers of our screen.
+ ** This is not quite legal, I suppose (but OK for PD :-))
+ */
+ for (i=0; i<greenbits; ++i)
+ {
+ pic->Screen->BitMap.Planes[i] =
+ pic->BitMap->Planes[16-greenbits+i];
+ }
+
+ for (i=0; i < rbbits; ++i)
+ {
+ pic->Screen->BitMap.Planes[greenbits+i] =
+ pic->BitMap->Planes[8-rbbits+i];
+
+ pic->Screen->BitMap.Planes[greenbits+rbbits+i] =
+ pic->BitMap->Planes[24-rbbits+i];
+ }
+
+ pic->ColorCount = 1 << depth;
+ }
+ else if (colortab = IFFL_FindChunk(ifffile, ID_CMAP) )
+ {
+ pic->ColorCount =
+ SetBounds(*(ULONG *)(colortab+4) / 3, 0, MAXCOLORS);
+
+ CopyMem(colortab+8, pic->Palette,
+ pic->ColorCount * sizeof(RGBColor));
+ }
+ else
+ {
+ /*
+ ** Use default colors for pictures without a CMAP
+ */
+ static RGBColor white = { 0xEE, 0xCC, 0xAA };
+ pic->ColorCount = 2;
+ pic->Palette[0] = white;
+// pic->Palette[1] = black;
+ }
+
+ LoadRGB8(&pic->Screen->ViewPort, pic->Palette, pic->ColorCount);
+
+
+ /*
+ ** To get our intuimessages, we open a window in the screen
+ */
+ if (pic->Window = OpenWindowTags(NULL,
+ WA_Flags, WFLG_BACKDROP | WFLG_BORDERLESS
+ | WFLG_ACTIVATE | WFLG_SIMPLE_REFRESH
+ | WFLG_NOCAREREFRESH | WFLG_REPORTMOUSE
+ | WFLG_RMBTRAP,
+ WA_IDCMP, IDCMP_MOUSEBUTTONS | IDCMP_MOUSEMOVE
+ | IDCMP_DELTAMOVE | IDCMP_VANILLAKEY,
+ WA_CustomScreen, pic->Screen,
+ TAG_DONE
+ ))
+ {
+ /*
+ ** Clear the mouse pointer if desired
+ */
+ if( !argv.PointerFlag)
+ SetPointer(pic->Window, emptysprite, 1L, 16L, 0L, 0L);
+
+ return TRUE;
+ }
+ }
+ else switch (oserror) /* OpenScreenTags() failed */
+ {
+ case OSERR_NOMONITOR:
+ PutStr("Monitor not available.\n");
+ break;
+
+ case OSERR_NOCHIPS:
+ PutStr("You need newer custom chips.\n");
+ break;
+
+ case OSERR_NOMEM:
+ PutStr("Not enough free main memory.\n");
+ break;
+
+ case OSERR_NOCHIPMEM:
+ PutStr("Not enough free chip mempry.\n");
+ break;
+
+ case OSERR_UNKNOWNMODE:
+ PutStr("Bad screen mode.\n");
+ break;
+
+ case OSERR_TOODEEP:
+ PutStr("Too many colors requested.\n");
+ break;
+
+ case OSERR_NOTAVAILABLE:
+ PutStr("Can't open screen.\n");
+ break;
+
+ default:
+ PutStr("You're completely lost.\n");
+ break;
+ }
+ }
+ else PutStr("Not enough memory\n");
+
+ ClosePicture(pic);
+ return FALSE;
+}
+
+
+/****************************************************************************
+** That's the big one! Load and display a picture, handle mouse movement
+** and other input events.
+** Returns FALSE if user presses the RMB (abort), else returns TRUE
+*/
+
+BOOL ShowPicture(char *name)
+{
+ BOOL cont = TRUE;
+
+ /*
+ ** Skip icon files
+ */
+ {
+ int len = strlen(name);
+ if (len >= 5)
+ {
+ if ( !Stricmp(name + len-5, ".info") )
+ return TRUE;
+ }
+ }
+
+ Printf("%s ... ", name);
+ Flush(Output());
+
+
+ /*
+ ** Load the IFF file into memory. If a file was already loaded, free
+ ** its memory first.
+ */
+ if(ifffile) IFFL_CloseIFF(ifffile);
+
+ if ( !(ifffile = IFFL_OpenIFF(name, IFFL_MODE_READ)) )
+ {
+ PrintIFFError();
+ return TRUE;
+ }
+
+ if ( *(((ULONG *)ifffile)+2) != ID_ILBM)
+ {
+ PutStr("Not an ILBM picture\n");
+ return TRUE;
+ }
+
+retry:
+ if (OpenPicture(&pic1) )
+ {
+ if (IFFL_DecodePic(ifffile, pic1.BitMap) )
+ {
+ struct SHAMChunk *sham;
+ LONG i;
+ int xoff = 0, yoff = 0;
+ int maxx0 = pic1.PicW - pic1.Screen->Width;
+ int maxy0 = pic1.PicH - pic1.Screen->Height;
+
+ /*
+ ** In 2.0 there's this RasInfo scrolling bug, it's fixed
+ ** for 3.0, so we'll make an explicit version check, and
+ ** a workaround for the bug.
+ */
+ if (pic1.Screen->ViewPort.Modes & HIRES)
+ {
+ if( (GfxBase->LibNode.lib_Version >= 36)
+ && (GfxBase->LibNode.lib_Version <= 38) )
+ maxx0 >>= 1;
+ }
+
+
+ /*
+ ** If the picture is not as high as the screen, we have to
+ ** move it down so it will be centered.
+ */
+ if (pic1.Y0)
+ {
+// Printf("ScrollRaster(rp,0,%ld,0,0,%ld,%ld)\n",-pic1.Y0,pic1.PicW-1,pic1.PicH-1);
+ ScrollRaster(&pic1.Screen->RastPort,
+ 0, -pic1.Y0, 0, 0, pic1.PicW-1, pic1.PicH+pic1.Y0-1);
+ }
+
+
+ /*
+ ** If an SHAM or DYNA chunk is found, build the appropriate
+ ** copper list to display the picture. This may not be supported
+ ** in future versions.
+ */
+ if (sham = IFFL_FindChunk(ifffile, ID_SHAM) )
+ {
+ Printf("SHAM ");
+ if (sham->Version == 0)
+ {
+ pic1.SHAMColors = sham->Colors;
+ }
+ else Printf("Unsupported mode: %ld ", (LONG)sham->Version);
+
+ MakeSHAMCopList(&pic1);
+ }
+
+ if (sham = IFFL_FindChunk(ifffile, ID_CTBL) )
+ {
+ Printf("DYNA ");
+ pic1.SHAMColors = &sham->Version; /* DYNA has no version */
+ pic1.Flags |= PICF_DYNA;
+ MakeSHAMCopList(&pic1);
+ }
+
+ Flush(Output());
+
+
+ /*
+ ** Display the picture, and close a possible old one
+ */
+ ScreenToFront(pic1.Screen);
+ ClosePicture(&pic2);
+
+
+ /*
+ ** And now for the event loop ...
+ */
+ for (i = 0; i < delay; ++i)
+ {
+ struct IntuiMessage *msg;
+
+ WaitTOF();
+ while (msg = (struct IntuiMessage *)GetMsg(pic1.Window->UserPort) )
+ {
+newmsg: switch(msg->Class)
+ {
+ case IDCMP_MOUSEMOVE:
+
+ xoff += msg->MouseX;
+ yoff += msg->MouseY;
+ xoff = SetBounds(xoff, 0, maxx0);
+ yoff = SetBounds(yoff, 0, maxy0);
+
+ pic1.Screen->ViewPort.RasInfo->RxOffset = xoff;
+ pic1.Screen->ViewPort.RasInfo->RyOffset = yoff;
+
+ /*
+ ** If there is an SHAM copper list, we must
+ ** update it if the user scrolled the picture.
+ ** This is quite slow, so we collect all mouse
+ ** movement messages during this time.
+ */
+ if (pic1.SHAMColors)
+ {
+ struct IntuiMessage *m2;
+
+ MakeSHAMCopList(&pic1);
+ while (m2 = (struct IntuiMessage *)GetMsg(pic1.Window->UserPort) )
+ {
+ ReplyMsg(msg); msg = m2;
+
+ if(msg->Class == IDCMP_MOUSEMOVE)
+ {
+ xoff += msg->MouseX;
+ yoff += msg->MouseY;
+ }
+ else goto newmsg;
+ }
+ }
+
+ /*
+ ** Now make the changes visible. Under V39 we
+ ** use the updated ScrollVPort() routine.
+ */
+#if 0
+ if (OSVERSION(39) )
+ {
+ ScrollVPort(&pic1.Screen->ViewPort);
+ }
+ else
+#endif
+ {
+ MakeScreen(pic1.Screen);
+ RethinkDisplay();
+ }
+ break;
+
+ case IDCMP_VANILLAKEY:
+ if (msg->Code == 'c')
+ {
+ if (argv.Command)
+ {
+ char buf[200];
+ sprintf(buf, argv.Command, name, name);
+ Execute(buf, NULL, Output());
+ }
+ }
+ break;
+
+ case IDCMP_MOUSEBUTTONS:
+ if (!argv.NoBreakFlag)
+ {
+ if (msg->Code == MENUDOWN) goto usrbreak;
+ if (msg->Code == SELECTDOWN) goto showend;
+ }
+ break;
+ }
+
+ ReplyMsg(msg);
+ }
+
+ /*
+ ** If the user hits Ctrl-C we quit, if not NOBREAK
+ */
+ if (!argv.NoBreakFlag)
+ {
+ if (CheckSignal(SIGBREAKF_CTRL_C) )
+ {
+usrbreak: PutStr("***BREAK\n");
+ cont = FALSE;
+ goto showend2;
+ }
+ }
+ }
+
+showend:
+ PutStr("- Done\n");
+
+showend2:
+ pic2 = pic1;
+ memset(&pic1, 0, sizeof(pic1) );
+ }
+ else
+ {
+ ClosePicture(&pic1);
+ PrintIFFError();
+ }
+ }
+ else if(pic2.Window)
+ {
+ ClosePicture(&pic2);
+ goto retry;
+ }
+
+ return cont;
+}
+
+
+/****************************************************************************
+** Expand a pattern and call ShowPicture() for each matching file.
+** Rreturn FALSE if the user presses ^C, or if ShowPicture() returned FALSE.
+*/
+
+BOOL ShowPattern(char *pathname)
+{
+ char buf[256];
+ BPTR file;
+ BOOL cont = TRUE;
+
+ /*
+ ** Check if the supplied pathname contains any wildcards. In this
+ ** case (ParsePattern() returns TRUE) we scan the directory.
+ ** If no wildcards are found, we just pass along the name to
+ ** ShowPicture(), if it is not the name of a directory.
+ */
+ if (ParsePatternNoCase(pathname, buf, sizeof(buf)) )
+ {
+ struct
+ {
+ struct AnchorPath APath;
+ char FullPath[255]; /* cheap way to extend ap_Buf[] */
+ } *myanchor;
+
+iswild:
+ if (myanchor = AllocVec(sizeof(*myanchor), MEMF_PUBLIC | MEMF_CLEAR) )
+ {
+ BOOL showit = TRUE;
+ LONG error;
+
+ myanchor->APath.ap_Strlen = sizeof(myanchor->FullPath);
+ myanchor->APath.ap_Flags = APF_DOWILD;
+ myanchor->APath.ap_BreakBits = SIGBREAKF_CTRL_C;
+
+ error = MatchFirst(pathname, myanchor);
+
+ while (!error)
+ {
+ if (CheckSignal(SIGBREAKF_CTRL_E) )
+ {
+ PutStr("***DIR BREAK\n"); showit=FALSE;
+ /* myanchor->APath.ap_Flags &= ~APF_DODIR; */
+ }
+
+ if(myanchor->APath.ap_Info.fib_DirEntryType >= 0) /* Dir */
+ {
+ if (argv.AllFlag)
+ {
+ if ( !(myanchor->APath.ap_Flags & APF_DIDDIR) )
+ {
+ myanchor->APath.ap_Flags |= APF_DODIR;
+ showit = TRUE;
+ }
+ myanchor->APath.ap_Flags &= ~APF_DIDDIR;
+ }
+ }
+ else if(showit)
+ {
+ if (!ShowPicture(myanchor->APath.ap_Buf) )
+ {
+ cont = FALSE;
+ break;
+ }
+ }
+ error = MatchNext(myanchor);
+ }
+
+ MatchEnd(myanchor);
+
+
+ /*
+ ** Find out why the loop terminated
+ */
+ switch(error)
+ {
+ case 0:
+ break;
+
+ case ERROR_BREAK:
+ PutStr("***BREAK\n");
+ cont = FALSE;
+ break;
+
+ case ERROR_OBJECT_NOT_FOUND:
+ PutStr("File not found\n");
+ cont = FALSE;
+ break;
+
+ case ERROR_BUFFER_OVERFLOW:
+ PutStr("Path too long\n");
+ break;
+
+ case ERROR_NO_MORE_ENTRIES: /* Normal termination */
+ break;
+
+ default:
+ PrintFault(error, "");
+ break;
+ }
+
+ FreeVec(myanchor);
+ }
+ else PutStr("No memory for anchor\n");
+ }
+ else if (file = Open(pathname, MODE_OLDFILE) ) /* Just one file ? */
+ {
+ Close(file);
+ return ShowPicture(pathname);
+ }
+ else /* No wildcards, and not a file: it's a device or a directory */
+ {
+ strcpy(buf, pathname);
+ AddPart(pathname=buf, "#?", sizeof(buf));
+ goto iswild; /* Not really elegant, but it works */
+ }
+
+ return cont;
+}
+
+
+/****************************************************************************
+** Started without arguments: create or delete our appicon
+*/
+
+void AppIconStuff(void)
+{
+ struct MsgPort *msgport;
+ struct AppIcon *ai;
+ struct AppMessage *amsg;
+
+ if (msgport = FindPort(APPICONPORTNAME) ) /* Already running ? */
+ {
+ Signal(msgport->mp_SigTask, SIGBREAKF_CTRL_C); /* Yes ---> Kill it */
+ }
+ else if(msgport = CreateMsgPort() )
+ {
+ struct DiskObject *appdobj = NULL;
+ char *tooltype;
+
+ msgport->mp_Node.ln_Name = APPICONPORTNAME;
+ AddPort(msgport);
+
+ /*
+ ** If an "ICON" tooltype is specified, we use this as the
+ ** appicon for ShowIFF. Default is ShowIFF's own icon image.
+ */
+ if (tooltype = FindToolType(dobj->do_ToolTypes, ICONTOOLTYPE) )
+ appdobj = GetDiskObject(tooltype);
+
+ if (appdobj == NULL) appdobj = dobj;
+
+ /*
+ ** Position of the appicon can be specified with "ICON[XY]POS"
+ */
+ if (tooltype = FindToolType(dobj->do_ToolTypes, XPOSTOOLTYPE) )
+ appdobj->do_CurrentX = GetNumber(tooltype);
+ else
+ appdobj->do_CurrentX = NO_ICON_POSITION;
+
+ if (tooltype = FindToolType(dobj->do_ToolTypes, YPOSTOOLTYPE) )
+ appdobj->do_CurrentY = GetNumber(tooltype);
+ else
+ appdobj->do_CurrentY = NO_ICON_POSITION;
+
+ /*
+ ** The appicon's name is set with "ICONNAME"
+ */
+ if ( !(tooltype = FindToolType(dobj->do_ToolTypes, ICONNAMETOOLTYPE)) )
+ tooltype = DEFAULTAPPICONNAME;
+
+ /*
+ ** Add our appicon
+ */
+ if (ai = AddAppIconA(0, 0, tooltype, msgport, NULL, appdobj, NULL) )
+ {
+ while ( !(Wait(1L << msgport->mp_SigBit | SIGBREAKF_CTRL_C)
+ & SIGBREAKF_CTRL_C) )
+ {
+ if (wbwindow = Open(WindowTitle, MODE_OLDFILE) )
+ {
+ oldcos = SelectOutput(wbwindow);
+ }
+
+ while(amsg = (struct AppMessage *)GetMsg(msgport) )
+ {
+ struct WBArg *arg = amsg->am_ArgList;
+ int i, cont = TRUE;
+
+ for(i=0; (i < amsg->am_NumArgs) && cont; i++,arg++)
+ {
+ BPTR oldcd = 0;
+ if(arg->wa_Lock) oldcd = CurrentDir(arg->wa_Lock);
+ else DisplayBeep(NULL);
+
+ cont = ShowPattern(arg->wa_Name && *arg->wa_Name
+ ? (STRPTR)arg->wa_Name : "#?");
+ if(oldcd) CurrentDir(oldcd);
+ }
+ ReplyMsg(amsg);
+ }
+
+ ClosePicture(&pic2); /* Close last screen */
+
+
+ if(wbwindow)
+ {
+ WaitForChar(wbwindow, 2L<<20); /* Wait 2 seconds */
+ SelectOutput(oldcos);
+ oldcos = 0;
+ Close(wbwindow);
+ wbwindow = NULL;
+ SetSignal(0, SIGBREAKF_CTRL_C); /* Clear break sig */
+ }
+ }
+ RemoveAppIcon(ai);
+ }
+
+ if(appdobj != dobj) FreeDiskObject(appdobj);
+
+ /*
+ ** Make sure there are no more messages pending
+ */
+ while (amsg = (struct AppMessage *)GetMsg(msgport) )
+ ReplyMsg(amsg);
+
+ RemPort(msgport);
+ DeleteMsgPort(msgport);
+ }
+}
+
+
+/****************************************************************************
+** The entry point, called from ArgsStartup20.o
+*/
+
+LONG Main(struct WBStartup *startup, LONG arglen)
+{
+ #define argline ((char *)startup)
+
+ /*
+ ** Open all needed libraries
+ */
+ if ( !(UtilityBase = OpenLibrary(UTILITYNAME, 36L)) )
+ goto quit;
+
+ if ( !(GfxBase = (struct GfxBase *)OpenLibrary(GRAPHICSNAME, 36L)) )
+ goto quit;
+
+ if ( !(IntuitionBase = (void *)OpenLibrary("intuition.library", 36L)) )
+ goto quit;
+
+ if ( !(IconBase = OpenLibrary(ICONNAME, 36L)) )
+ goto quit;
+
+ if ( !(WorkbenchBase = OpenLibrary(WORKBENCH_NAME, 36L)) )
+ goto quit;
+
+ if ( !(IFFBase = OpenLibrary(IFFNAME, 19L)) )
+ goto quit;
+
+ if (IFFBase->lib_Version < IFFVERSION)
+ PutStr("WARNING: you have an old version of iff.library\n");
+
+
+ /*
+ ** Get args from WB or CLI as appropriate
+ */
+ if (arglen) /* From CLI */
+ {
+ if (*argline != '\n')
+ {
+ if (argv.DelayPtr)
+ delay = *argv.DelayPtr * SysBase->VBlankFrequency + 1;
+
+ if (argv.Monitor)
+ monitorid = GetNumber(argv.Monitor);
+
+ do
+ {
+ char **pattern = argv.Patterns;
+
+ if (*pattern)
+ {
+ while (*pattern)
+ if (!ShowPattern(*pattern++) )
+ goto done;
+ }
+ else ShowPattern("#?");
+
+ } while (argv.LoopFlag);
+done:
+ PutStr("All done.\n");
+ }
+ else
+ {
+ PutStr(VersionString+7);
+ PutStr(CLI_Help);
+ }
+ }
+ else /* Called from Workbench */
+ {
+ /*
+ ** Set defaults for Workbench
+ */
+ argv.AllFlag = TRUE;
+// argv.LoopFlag = FALSE;
+// argv.NoBreakFlag = FALSE;
+// argv.NoOverscanFlag = FALSE;
+
+ if (dobj = GetDiskObject(startup->sm_ArgList->wa_Name))
+ {
+ char *tooltype;
+
+#if 0
+ if (tooltype = FindToolType(dobj->do_ToolTypes, OPTIONSTOOLTYPE) )
+ {
+ GADS(tooltype, strlen(tooltype), NULL, argv, CLI_Template);
+ if (argv.DelayPtr)
+ delay = *argv.DelayPtr * SysBase->VBlankFrequency + 1;
+ }
+#endif
+
+ if (tooltype = FindToolType(dobj->do_ToolTypes, "MONITOR") )
+ monitorid = GetNumber(tooltype);
+ }
+
+ if (startup->sm_NumArgs > 1) /* Started with some arguments */
+ {
+ struct WBArg *arg = startup->sm_ArgList;
+ int i;
+
+ /*
+ ** Open our output window
+ */
+ if (wbwindow = Open(WindowTitle, MODE_OLDFILE) )
+ oldcos = SelectOutput(wbwindow);
+
+ for (i=1; i<startup->sm_NumArgs; ++i)
+ {
+ arg++;
+ if (arg->wa_Lock) CurrentDir(arg->wa_Lock);
+ else PutStr("Can't lock directory\n");
+
+ if (arg->wa_Name && *arg->wa_Name)
+ {
+ if (!ShowPattern(arg->wa_Name) )
+ break;
+ }
+ else ShowPattern("#?");
+ }
+
+ PutStr("All done.\n");
+ }
+ else /* no arguments, just clicked */
+ {
+ AppIconStuff();
+ }
+ }
+
+
+ /*
+ ** Cleanup
+ */
+quit:
+ ClosePicture(&pic1);
+ ClosePicture(&pic2);
+
+ if(ifffile) IFFL_CloseIFF(ifffile);
+
+ if (dobj)
+ {
+ FreeDiskObject(dobj);
+// dobj = NULL;
+ }
+
+ if(wbwindow)
+ {
+ WaitForChar(wbwindow, 3L<<20); /* Wait 3 seconds */
+ Close(wbwindow);
+// wbwindow = 0;
+ }
+
+ if (oldcos)
+ {
+ SelectOutput(oldcos);
+// oldcos = 0;
+ }
+
+ CloseLibrary(IFFBase);
+ CloseLibrary(WorkbenchBase);
+ CloseLibrary(IconBase);
+ CloseLibrary(IntuitionBase);
+ CloseLibrary(GfxBase);
+ CloseLibrary(UtilityBase);
+
+ return RETURN_OK;
+}