/* Program: SS Author : Kim Moser Date : 12/31/88 System : IBM PC / Borland Turbo-C 2.0 Descrip: Slide Show main program Requires IBM PC or compatible with EGA card. 01/05/89: Removed check for EGA card since it was not recognizing Video-7 VEGA cards. 04/04/89: Changed so that data file is opened once only, and closed only when program exits (this speeds file access). Changed printf's to fprintf's (to stderr). 01/25/90: Cleaned up code to make smaller and faster. Added custom batch mode slide show option (i.e. the ability to specify picture numbers on the command line) 05/27/91: Changed slideshow() function to start at first picture when done. Also, cursor Up/Dn keys now cause hilite bar to wrap. */ #ifndef __COMPACT__ #error SS.C must be compiled under the COMPACT memory model. #endif #include #include #include #include #include #include /*--- Listing 1 ------------------------- HUFF.H -------------- * Author: Anton Kruger, 5 October, 1990 * * Copyright (c) Truda Software * 814 Benton Drive, #34, * Iowa City, IA 52246 * * Description: Include file for the two routines "huff_zip" * and "huff_unzip" that perform file compression * using the Huffman algorithm. --------------------------------------------------------------*/ /* Size of I/O buffers for setvbuff */ #define BUFFER_SIZE 16384 /* Max # of unique symbols in file */ #define MAXSYM 256 /* Max # of nodes in Huffman tree */ #define MAXNOD 2*MAXSYM-1 /* Indicates a left son in tree */ #define LEFT 1 /* Indicates a right son in tree */ #define RIGHT 0 /* Indicates no father, son for node */ #define NONE -1 /* Actual # of unique symbols in file */ int nsymbols; /* Number of characters in input file */ unsigned long nchars; int left_son[MAXNOD]; int right_son[MAXNOD]; int father[MAXNOD]; unsigned long freq[MAXNOD]; unsigned char symbol[MAXSYM]; /* Tests bit "ib" in "byte" */ #define btest(byte,ib) (byte & (1< /* for ULONG_MAX used in build_tree() */ /*--- Listing 3 ------------------------- HUNZIP.C ------------- * Author: Anton Kruger, 5 October, 1990 * * Copyright (c) Truda Software * * Source code may be freely used if authorship is acknowledged. * Object code form may be used freely. * * Description: Contains routines to decompress a file that * has been Huffman encoded with huff_zip.c * * Compilers: Turbo C++ 1.0, MSC 6.0 * * Memory models: Any. * * Compile time switches: * MAIN - if defined, a driver is provided *-------------------------------------------------------------*/ static int huff_unzip(FILE *infile, char *dest); static int huff_unzip(FILE *infile, char *dest) { /* * This routine decodes a file "infile" that has been * compressed by the companion routine, huff_zip.c. * The output is written to the file "outfile". * * Return values: * 1: normal return * 0: error in header */ char byte; int ib,node; int root; /* Location of the root of the Huffman tree */ unsigned long decoded; /* Counts the number of decoded characters */ /* Open I/O files with enlarged buffers for efficiency */ /* Check input file header for characters "CH1" */ if (getc(infile) != 'C') return (0); if (getc(infile) != 'H') return (0); if (getc(infile) != '1') return (0); /* Read Huffman tree from input file */ fread(&nchars,sizeof(nchars),1,infile); fread(&root,sizeof(root),1,infile); fread(left_son,sizeof(left_son[1]),root+1,infile); fread(right_son,sizeof(right_son[1]),root+1,infile); fread(&nsymbols,sizeof(nsymbols),1,infile); fread(symbol,sizeof(symbol[1]),nsymbols,infile); /* Decompress the input file */ decoded = 0; node = root; while(decoded != nchars) { /* Get a byte from compressed file */ byte = (char)getc(infile); /* Scan all bits in byte */ for (ib=7; ib>=0; ib--){ if (btest(byte,ib)) /* bit ib set ?, select left node */ node = left_son[node]; else /* bit ib clear ?, select right node */ node = right_son[node]; /* Have reached a terminal node */ if (left_son[node] == NONE){ /* Write the decoded symbol */ *(dest++) = symbol[node]; /* putc(symbol[node],fp2); */ if (++decoded == nchars) /* Stop if all chars are decoded */ break; else /* Restart decoding at root of tree */ node = root; } } } return(1); } void error(char *s) { fprintf(stderr,"Error: %s\n",s); exit(-1); } /************************************************************************** Screen I/O identifiers **************************************************************************/ #define MAXROW 25 /* Width and height of screen [in characters]; may be changed if video card supports more rows and/or columns */ /* Color definitions [assumed to be unsigned short integers] */ #define BLACK 0 #define BLUE 1 #define GREEN 2 #define CYAN 3 #define RED 4 #define MAGENTA 5 #define BROWN 6 #define LIGHTGREY 7 #define DARKGREY 8 #define LIGHTBLUE 9 #define LIGHTGREEN 10 #define LIGHTCYAN 11 #define LIGHTRED 12 #define LIGHTMAGENTA 13 #define YELLOW 14 #define BRIGHTWHITE 15 /* Types for screen I/O: */ typedef unsigned char scrnbyte; /* Can be considered an unsigned short int */ typedef struct scrnchar { scrnbyte ch, at; /* Character and its attribute [on screen] */ }; #define PLANESIZE 8000 #define PICSIZE (4*PLANESIZE) typedef struct scrnchar far *vid_addr; typedef char far *hires_addr; /* Screen I/O vars */ static scrnbyte fgd = BRIGHTWHITE; /* Default foreground color */ static scrnbyte bgd = BLACK; /* Default background color */ static scrnbyte att = BRIGHTWHITE; /* Default attribute byte */ #define COLOR 0xB8000000L #define MONO 0xB0000000L #define HIRES 0xA0000000L /* BIOS video mode number */ static unsigned char far *CRT_MODE = (unsigned char far *) 0x00400049L; /* Pointer to number of columns */ static unsigned int far *CRT_COL = (unsigned int far *) 0x0040004AL; static vid_addr SCREEN = (vid_addr) COLOR; /* Default */ static hires_addr BITMAP = (hires_addr) HIRES; /* This is what gets added to extended keystrokes to differentiate them from 'normal' keystrokes: */ #define EXTENDED 256 /* Ordinal keystroke values: */ #define ESCKEY 27 #define ENTERKEY 13 #define BACKSPACEKEY 8 #define DELETEKEY (83+EXTENDED) #define UPKEY (72+EXTENDED) #define DOWNKEY (80+EXTENDED) #define LEFTKEY (75+EXTENDED) #define RIGHTKEY (77+EXTENDED) #define HOMEKEY (71+EXTENDED) #define ENDKEY (79+EXTENDED) #define PGUPKEY (73+EXTENDED) #define PGDNKEY (81+EXTENDED) #define F1KEY (59+EXTENDED) #define F2KEY (60+EXTENDED) #define F3KEY (61+EXTENDED) #define F4KEY (62+EXTENDED) #define F5KEY (63+EXTENDED) #define F6KEY (64+EXTENDED) #define F7KEY (65+EXTENDED) #define F10KEY (68+EXTENDED) static void setcolor( int f, int b ); static void setcolor( int f, int b ) /* Creates attribute byte 'att' from 'fgd' and 'bgd' colors */ { /* Are we setting colors that have already been set? */ if ( (fgd != f) || (bgd != b) ) { /* Set foreground and background colors: */ fgd = f; bgd = b; /* Make attribute byte: */ att = (bgd << 4) + fgd; } } #if 0 static int xytoadr( int x, int y ); static int xytoadr( int x, int y ) /* Returns offset from (0,0), of location (x,y) on screen, according to screen width and height #defined */ { return (int) (y-1)* *CRT_COL + (x-1) ); } #endif #define xytoadr(_x,_y) ( (((_y)-1)*(*CRT_COL)) + ((_x)-1) ) static void writeat( int x, int y, char *s ); static void writeat( int x, int y, char *s ) /* Write string 's' at screen location 'x','y' (1,1 = top left). Does NOT check whether string extends past last screen location. */ { vid_addr scrn; /* Points to char/attribute */ scrn = (vid_addr) (SCREEN + xytoadr(x,y)); /* Must be FAR because screen memory is in a different data segment */ while (*s != '\0') { scrn->ch = *s; /* Write character on screen */ (scrn++)->at = att; /* Write attribute and point to next char on screen */ s++; } } static void writeatch( int x, int y, int c ); static void writeatch( int x, int y, int c ) /* Write character 'c' at screen location 'x','y' (1,1 = top left). Note: c must be passed as 'c', NOT "c", because it is a char. */ { static char *s = " "; s[0] = c; writeat( x, y, s ); } static void writeatcenter( int y, char *s ); static void writeatcenter( int y, char *s ) { writeat( (*CRT_COL-strlen(s)+1)/2, y, s ); } static void fillarea( int x1, int y1, int x2, int y2, int f, int b, int c ); static void fillarea( int x1, int y1, int x2, int y2, int f, int b, int c ) /* Fills area of screen bounded by (x1,y1) and (x2,y2) [offset from (1,1)] with char 'c' using foreground and background colors 'f' and 'b' */ { int x, y; /* Local row, col counters */ setcolor( f, b ); for ( y=y1; y<=y2; y++ ) { /* Fill all requested rows */ for ( x=x1; x<=x2; x++ ) { /* Fill all requested columns of current row */ writeatch( x, y, c ); } } } static void clearscr( int f, int b ); static void clearscr( int f, int b ) { fillarea( 1, 1, *CRT_COL, MAXROW, f, b, ' ' ); } static int oldvidmode; static int getvidmode(void); static int getvidmode(void) /* Returns current video mode */ { struct REGPACK r; r.r_ax = 0x0F00; /* 00001111 00000000 */ intr( 0x10, &r ); return (r.r_ax & 0x00FF); /* Returns LOW byte */ } static void setvidmode( int n ); static void setvidmode( int n ) /* Sets video mode to 'n' */ { struct REGPACK r; r.r_ax = n; /* 00000000 nnnnnnnn */ intr( 0x10, &r ); /* rgstr.a.h := 0C; rgstr.a.l := CHR(ORD(TheMode)); LowLevel.VideoInterrupt( rgstr); */ } static void balk( char *s ); static void balk( char *s ) { setvidmode( oldvidmode ); clearscr( BRIGHTWHITE, BLACK ); fprintf( stderr, "SS: %s", s ); exit(1); } /****************************************/ static int keyhit(void); static int keyhit(void) { int ch; return ((ch=getch()) == 0 ? getch() + EXTENDED : ch ); /* Assumes that extended key code is next char returned, and that getch() will NOT wait for a key [i.e. key will be available immediately]. */ } /***************************************/ /* Maximum characters per picture name: */ #define MAX_NAME 18 /* How many rows and cols choices will be divided into: */ #define ROWS 10 #define COLS 4 static struct { int x, y; char *name; unsigned long length; char bw; char *descrip; } pics[] = { 0,0, " Mad ", 9478L, 0, "The Mad magazine cover logo", 0,0, " RCA ", 1874L, 1, "The Radio Corporation of America logo", 0,0, " IBM ", 5764L, 0, "The International Business Machines logo", 0,0, " GAF ", 7064L, 0, "The GAF logo", 0,0, " Face ", 2614L, 1, "A face (any resemblance to persons living or dead is entirely coincidental)", 0,0, " Izod ", 2873L, 1, "A man wearing an Izod shirt and carrying a rifle", 0,0, " Punk ", 14468L, 0, "Diagram of a punk (head detail)", 0,0, " Byte ", 6762L, 0, "The Byte magazine cover logo", 0,0, " Nike ", 6767L, 0, "The Nike sneaker logo", 0,0, " Exxon ", 7110L, 0, "The Exxon logo", 0,0, " Apple ", 5986L, 0, "The Apple logo", 0,0, " Video ", 6665L, 0, "The Video magazine cover logo", 0,0, " Nashua ", 3835L, 1, "The Nashua logo from a Nashua diskette sleeve", 0,0, " Maxell ", 8620L, 0, "The Maxell logo from a Maxell diskette sleeve", 0,0, " Pickle ", 3614L, 1, "A singing pickle (Elvis lives!)", 0,0, " Scream ", 4603L, 1, "Someone (a programmer?) screaming", 0,0, " Madness ", 3459L, 1, "What programming is", 0,0, " Cinelli ", 2017L, 1, "The Cinelli logo", 0,0, " Vampire ", 3455L, 1, "A vampire", 0,0, " Cartoon ", 4956L, 1, "A computer cartoon", 0,0, " Datalife ", 2141L, 1, "The Datalife logo from a Datalife diskette sleeve", 0,0, " dBASE II ", 2549L, 1, "The cover of the dBASE II manual", 0,0, " Citicard ", 8394L, 0, "A Citibank electronic banking card", 0,0, " Formicone ", 3270L, 1, "The Il Formicone logo (this one's for you, Talya)", 0,0, " Commodore ", 6731L, 0, "The Commodore Business Machines logo", 0,0, " Mindscape ", 7231L, 0, "The Mindscape logo from a Mindscape diskette sleeve", 0,0, " Coca Cola ", 7627L, 0, "Korean Coca Cola", 0,0, " Zebrakenko ", 7087L, 0, "The Zebrakenko logo", 0,0, " Mr. Peanut ", 4069L, 1, "Mr. Peanut (not to be confused with Mr. Salty)", 0,0, " Over Board ", 6318L, 0, "Another yellow sign to stick to your car window", 0,0, " Miami Vice ", 6285L, 0, "The Miami Vice logo", 0,0, " The Bandit ", 8093L, 0, "The Skoal Bandit logo (Warning: the Surgeon General has determined...)", 0,0, " Amiga World ", 11424L, 0, "The Amiga World magazine cover logo", 0,0, " Kissbusters ", 9251L, 0, "The WBLS radio station logo", 0,0, " Pig Business ", 2493L, 1, "An unfinished picture of a pig executive", 0,0, " Ghostbusters ", 6395L, 0, "The Ghostbusters logo", 0,0, " American Flag ", 6339L, 0, "The American flag (Pledge of Allegiance not required)", 0,0, " New York Pulse ", 6894L, 0, "The New York Pulse logo", 0,0, " BrainBank, Inc. ", 6587L, 0, "The BrainBank logo", 0,0, " Electronic Arts ", 1823L, 1, "The Electronic Arts logo", 0,0, NULL, 0L, 0, NULL }; #define NORMFG BRIGHTWHITE #define NORMBG BLACK #define HIGHFG YELLOW #define HIGHBG BLUE #define FILENAME "SS.DAT" static void box( int x1, int y1, int x2, int y2, char *s ); static void box( int x1, int y1, int x2, int y2, char *s ) { /* s[0] s[1] ... s[1] s[2] s[3] s[4] s[5] s[6] ... s[6] s[7] */ int i; writeatch( x1, y1, s[0] ); /* Top left corner */ writeatch( x2, y1, s[2] ); /* Top right corner */ writeatch( x1, y2, s[5] ); /* Bottom left corner */ writeatch( x2, y2, s[7] ); /* Bottom right corner */ /* Horizontal lines: */ for (i=x1+1; i=0; row--) { /* All pic rows */ for (plane=0; plane<4; plane++) { setplane( plane ); minus = 1; for (subrow=row; subrow>=0; subrow-=(minus+=1)) memmove( &BITMAP[subrow*40], &buf.planes[plane][row*40], 40 ); } } } static void scrollbuftoscrn(void); static void scrollbuftoscrn(void) { register unsigned char plane; register int row; /* Must be signed */ /* Transfer buffer to video: */ for (row=199; row>=0; row-=2) { /* All pic rows */ for (plane=0; plane<4; plane++) { setplane( plane ); memmove( BITMAP, &buf.planes[plane][row*40], 40*(200-row) ); } if (row==1) row=2; /* Clean-up */ } } static void makerand( int *seq, int n ); static void makerand( int *seq, int n ) /* n == HIGH(s); assumed to be <255 */ { register int count, r, x, y, ndx; unsigned int s[255]; /* Fill s[]: */ for (count=0; count=0; count--) { if (count>0) r=random(count); else r=0; seq[count] = s[r]; if (r0) && (seq[x]==seq[y]) ) balk( "makerand(): duplicate number found.\n" ); } } static void linebuftoscrn(void); static void linebuftoscrn(void) { register unsigned char plane; register int count; int seq[200]; makerand( seq, 200 ); for (count=0; count<200; count++) for (plane=0; plane<4; plane++) { setplane( plane ); memmove( &BITMAP[seq[count]*40], &buf.planes[plane][seq[count]*40], 40 ); } } static void bytebuftoscrn(void); static void bytebuftoscrn(void) { register unsigned char plane; register int i, ndx, q=0; register int count; int seq[64]; makerand( seq, 64 ); for (count=0; count<64; count++) { for (i=0; i<125; i++) { if (++q >= 64) q=0; ndx = i*64 + seq[q]; /* ndx = offset to byte containing pixel */ for (plane=0; plane<4; plane++) { setplane( plane ); BITMAP[ndx] = buf.planes[plane][ndx]; } } } } static void (*xferbuftoscrn)(void) = normbuftoscrn; /* Default */ static int israndom = 0; /* default */ static void showmethod(void); static void showmethod(void) { char *s; static char *tmp[] = { " (Display effect set to 'random') ", " (Display effect set to 'normal') ", " (Display effect set to 'flow') ", " (Display effect set to 'scroll') ", " (Display effect set to 'line') ", "(Display effect set to 'bytefade')" }; setcolor( GREEN, BLACK ); if (israndom) s = tmp[0]; else if (xferbuftoscrn==normbuftoscrn) s = tmp[1]; else if (xferbuftoscrn==flowbuftoscrn) s = tmp[2]; else if (xferbuftoscrn==scrollbuftoscrn) s = tmp[3]; else if (xferbuftoscrn==linebuftoscrn) s = tmp[4]; else if (xferbuftoscrn==bytebuftoscrn) s = tmp[5]; else balk( "Unknown display effect.\n" ); writeatcenter(10, s); } static void pickrandom(void); static void pickrandom(void) /* sets xferbuftoscrn to a random method */ { switch(random(5)) { case 0: xferbuftoscrn=normbuftoscrn; break; case 1: xferbuftoscrn=flowbuftoscrn; break; case 2: xferbuftoscrn=scrollbuftoscrn; break; case 3: xferbuftoscrn=linebuftoscrn; break; case 4: xferbuftoscrn=bytebuftoscrn; break; default: balk( "Unknown random method.\n" ); break; } } static FILE *DATAFILE; static void readpic( int n ); static void readpic( int n ) { unsigned long offset=0; int i, count; /* Determine this picture's offset: */ for (i=0; i, 'Q', or 'X' to return to the main menu, or", "any other key to display the next picture.", "", "You are granted permission to copy this program and distribute it to your", "friends (and enemies) provided that you neither alter it in any way nor", "charge money for it.", NULL }; static void moreinfo(void); static void moreinfo(void) { int row = 2; int i; gotoxy(1,1); clearscr( BRIGHTWHITE, BLACK ); setcolor( LIGHTGREY, BLACK ); box( 1, 1, *CRT_COL, MAXROW, "\332\304\277\263\263\300\304\331" ); setcolor( LIGHTCYAN, BLACK ); for (i=0; info[i] != NULL; i++) writeat( 3, row++, info[i] ); setcolor( YELLOW, BLACK ); writeatcenter( MAXROW-1, "Press any key to return to the slide show." ); keyhit(); } static unsigned long ticks(void); static unsigned long ticks(void) { unsigned long int far *timer = (unsigned long int far *) (0x046C); return *timer; } static unsigned int numpics = 0; /* How many ticks to pause between pictures: */ #define PAUSE 175 static int timeout(void); static int timeout(void) /* Wait PAUSE ticks, or until key hit; returns 0 if timed out, 1 if key pressed, or 2 if exit key pressed. */ { unsigned long newtime; int done = 0; newtime = ticks() + PAUSE; /* Assume we're not within that many seconds of rollover */ while ((ticks() < newtime) && !done) { if (kbhit()) { switch(keyhit()) { case 'Q': case 'q': case 'X': case 'x': case ESCKEY: return 2; /* Exit key pressed */ default: done = 1; /* Key pressed */ break; } } } return 0; /* Timed out */ } static int slideshow(void); static int slideshow(void) /* 'Q' or 'ESCape' quits, any other key for next picture [or wait PAUSE ticks]. Return number of last picture shown */ { int index; while (1) { for (index=0; index"); writeat(48, 6, "F2...F7"); writeat(52, 7, "F10"); writeat(47, 8, ""); setcolor( CYAN, BLACK ); writeat(12, 6, "more information"); writeat(12, 7, "move selection bar"); writeat(12, 8, "view selected picture"); writeat(57, 6, "change display effect"); writeat(57, 7, "view all pictures"); writeat(57, 8, "return to DOS"); #if 0 writeat(1, 6, " F1 more information F2...F7 change display effect" ); writeat(1, 7, "\030 \031 \032 \033 move selection bar F10 view all pictures" ); writeat(1, 8, " view the selected picture return to DOS" ); #endif showmethod(); setcolor( LIGHTGREY, BLACK ); box( 1, 11, *CRT_COL, 11+ROWS+1, boxstr); box( 1, 11+ROWS+1, *CRT_COL, 11+ROWS+3, boxstr); writeat( 1, 11+ROWS+1, "\303"); writeat( *CRT_COL, 11+ROWS+1, "\264"); /* Set screen coords for each picture and display names: */ setcolor( NORMFG, NORMBG ); k = 0; for (i=0; i= 0 ) index -= COLS; else index = (index ? numpics - (COLS+1) + index : numpics-1); break; case DOWNKEY: if ( (index+COLS) < numpics ) index += COLS; else if ((index = (index % COLS) + 1) == COLS) index = 0; break; case LEFTKEY: if (index-- == 0) index = numpics-1; break; case RIGHTKEY: if (++index >= numpics) index=0; break; case HOMEKEY: case PGUPKEY: index=0; break; case ENDKEY: case PGDNKEY: index=numpics-1; break; case F1KEY: /* Help */ moreinfo(); mainmenu(); break; case F2KEY: /* Change xferbuftoscrn() */ israndom=0; xferbuftoscrn = normbuftoscrn; showmethod(); break; case F3KEY: /* Change xferbuftoscrn() */ israndom=0; xferbuftoscrn = flowbuftoscrn; showmethod(); break; case F4KEY: /* scrollbuftoscrn() */ israndom=0; xferbuftoscrn = scrollbuftoscrn; showmethod(); break; case F5KEY: /* linebuftoscrn() */ israndom=0; xferbuftoscrn = linebuftoscrn; showmethod(); break; case F6KEY: /* bytefadebuftoscrn() */ israndom=0; xferbuftoscrn = bytebuftoscrn; showmethod(); break; case F7KEY: /* rndfadebuftoscrn() */ israndom=1; showmethod(); break; case F10KEY: /* View all */ setvidmode( 13 ); index = slideshow(); setvidmode( oldvidmode ); mainmenu(); break; case ENTERKEY: setvidmode( 13 ); readpic(index); keyhit(); setvidmode( oldvidmode ); mainmenu(); break; default: /* Ignore other keys */ update = 0; break; } } while ( (ch!='Q') && (ch!='q') && (ch!='x') && (ch!='X') && (ch!=ESCKEY) ); } static void usage(void); static void usage(void) { fprintf(stderr, "\ Usage: SS [pictures]\nwhere [pictures] is a list of picture numbers, each between 1 and %d\n\ Example: SS 7 15 23 24 27 32 36\n", numpics ); exit(-1); } static void show(int argc, char **argv); static void show(int argc, char **argv) { int index; int i; setvidmode(13); for (i=1; i 0 */ readpic(index-1); if (timeout() == 2) break; /* Exit key pressed */ } } setvidmode(oldvidmode); } void main(int argc, char **argv) { int i, index; SCREEN = ((*CRT_MODE==7) ? (vid_addr) MONO : (vid_addr) COLOR ); /* Determine how many pictures total: */ for (numpics=0; pics[numpics].name != NULL; numpics++); if (argc > 1) { for (i=1; i numpics) || (index <= 0)) usage(); } } if ( (DATAFILE = fopen(FILENAME, "rb")) == NULL ) { fprintf( stderr, "\ Unable to open data file.\n\ For this program to work, the file %s\n\ must be in the current directory.\n", FILENAME ); exit(1); } setvbuf(DATAFILE,NULL,_IOFBF,BUFFER_SIZE); /* Assume success */ randomize(); oldvidmode = getvidmode(); if (argc > 1) { show(argc, argv); } else { main2(); } fclose(DATAFILE); clearscr( BRIGHTWHITE, BLACK ); gotoxy(1, 1); }