added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / workbench / demos / 2View / 2View.c
blobddf07490025d072c9615795f6d0b7764639ff59b
1 /* Modified version for AROS - The AROS Research OS
2 ** $Id$
3 */
5 /***********************************************************************\
6 * 2View V1.50 *
7 * A simple, fast ILBM viewer, for use under AmigaOS V2.x. *
8 * Written and ©1991-1992 by Dave Schreiber. All Rights Reserved. *
9 * *
10 * Usage: *
11 * 2View FILE/A/M,FROM/K,SECS=SECONDS/K/N,TICKS/K/N,LOOP/S,PRINT *
12 * *
13 * Where the following arguments are defined as follows: *
14 * FILE - The name of one (or more) IFF ILBM files *
15 * FROM - A file containing a list of filenames. Used instead of FILE *
16 * SECS - Number of seconds to display a file *
17 * TICKS - Number of ticks (1/60ths of a second) *
18 * LOOP - When finished showing the last pictures, start over *
19 * PRINT - Print each picture as it is shown *
20 * *
21 * To compile (with SAS/C V5.10a): *
22 * lc -v 2View ARexx *
23 * lc -v -b0 Misc *
24 * asm 2ViewAsm.a *
25 * blink with 2View.lnk *
26 * *
27 * Version history: *
28 * 1.50 - Rewrote the subroutine that reads the ILBM from disk in *
29 * assembly language, for speed. Added support for SHAM and *
30 * Macro Paint images, and for color cycling (both *
31 * traditional (CRNG, i.e. continutout cycle ranges) and *
32 * DPaint-IV style cycling (DRNG, i.e. non-continuous cycle *
33 * ranges). A 'tick' (as used with the "TICK" keyword, above)*
34 * has been redefined as 1/60th of a second. Finally, the *
35 * source code in 2View.c has been split into two files *
36 * (2View.c and Misc.c). *
37 * Released 3/24/92 *
38 * *
39 * 1.11 - Improved error reporting (with this version, if the user *
40 * run 2View from Workbench and there's an error, a requester *
41 * is put up. Previously, the user was not notified at all *
42 * of the error). *
43 * Released 9/11/91 *
44 * *
45 * 1.10 - Added support for Workbench, ARexx, scrollable bitmaps, *
46 * and printing. Also, the user can now use CTRL-C to advance*
47 * to the next frame, and CTRL-D to abort a playlist. *
48 * Released 9/3/91 *
49 * *
50 * 1.00 - Original version. Released 7/24/91 *
51 * *
52 \************************************************************************/
55 unsigned long availBytes,curPos,bufSize;
57 /*Include files*/
59 #include <exec/types.h>
60 #include <libraries/iffparse.h>
61 #include <dos/dos.h>
62 #include <dos/dosasl.h>
63 #include <intuition/intuition.h>
64 #include <exec/memory.h>
65 #include <workbench/startup.h>
66 #include <graphics/gfxbase.h>
68 /*Prototypes*/
69 #include <proto/exec.h>
70 #include <proto/intuition.h>
71 #include <proto/dos.h>
72 #include <proto/graphics.h>
73 #include <proto/iffparse.h>
75 /*Other include files*/
76 #include "iff.h"
77 #include "2View.h"
78 /* #include "arexx.h" */
80 #include <stdlib.h>
81 #include <string.h>
83 /*Libraries we'll need*/
84 struct Library *IFFParseBase=NULL;
85 struct IntuitionBase *IntuitionBase=NULL;
86 struct GfxBase *GfxBase=NULL;
88 #ifdef __AROS__
89 #define __chip
90 #endif
92 /*Generic screen and window definitions. They will be used to define*/
93 /*the screen and window that the various pictures will be shown on*/
94 struct NewScreen newScreen=
96 0,0,0,0,0,1,0,0,CUSTOMSCREEN|SCREENBEHIND|AUTOSCROLL,NULL,NULL,NULL,
97 NULL
100 struct NewWindow newWindow =
102 0,0,0,0,0,1,IDCMP_MENUPICK|IDCMP_MOUSEBUTTONS|IDCMP_ACTIVEWINDOW|IDCMP_VANILLAKEY,
103 WFLG_RMBTRAP|WFLG_BORDERLESS|WFLG_NOCAREREFRESH,NULL,NULL,NULL,NULL,NULL,
104 0,0,640,400,CUSTOMSCREEN
107 struct Screen *screen=NULL;
108 struct Window *window=NULL;
110 UWORD *storage;
111 int counter;
113 /*A true here indicates the current ILBM file is compressed*/
114 BYTE Compression;
116 /*The version string. Do a 'version 2View' to display it*/
117 char *version="$VER: QView V1.50 (24.3.92)";
119 /*Just so that the © message is part of the actual program*/
120 char *copyRightMsg="Copyright 1991-1992 by Dave Schreiber. All Rights Reserved.";
122 BYTE ExitFlag=FALSE; /*'Exit now' flag*/
123 UWORD ticks=0; /*Delay requested by user.*/
125 /*The previous screen and window*/
126 struct Window *prevWindow=NULL;
127 struct Screen *prevScreen=NULL;
129 /*Data for a blank pointer*/
130 UWORD __chip fakePointerData[]={0,0,0,0,0};
132 struct IFFHandle *iff=NULL; /*IFF handle*/
133 BPTR pL=NULL; /*Playlist file pointer*/
134 BOOL masking,print,toFront,printPics;
135 #ifdef __AROS__
136 struct WBStartup *WBenchMsg = NULL;
137 #else
138 extern struct WBStartup *WBenchMsg;
139 #endif
141 char *playListFilename=NULL;
143 /*Variables that have to be global so that ARexx.c can access them*/
144 ButtonTypes rexxAbort=none;
145 /* long arexxSigBit; */
146 UWORD ticksRemaining=0;
147 BOOL loop=FALSE;
148 BYTE specialModes;
150 char *picFilename;
151 char trashBuf[512]; /* A place to dump mask information */
152 char *buf=trashBuf;
154 struct TagItem TagList[]=
156 /* This defines what part of the displayed picture is shown. It's */
157 /* necessary to have a line like this in here in order to get */
158 /* 2.0 autoscrolling to work. */
159 {SA_Overscan,OSCAN_VIDEO},
160 {TAG_DONE,0}
163 char *about1="2View";
164 char *about2="Please";
166 extern struct EasyStruct erError1Line;
167 BOOL cycle=FALSE;
168 UBYTE numColors;
169 UWORD destMap[32];
170 UBYTE numCycleColors;
171 UBYTE rate;
173 /* The assembly-language reader routine */
174 extern int ReadILBM (struct IFFHandle * iff,
175 struct Window * window, ULONG width, ULONG height, UWORD Depth,
176 BOOL Compression, BOOL masking);
178 char **filenames;
179 UWORD numFilenames=0,numSlots;
181 int main(int argc, char ** argv)
183 UWORD c;
184 IPTR args[7] = { 0 };
185 char **filenames = NULL;
186 char curFilename[140];
187 BYTE playList = FALSE; /*True if a playlist is being used, false otherwise*/
189 /*Open the libraries*/
190 IFFParseBase=(struct Library *)OpenLibrary("iffparse.library",0L);
191 if(IFFParseBase==NULL)
193 cleanup();
194 exit(50);
197 IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library",0L);
198 if(IntuitionBase==NULL)
200 cleanup();
201 exit(75);
204 GfxBase=(struct GfxBase *)OpenLibrary("graphics.library",0L);
205 if(GfxBase==NULL)
207 cleanup();
208 exit(85);
211 /*Get the arguments*/
212 if(WBenchMsg==NULL)
214 ParseArgs(args);
216 /*If a playlist filename was provided, store it for later use*/
217 if((char *)args[4]!=NULL)
219 playListFilename=(char *)args[4];
220 playList=TRUE;
222 else /*Otherwise, read the filenames from the command line*/
223 playList=FALSE;
225 /*If a time was provided (in ticks), use it*/
226 if((ULONG *)args[1]!=NULL)
227 ticks=*(ULONG *)args[1]*50;
229 /*If a time was provided (in seconds), use it (overrides ticks)*/
230 if((ULONG *)args[2]!=NULL && *(ULONG *)args[2]!=0)
231 ticks=*(ULONG *)args[2];
233 /*If neither a picture filename, nor a playlist filename, was*/
234 /*specified, print an error and exit.*/
235 if((char **)args[0]==NULL && !playList)
237 printError("Please enter one or more filenames");
238 cleanup();
239 exit(45);
242 /*Determine if we should print the pictures we display or not*/
243 printPics=((BOOL *)args[5]!=NULL);
245 /*Get the pointer to the list of filename*/
246 filenames=(char **)args[0];
248 /*Will we loop back to the beginning once we finish displaying all*/
249 /*the pictures?*/
250 loop=((BOOL *)args[3]!=NULL);
252 else
253 if(WBenchMsg->sm_NumArgs==1)
255 EasyRequest(NULL,&erError1Line,NULL,
256 (ULONG) "2View V1.50 (March 24, 1992)",
257 (ULONG) "Written by Dave Schreiber");
258 cleanup();
259 exit(0);
263 #if 0
264 /* Initialize the ARexx port */
265 arexxSigBit=initRexxPort();
266 if(arexxSigBit==0)
268 cleanup();
269 exit(47);
271 #endif
273 /*Allocate the IFF structure*/
274 iff=AllocIFF();
276 /*If the allocation failed, abort*/
277 if(iff==NULL)
279 printError("Couldn't allocate necessary resources");
280 cleanup();
281 exit(100);
284 /*Run until we run out of filenames, or the user aborts*/
285 while(!ExitFlag)
287 picFilename=curFilename; /*Get a pointer to the filename buffer*/
289 /*Check to see if we're running from Workbench. If so, and the*/
290 /*user provided names of pictures to display (by clicking on their*/
291 /*icons), display those pictures*/
292 if(WBenchMsg!=NULL && WBenchMsg->sm_NumArgs>1)
294 CurrentDir(WBenchMsg->sm_ArgList[1].wa_Lock);
295 picFilename=WBenchMsg->sm_ArgList[1].wa_Name;
297 else if(playList) /*If a playlist is being used*/
299 pL=Open(playListFilename,MODE_OLDFILE); /*Open the playlist*/
301 if(pL==NULL) /*If we couldn't open the playlist, abort*/
303 printError("Can't open playlist");
304 cleanup();
305 exit(199);
308 do /*Loop until we run out of playlist, or get a valid name*/
310 if(FGets(pL,picFilename,140)==NULL) /*If end-of-file*/
311 picFilename=NULL; /*Set as NULL as a flag*/
313 while(picFilename!=NULL && picFilename[0]==0x0A);
315 if(picFilename!=NULL) /*If not NULL, it's a valid filename*/
316 picFilename[strlen(picFilename)-1]='\0'; /*Remove the linefeed*/
318 else /*Otherwise, if a playlist isn't being used, get the current*/
319 picFilename=filenames[0]; /*filename*/
322 /*Loop while the user hasn't requested an abort, and while*/
323 /*there are still files to display*/
324 for(c=0;!ExitFlag && picFilename!=NULL;c++)
326 if((iff->iff_Stream=(IPTR)Open(picFilename,MODE_OLDFILE))==0)
327 { /*If the ILBM file can't be opened...*/
329 /*Print an error...*/
330 printError("Can't open: %s", picFilename);
332 cleanup();
333 exit(200);
336 InitIFFasDOS(iff); /*The IFF file will be read from disk*/
338 OpenIFF(iff,IFFF_READ); /*Make iffparse.library aware of the*/
339 /*ILBM file*/
341 /*Read in the file and display*/
342 ReadAndDisplay(picFilename,iff);
344 CloseIFF(iff); /*Release iffparse's hold on the file*/
346 Close((BPTR)iff->iff_Stream); /*Close the file*/
348 /*Get the next filename, either from Workbench,*/
349 if(WBenchMsg!=NULL)
351 if(WBenchMsg->sm_NumArgs > c+2)
353 CurrentDir(WBenchMsg->sm_ArgList[c+2].wa_Lock);
354 picFilename=WBenchMsg->sm_ArgList[c+2].wa_Name;
356 else
357 picFilename=NULL;
359 else if(playList) /*The playlist*/
363 if(FGets(pL,picFilename,140)==NULL)
364 picFilename=NULL;
366 while(picFilename!=NULL && picFilename[0]==0x0A);
368 if(picFilename!=NULL)
369 picFilename[strlen(picFilename)-1]='\0';
371 else /*or the command line*/
372 picFilename=filenames[c+1];
375 /*We're finished with this run of pictures*/
376 if(playList) /*Close playlist, if open*/
377 Close(pL);
378 pL=NULL;
380 if(!loop && !printPics) /*If the loop flag wasn't given, exit*/
381 ExitFlag=TRUE;
384 /*Time to exit, so close stuff*/
386 cleanup();
387 exit(0); /*And exit*/
390 LONG ilbmprops[] = { ID_ILBM,ID_CMAP,ID_ILBM,ID_BMHD,ID_ILBM,ID_CAMG,
391 ID_ILBM,ID_CRNG,ID_ILBM,ID_DRNG,ID_ILBM,ID_SHAM,
392 ID_ILBM,ID_CTBL };
394 /*Read in an ILBM file and display it*/
395 void ReadAndDisplay(char *filename,struct IFFHandle *iff)
397 int error;
398 UBYTE *bodyBuffer = NULL; /*Pointer to buffer holding 'BODY' chunk info*/
399 ULONG ViewModes; /*Holds the viewmodes flags*/
400 UWORD c;
401 ButtonTypes button;
402 UBYTE cycleTable[32];
403 UBYTE countDown;
405 /*Structures required for IFF parsing*/
406 struct StoredProperty *bmhd,*cmap,*camg,*crng,*drng,*sham,*ctbl;
407 struct ContextNode *bodyContext;
409 /*IntuiMessage...*/
410 struct IntuiMessage *mesg;
412 /*Indentify chunks that should be stored during parse*/
413 /*(in this case, CMAP, BMHD, CRNG, DRNG, CAMG, and SHAM)*/
414 error=PropChunks(iff,ilbmprops,7);
416 /*If there was an error, print a message and return*/
417 if(error!=0)
419 printError("Error in PropChunks() wile reading %s: %d\n",filename,error);
420 ExitFlag=TRUE;
421 return;
424 /*Tell iffparse to stop at a 'BODY' chunk*/
425 error=StopChunk(iff,ID_ILBM,ID_BODY);
427 /*Error handling yet again*/
428 if(error!=0 && error!=-1)
430 printError("Error in StopChunk() wile reading %s: %d\n",filename,error);
431 ExitFlag=TRUE;
432 return;
435 /*Do the actual parsing*/
436 error=ParseIFF(iff,IFFPARSE_SCAN);
438 /*Check for errors yet again*/
439 if(error!=0 && error !=-1)
441 printError("Error in ParseIFF() wile reading %s: %d\n",filename,error);
442 ExitFlag=TRUE;
443 return;
446 /*Get the chunks that were found in the file*/
447 bmhd = FindProp(iff,ID_ILBM,ID_BMHD); /*Bitmap information*/
448 cmap = FindProp(iff,ID_ILBM,ID_CMAP); /*Color map*/
449 camg = FindProp(iff,ID_ILBM,ID_CAMG); /*Amiga viewmode information*/
450 crng = FindProp(iff,ID_ILBM,ID_CRNG); /*Color-cycling ranges*/
451 drng = FindProp(iff,ID_ILBM,ID_DRNG); /*New (DPaint IV) color-cycling*/
452 sham = FindProp(iff,ID_ILBM,ID_SHAM); /*SHAM color tables*/
453 ctbl = FindProp(iff,ID_ILBM,ID_CTBL); /*Macro Paint color table info*/
455 /*Get the descriptor for the BODY chunk*/
456 bodyContext=CurrentChunk(iff);
458 /*If there wasn't a BMHD, CMAP, or BODY chunk, abort*/
459 if (!bmhd | !cmap | !bodyContext)
461 printError ("%s is corrupted or is not in Amiga ILBM format. No %s%s%s%s%s found."
462 , filename
463 , bmhd ? "" : "BMHD"
464 , !bmhd && !cmap ? ", " : ""
465 , cmap ? "" : "CMAP"
466 , (!bmhd || !cmap) && !bodyContext ? ", " : ""
467 , bodyContext ? "" : "BODY"
469 ExitFlag=TRUE;
470 return;
473 /*Prepare to determine screen modes*/
474 newScreen.ViewModes=0;
476 /*If there was a CAMG chunk, use it to get the viewmodes*/
477 if(camg!=NULL)
479 ViewModes=( ((CAMG *)(camg->sp_Data))->viewmodes );
481 if(ViewModes & HAM)
482 newScreen.ViewModes|=HAM;
484 if(ViewModes & EXTRA_HALFBRITE)
485 newScreen.ViewModes|=EXTRA_HALFBRITE;
487 if(ViewModes & LACE)
488 newScreen.ViewModes|=LACE;
490 if(ViewModes & HIRES)
491 newScreen.ViewModes|=HIRES;
495 if(crng==NULL)
497 if(drng==NULL) /*No color cycling*/
498 numCycleColors=0;
499 else /* DPaint-IV--style color cycling*/
500 numCycleColors=interpretDRNG(cycleTable,(DRNG *)(drng->sp_Data),&rate);
501 } else /*DPaint I-III--style color cycling*/
502 numCycleColors=interpretCRNG( cycleTable,(CRNG *)(crng->sp_Data),&rate);
504 if(numCycleColors != 0)
505 cycle=TRUE; /*Start cycling if there are colors to cycle*/
506 else
507 cycle=FALSE;
509 /*Interpret the BMHD chunk*/
510 getBMHD(bmhd->sp_Data);
512 /*Don't open an interlace screen if the image is in SHAM mode*/
513 /*(the Amiga OS doesn't properly handle user copper lists on */
514 /*interlaced screens for some reason)*/
515 if(sham!=NULL)
516 newScreen.ViewModes&=~LACE;
518 /*Open a screen, defined by the BMHD and CAMG chunks*/
519 screen=OpenScreenTagList(&newScreen,TagList);
521 /*If the screen couldn't be opened, abort*/
522 if(screen==NULL)
524 printError("Cannot open screen!");
525 ExitFlag=TRUE;
526 return;
529 /*This more properly centers the screen, for some reason */
530 MoveScreen(screen,1,1);
531 MoveScreen(screen,-1,-1);
533 /*Set the window dimensions from the screen dimensions*/
534 newWindow.Screen=screen;
535 newWindow.Width=newScreen.Width;
536 newWindow.Height=newScreen.Height;
538 /*Open the window*/
539 window=OpenWindow(&newWindow);
541 /*Abort if the window couldn't be opened*/
542 if(window==NULL)
544 printError("Cannot open window!");
546 ExitFlag=TRUE;
547 return;
550 availBytes = bufSize;
551 curPos = bufSize;
553 /*Blank out the pointer*/
554 SetPointer(window,fakePointerData,1,16,0,0);
556 /*Set the screen colors to those provided in the CMAP chunk*/
557 setScreenColors(screen,cmap->sp_Data,newScreen.Depth,destMap,&numColors);
559 /*Uncompress an ILBM and copy it into the bitmap*/
560 if (!ReadILBM (iff, window, window->Width, window->Height,
561 newScreen.Depth,
562 Compression, masking))
564 printError ("Cannot read bitmap!");
566 ExitFlag=TRUE;
567 return;
570 /*Activate the window, and flush any IDCMP message*/
571 ActivateWindow(window);
572 while((mesg=(struct IntuiMessage *)GetMsg(window->UserPort))!=NULL)
573 ReplyMsg((struct Message *)mesg);
575 #if 0
576 /*If this is a SHAM image, setup the copper list appropriately*/
577 if(sham!=NULL)
579 specialModes=SHAM;
580 setupSHAM(screen,(UWORD *)(sham->sp_Data));
582 else
583 /*If this is a MacroPaint image, setup the copper list*/
584 if(ctbl!=NULL)
586 specialModes=MACROPAINT;
587 setupDynHires(screen,(UWORD *)(ctbl->sp_Data));
589 else
590 #endif
591 /* Otherwise, this is a normal ILBM*/
592 specialModes=NORMAL_MODE;
594 /*Bring the screen to the front*/
595 ScreenToFront(screen);
597 /*If the user used the 'print' flag on the command line, print*/
598 /*the picture (but not if this is a SHAM or MacroPaint image)*/
599 if(printPics && specialModes == NORMAL_MODE)
600 dumpRastPort(&(screen->RastPort),&(screen->ViewPort));
602 print=TRUE;
604 /*Close the previous window and screen*/
605 if(prevWindow!=NULL)
606 CloseWindow(prevWindow);
607 if(prevScreen!=NULL)
608 CloseScreen(prevScreen);
610 /*Free the buffer that holds the BODY chunk information*/
611 FreeMem(bodyBuffer,bufSize);
613 /*Store the current window & screen structures, so they can be*/
614 /*closed later*/
615 prevWindow=window;
616 prevScreen=screen;
618 screen=NULL;
619 window=NULL;
621 rexxAbort=none;
622 countDown=rate;
623 if(ticks==0) /*If ticks==0, this means that no delay was specified*/
624 { /*by the user. So just wait for him to click a button*/
625 #if 0
626 int prevTopEdge=prevScreen->TopEdge;
627 #endif
629 while((button=checkButton())==none && rexxAbort==none)
631 /*Wait for 1/60th of a second*/
632 Wait (1L << prevWindow->UserPort->mp_SigBit);
634 #if 0
635 /*Refresh the SHAM copper list if required*/
636 if(prevTopEdge!=prevScreen->TopEdge && sham!=NULL)
638 prevTopEdge=prevScreen->TopEdge;
639 setupSHAM(prevScreen,(UWORD *)(sham->sp_Data));
642 /*Refresh the MacroPaint copper list if required*/
643 if(prevTopEdge!=prevScreen->TopEdge && ctbl!=NULL)
645 prevTopEdge=prevScreen->TopEdge;
646 setupDynHires(prevScreen,(UWORD *)(ctbl->sp_Data));
648 #endif
650 /*If its time to cycle the colors, then cycle them*/
651 if(cycle && numCycleColors!=0 && --countDown==0)
653 cycleColors(cycleTable,destMap,numCycleColors,numColors);
654 countDown=rate;
657 #if 0
658 dispRexxPort();
659 #endif
662 /*Check to see if the user wants to abort*/
663 if(button==menu || rexxAbort==menu)
664 ExitFlag=TRUE;
666 else /*Otherwise, wait for the specified amount of time*/
668 for(c=0;c<ticks;c++)
670 /*Wait 1/60th of a second*/
671 WaitTOF();
673 /*Cycle colors if necessary*/
674 if(cycle && numCycleColors!=0 && --countDown==0)
676 cycleColors(cycleTable,destMap,numCycleColors,numColors);
677 countDown=rate;
680 #if 0
681 dispRexxPort(); /*Check ARexx port*/
682 #endif
684 button=checkButton(); /*After each 25 ticks, check to see if*/
685 if(button==menu || rexxAbort==menu) /*the user wants to abort*/
687 ExitFlag=TRUE;
688 return;
690 if(button==select || rexxAbort==select) /*Or advance prematurely*/
691 return;
696 /*End of 2View.c*/