00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050 #define DA_REV 1.00
00051
00052 #include "whirlgif.h"
00053 #include <stdlib.h>
00054 #include <string.h>
00055
00056 #define MAXVAL 4100
00057 #define MAXVALP 4200
00058
00059
00060
00061
00062 unsigned int loop=DEFAULT_LOOP,loopcount=0,
00063 use_colormap=DEFAULT_USE_COLORMAP,
00064 debug_flag=0,
00065 verbose=0;
00066
00067 int imagex = 0;
00068 int imagey = 0;
00069 int imagec = 0;
00070
00071
00072 Global global;
00073
00074 GIF_Color gif_cmap[256];
00075
00076 ULONG GIF_Get_Code();
00077 void GIF_Decompress();
00078 void GIF_Get_Next_Entry();
00079 void GIF_Add_To_Table();
00080 void GIF_Send_Data();
00081 void GIF_Clear_Table();
00082 void GIF_Screen_Header();
00083 void GIF_Image_Header();
00084 void GIF_Read_File();
00085 void GIF_Comment();
00086 void GIF_Loop();
00087 void GIF_GCL();
00088 void Calc_Trans();
00089 void set_offset();
00090
00091 GIF_Screen_Hdr gifscrn;
00092 GIF_Image_Hdr gifimage;
00093 GIF_Table table[MAXVALP];
00094
00095 ULONG root_code_size,code_size,CLEAR,EOI,INCSIZE;
00096 ULONG nextab;
00097 ULONG gif_mask[16] = {1,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,0,0};
00098 ULONG gif_ptwo[16] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,0,0};
00099
00100
00101 UBYTE gif_buff[MAXVALP];
00102 ULONG gif_block_size;
00103 int num_bits,bits;
00104
00105 int pic_i;
00106 char gif_file_name[BIGSTRING];
00107 int screen_was_last;
00108
00109
00110 void TheEnd()
00111 {
00112 exit(0);
00113 }
00114
00115 void TheEnd1(p)
00116 char *p;
00117 {
00118 fprintf(stderr,"%s",p);
00119 TheEnd();
00120 }
00121
00122 Usage()
00123 {
00124 fprintf(stderr,"\nUsage: whirlgif [-o outfile] [-loop [count]] [-time #delay]\n");
00125 fprintf(stderr,"\t[ -i listfile] file1 [ -time #delay] file2 ...\n");
00126 fprintf(stderr,"\nTry whirlgif -help for more information\n") ;
00127 exit(0);
00128 }
00129
00130 main(argc,argv)
00131 int argc;
00132 char *argv[];
00133 {
00134 FILE * infile, *fout;
00135 char temp[BIGSTRING];
00136 int ret,i;
00137 int count=0;
00138
00139 fprintf(stderr,"whirlgif Rev %2.2f (C) 1996 by Kevin Kadow\n",DA_REV);
00140 fprintf(stderr," (C) 1991,1992 by Mark Podlipec\n");
00141
00142 if (argc < 2) Usage();
00143
00144
00145 screen_was_last = FALSE;
00146 global.trans.type=TRANS_NONE;
00147 global.trans.valid=FALSE;
00148 global.time=DEFAULT_TIME;
00149 global.left=0;
00150 global.top=0;
00151
00152
00153 fout=stdout;
00154 i = 1;
00155 while( i < argc)
00156 {
00157 char *p;
00158 p = argv[i];
00159
00160 if ( (p[0] == '-') || (p[0] == '+') )
00161 {
00162 ++p;
00163 switch(p[0])
00164 {
00165 case 'v':
00166 verbose++;
00167 i++;
00168 break;
00169
00170 case 'd':
00171 debug_flag++;
00172 i++;
00173 fprintf(stderr,"DEBUG: Debug Level %d\n",debug_flag);
00174 break;
00175
00176 case 'l':
00177 loop=TRUE;
00178 i++;
00179 if(*argv[i] !='-') {
00180
00181 loopcount=atoi(argv[i++]);
00182 if(verbose) fprintf(stderr,"Loop %d times\n",loopcount);
00183 }
00184 else {
00185
00186 loopcount=0;
00187 if(verbose) fputs("Looping enabled\n",stderr);
00188 }
00189 break;
00190
00191 case 'u':
00192 i++;
00193 if(atoi(argv[i]) || !strcmp("true",argv[i])) use_colormap=1;
00194 else use_colormap=0;
00195 i++;
00196 break;
00197
00198 case 't':
00199 i++;
00200 if(!strcmp("time",p)) {
00201
00202 global.time=atoi(argv[i++]);
00203 }
00204 else if(!strncmp("trans",p,4)) Calc_Trans(argv[i++]);
00205 break;
00206
00207 case 'o':
00208 i++;
00209 if(!strncmp("off",p,3)) set_offset(argv[i]);
00210 else
00211
00212 if(NULL==(fout=fopen(argv[i],"w")))
00213 {
00214 fprintf(stderr,"Cannot open %s for output\n",argv[i]);
00215 exit(1);
00216 }
00217 i++;
00218 break;
00219 case 'i':
00220 i++;
00221 if(NULL != (infile=fopen(argv[i],"r"))) {
00222 while(fgets(gif_file_name,BIGSTRING,infile)) {
00223 strtok(gif_file_name,"\n");
00224 if(!count) GIF_Read_File(fout,gif_file_name,1);
00225 else GIF_Read_File(fout,gif_file_name,0);
00226 count++;
00227 }
00228 fclose(infile);
00229 }
00230 else fprintf(stderr,"Cannot read list file %s\n",argv[i]);
00231 i++;
00232 break;
00233
00234 case 'h':
00235 big_Usage() ;
00236 exit(0) ;
00237 break ;
00238
00239 default:
00240 Usage();
00241 exit(0);
00242 break;
00243 }
00244 continue;
00245 }
00246
00247 if(!count) GIF_Read_File(fout,argv[i],1);
00248 else GIF_Read_File(fout,argv[i],0);
00249 count++;
00250 i++;
00251 }
00252
00253 if(count >0)
00254 {
00255 fputc(';',fout);
00256 sprintf(temp,"whirlgif %2.2f (C) kadokev@msg.net. %d images",DA_REV,count);
00257 GIF_Comment(fout,temp);
00258 }
00259
00260 fclose(fout);
00261 fprintf(stderr,"Processed %d files.\n",count);
00262 }
00263
00264
00265
00266
00267
00268
00269
00270
00271 void
00272 GIF_Read_File(fout,fname,first_image)
00273 FILE * fout;
00274 char *fname;
00275 int first_image;
00276 {
00277 FILE *fp;
00278 int ret,i,exit_flag;
00279
00280 if ( (fp=fopen(fname,"r"))==0)
00281 {
00282 fprintf(stderr,"Can't open %s for reading.\n",fname);
00283 TheEnd();
00284 }
00285
00286 GIF_Screen_Header(fp,fout,first_image);
00287
00288
00289 do
00290 {
00291 i=fgetc(fp);
00292 if ( (i<0) && feof(fp))
00293 {
00294 fclose(fp);
00295 TheEnd1("GIF_Read_Header: Unexpected End of File\n");
00296 }
00297 } while(i != ',');
00298
00299 if(first_image)
00300 {
00301
00302 if(loop) GIF_Loop(fout,loopcount);
00303 }
00304 if(global.time||(global.trans.type!=TRANS_NONE && global.trans.valid))
00305 GIF_GCL(fout,global.time);
00306
00307 fputc(',',fout);
00308
00309 GIF_Image_Header(fp,fout,first_image);
00310
00311
00312
00313
00314
00315 GIF_Decompress(fp,fout,0);
00316 fputc(0,fout);
00317
00318 fclose(fp);
00319 }
00320
00321 void GIF_Decompress(fp,fout)
00322 FILE *fp,*fout;
00323 {
00324 register ULONG code,old;
00325
00326 pic_i = 0;
00327 bits=0;
00328 num_bits=0;
00329 gif_block_size=0;
00330
00331 root_code_size=(fgetc(fp) & 0xff); fputc(root_code_size,fout);
00332 GIF_Clear_Table();
00333
00334 code=GIF_Get_Code(fp,fout);
00335
00336 if (code==CLEAR)
00337 {
00338 GIF_Clear_Table();
00339 code=GIF_Get_Code(fp,fout);
00340 }
00341
00342 GIF_Send_Data(code);
00343 old=code;
00344 code=GIF_Get_Code(fp,fout);
00345 do
00346 {
00347 if (table[code].valid==1)
00348 {
00349
00350 GIF_Send_Data(code);
00351 GIF_Get_Next_Entry(fp);
00352 GIF_Add_To_Table(old,code,nextab);
00353 old=code;
00354 }
00355 else
00356 {
00357 GIF_Add_To_Table(old,old,code);
00358 GIF_Send_Data(code);
00359 old=code;
00360 }
00361 code=GIF_Get_Code(fp,fout);
00362 if (code==CLEAR)
00363 {
00364 GIF_Clear_Table();
00365 code=GIF_Get_Code(fp,fout);
00366 GIF_Send_Data(code);
00367 old=code;
00368 code=GIF_Get_Code(fp,fout);
00369 }
00370 } while(code!=EOI);
00371 }
00372
00373 void GIF_Get_Next_Entry(fp)
00374 FILE *fp;
00375 {
00376
00377 while( (table[nextab].valid==1)
00378 &&(nextab<MAXVAL)
00379 ) nextab++;
00380
00381
00382
00383 if (nextab>=MAXVAL)
00384 {
00385 fprintf(stderr,"Error: GetNext nextab=%ld\n",(long)nextab);
00386 fclose(fp);
00387 TheEnd();
00388 }
00389 if (nextab==INCSIZE)
00390 {
00391
00392 code_size++; INCSIZE=(INCSIZE*2)+1;
00393 if (code_size>=12) code_size=12;
00394
00395 }
00396
00397 }
00398
00399
00400
00401
00402
00403 void GIF_Add_To_Table(body,next,index)
00404 register ULONG body,next,index;
00405 {
00406 if (index>MAXVAL)
00407 {
00408 fprintf(stderr,"Error index=%ld\n",(long)index);
00409 }
00410 else
00411 {
00412 table[index].valid=1;
00413 table[index].data=table[next].first;
00414 table[index].first=table[body].first;
00415 table[index].last=body;
00416 }
00417 }
00418
00419 void GIF_Send_Data(index)
00420 register int index;
00421 {
00422 register int i,j;
00423 i=0;
00424 do
00425 {
00426 gif_buff[i]=table[index].data;
00427 i++;
00428 index=table[index].last;
00429 if (i>MAXVAL)
00430 {
00431 fprintf(stderr,"Error: Sending i=%ld index=%ld\n",(long)i,(long)index);
00432 TheEnd();
00433 }
00434 } while(index>=0);
00435
00436
00437 i--;
00438 for(j=i;j>=0;j--)
00439 {
00440
00441 pic_i++;
00442 }
00443 }
00444
00445
00446
00447
00448
00449 void GIF_Init_Table()
00450 {
00451 register int maxi,i;
00452
00453 if (debug_flag) fprintf(stderr,"Initing Table...");
00454 maxi=gif_ptwo[root_code_size];
00455 for(i=0; i<maxi; i++)
00456 {
00457 table[i].data=i;
00458 table[i].first=i;
00459 table[i].valid=1;
00460 table[i].last = -1;
00461 }
00462 CLEAR=maxi;
00463 EOI=maxi+1;
00464 nextab=maxi+2;
00465 INCSIZE = (2*maxi)-1;
00466 code_size=root_code_size+1;
00467 }
00468
00469
00470
00471
00472
00473 void GIF_Clear_Table()
00474 {
00475 register int i;
00476 if (debug_flag) fprintf(stderr,"Clearing Table...\n");
00477 for(i=0;i<MAXVAL;i++) table[i].valid=0;
00478 GIF_Init_Table();
00479 }
00480
00481
00482 ULONG GIF_Get_Code(fp,fout)
00483 FILE *fp,*fout;
00484 {
00485 ULONG code;
00486 register int tmp;
00487
00488 while(num_bits < code_size)
00489 {
00490
00491 if (gif_block_size==0)
00492 {
00493 tmp = fgetc(fp);
00494 if (tmp >= 0 )
00495 {
00496 fputc(tmp,fout);
00497 gif_block_size=(ULONG)(tmp);
00498 }
00499 else TheEnd1("EOF in data stream\n");
00500 }
00501
00502 tmp = fgetc(fp); gif_block_size--;
00503 if (tmp >= 0)
00504 {
00505 fputc(tmp,fout);
00506 bits |= ( ((ULONG)(tmp) & 0xff) << num_bits );
00507 num_bits+=8;
00508 }
00509 else TheEnd1("EOF in data stream\n");
00510 }
00511
00512 code = bits & gif_mask[code_size];
00513 bits >>= code_size;
00514 num_bits -= code_size;
00515
00516
00517 if (code>MAXVAL)
00518 {
00519 fprintf(stderr,"\nError! in stream=%lx \n",(unsigned long)code);
00520 fprintf(stderr,"CLEAR=%lx INCSIZE=%lx EOI=%lx code_size=%lx \n",
00521 (unsigned long)CLEAR,(unsigned long)INCSIZE,(unsigned long)EOI,(unsigned long)code_size);
00522 code=EOI;
00523 }
00524
00525 if (code==INCSIZE)
00526 {
00527 if (code_size<12)
00528 {
00529 code_size++; INCSIZE=(INCSIZE*2)+1;
00530 }
00531 else if (debug_flag) fprintf(stderr,"<13?>");
00532 }
00533
00534 return(code);
00535 }
00536
00537
00538
00539
00540
00541 void GIF_Screen_Header(fp,fout,first_time)
00542 FILE *fp,*fout;
00543 int first_time;
00544 {
00545 int temp,i;
00546
00547 for(i=0;i<6;i++)
00548 {
00549 temp = fgetc(fp);
00550 if(i==4 && temp == '7') temp='9';
00551 if (first_time==TRUE) fputc(temp,fout);
00552 }
00553
00554 gifscrn.width = GIF_Get_Short(fp,fout,first_time);
00555 gifscrn.height = GIF_Get_Short(fp,fout,first_time);
00556 temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout);
00557 gifscrn.m = temp & 0x80;
00558 gifscrn.cres = (temp & 0x70) >> 4;
00559 gifscrn.pixbits = temp & 0x07;
00560
00561 gifscrn.bc = fgetc(fp);
00562 if (first_time==TRUE)
00563 {
00564
00565 fputc(gifscrn.bc,fout);
00566 }
00567
00568 temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout);
00569 imagec=gif_ptwo[(1+gifscrn.pixbits)];
00570
00571 if (verbose)
00572 fprintf(stderr,"Screen: %ldx%ldx%ld m=%ld cres=%ld bkgnd=%ld pix=%ld\n",
00573 (long)gifscrn.width,(long)gifscrn.height,(long)imagec,(long)gifscrn.m,(long)gifscrn.cres,
00574 (long)gifscrn.bc,(long)gifscrn.pixbits);
00575
00576 if(global.trans.type==TRANS_RGB) global.trans.valid=0;
00577 if (gifscrn.m)
00578 {
00579 for(i=0;i<imagec;i++)
00580 {
00581 gif_cmap[i].cmap.red = temp = fgetc(fp);
00582 if (first_time==TRUE) fputc(temp,fout);
00583 gif_cmap[i].cmap.green = temp = fgetc(fp);
00584 if (first_time==TRUE) fputc(temp,fout);
00585 gif_cmap[i].cmap.blue = temp = fgetc(fp);
00586 if (first_time==TRUE) fputc(temp,fout);
00587
00588 if(global.trans.type==TRANS_RGB && !global.trans.valid)
00589 if(global.trans.red==gif_cmap[i].cmap.red &&
00590 global.trans.green==gif_cmap[i].cmap.green &&
00591 global.trans.blue==gif_cmap[i].cmap.blue) {
00592 if(debug_flag>1) fprintf(stderr," Transparent match at %d\n",i);
00593 global.trans.map=i;
00594 global.trans.valid=TRUE;
00595 }
00596 }
00597 }
00598 screen_was_last = TRUE;
00599 }
00600
00601 void GIF_Image_Header(fp,fout,first_time)
00602 FILE *fp,*fout;
00603 int first_time;
00604 {
00605 int temp,tnum,i,r,g,b;
00606
00607 gifimage.left = GIF_Get_Short(fp,fout,1);
00608 if(global.left) gifimage.left+=global.left;
00609
00610 gifimage.top = GIF_Get_Short(fp,fout,1);
00611 if(global.top) gifimage.top+=global.top;
00612
00613 gifimage.width = GIF_Get_Short(fp,fout,1);
00614 gifimage.height = GIF_Get_Short(fp,fout,1);
00615 temp=fgetc(fp);
00616
00617
00618
00619 gifimage.i = temp & 0x40;
00620 gifimage.pixbits = temp & 0x07;
00621 gifimage.m = temp & 0x80;
00622
00623
00624 if (screen_was_last && (first_time==FALSE)) temp |= 0x80;
00625
00626 temp &= 0xf8;
00627 temp |= gifscrn.pixbits;
00628 fputc(temp,fout);
00629
00630 imagex=gifimage.width;
00631 imagey=gifimage.height;
00632 tnum=gif_ptwo[(1+gifimage.pixbits)];
00633 if (verbose)
00634 fprintf(stderr,"Image: %ldx%ldx%ld (%ld,%ld) m=%ld i=%ld pix=%ld \n",
00635 (long)imagex,(long)imagey,(long)tnum,(long)gifimage.left,(long)gifimage.top,
00636 (long)gifimage.m,(long)gifimage.i,(long)gifimage.pixbits);
00637
00638
00639
00640 if (gifimage.m)
00641 {
00642
00643 for(i=0;i<tnum;i++)
00644 {
00645 gif_cmap[i].cmap.red = r = fgetc(fp);
00646 gif_cmap[i].cmap.green = g = fgetc(fp);
00647 gif_cmap[i].cmap.blue = b = fgetc(fp);
00648 fputc(r,fout);
00649 fputc(g,fout);
00650 fputc(b,fout);
00651 }
00652 }
00653 else if (screen_was_last && (first_time==FALSE))
00654 {
00655
00656 for(i=0;i<imagec;i++)
00657 {
00658 fputc(gif_cmap[i].cmap.red ,fout);
00659 fputc(gif_cmap[i].cmap.green,fout);
00660 fputc(gif_cmap[i].cmap.blue ,fout);
00661 }
00662 }
00663 screen_was_last = FALSE;
00664 }
00665
00666
00667
00668
00669
00670 int GIF_Get_Short(fp,fout,first_time)
00671 FILE *fp,*fout;
00672 int first_time;
00673 {
00674 register int temp,tmp1;
00675 temp=fgetc(fp); if (first_time==TRUE) fputc(temp,fout);
00676 tmp1=fgetc(fp); if (first_time==TRUE) fputc(tmp1,fout);
00677 return(temp|( (tmp1) << 8 ));
00678 }
00679
00680 void GIF_Comment(fout,string)
00681 FILE *fout;
00682 char *string;
00683 {
00684 if(!string || !strlen(string))
00685 {
00686
00687 if(debug_flag) fprintf(stderr,"GIF_Comment: invalid argument");
00688 return;
00689 }
00690 fputc(0x21,fout);
00691 fputc(0xF9,fout);
00692 fputs(string,fout);
00693 fputc(0,fout);
00694 }
00695
00696
00697
00698
00699 void GIF_Loop(fout,repeats)
00700 FILE *fout;
00701 unsigned int repeats;
00702 {
00703 UBYTE low=0,high=0;
00704 if(repeats) {
00705
00706 high=repeats / 256;
00707 low=repeats % 256;
00708 }
00709
00710 fputc(0x21,fout);
00711 fputc(0xFF,fout);
00712 fputc(0x0B,fout);
00713 fputs("NETSCAPE2.0",fout);
00714 fputc(0x03,fout);
00715 fputc(0x01,fout);
00716 fputc(0x00,fout);
00717
00718
00719 fputc(low,fout);
00720 fputc(high,fout);
00721
00722 if(verbose) fprintf(stderr,"Wrote loop extension\n");
00723 }
00724
00725
00726
00727
00728 void GIF_GCL(fout,delay)
00729 FILE * fout;
00730 unsigned int delay;
00731 {
00732 UBYTE low=0,high=0,flag=0;
00733 if(delay) {
00734
00735 high=delay / 256;
00736 low=delay % 256;
00737 }
00738
00739 fputc(0x21,fout);
00740 fputc(0xF9,fout);
00741 fputc(0x04,fout);
00742
00743 if(delay) flag |=0x80;
00744 if(global.trans.valid) flag |=0x01;
00745 fputc(flag,fout);
00746
00747 fputc(low,fout);
00748 fputc(high,fout);
00749
00750 fputc(global.trans.map,fout);
00751 fputc(0,fout);
00752 if(debug_flag>1) {
00753 fprintf(stderr,"GCL: delay %d",delay);
00754 if(global.trans.valid) fprintf(stderr," Transparent: %d",global.trans.map);
00755 fputc('\n',stderr);
00756 }
00757 }
00758
00759
00760 void Calc_Trans(string)
00761 char * string;
00762 {
00763 if(string[0] != '#') {
00764 global.trans.type=TRANS_MAP;
00765 global.trans.map=atoi(string);
00766 global.trans.valid=1;
00767 }
00768 else
00769 {
00770
00771 int r,g,b;
00772 string++;
00773 if(3==sscanf(string,"%2x%2x%2x",&r,&g,&b)) {
00774 global.trans.red=r;
00775 global.trans.green=g;
00776 global.trans.blue=b;
00777 global.trans.type=TRANS_RGB;
00778 if(debug_flag) fprintf(stderr,"Transparent RGB=(%x,%x,%x)\n",r,g,b);
00779 }
00780 }
00781 if(debug_flag) fprintf(stderr,"DEBUG:Calc_trans is %d\n",global.trans.type);
00782 }
00783
00784 void set_offset(string)
00785 char * string;
00786 {
00787 char *off_x,*off_y;
00788 off_x=(char *) strtok(string,",");
00789 off_y=(char *)strtok((char *)NULL,",");
00790 if(off_x && off_y) {
00791
00792 global.left=atoi(off_x);
00793 global.top=atoi(off_y);
00794 if(debug_flag>1) fprintf(stderr,"Offset changed to %d,%d\n",
00795 global.left,global.top);
00796 return;
00797 }
00798 if(debug_flag>1) fprintf(stderr,"Couldn't parse offset values.\n");
00799 exit(0);
00800 }
00801
00802 big_Usage()
00803 {
00804 printf("\n"
00805 "whirlgif is a quick program that reads a series of GIF files, and produces\n"
00806 "a single gif file composed of those images.\n"
00807 "\n"
00808 "Usage: whirlgif [-v] [-trans index ] [-time delay] [-o outfile]\n"
00809 " [-loop] [-i incfile] file1 [ -time delay] file2\n"
00810 "\n"
00811 "options:\n"
00812 " -v verbose mode\n"
00813 " -loop [count] add the Netscape 'loop' extension.\n"
00814 " -time delay inter-frame timing.\n"
00815 " -trans index set the colormap index 'index' to be transparent\n"
00816 " -o outfile write the results to 'outfile'\n"
00817 " -i incfile read a list of names from 'incfile'\n"
00818 "\n"
00819 "TIPS\n"
00820 "\n"
00821 "If you don't specify an output file, the GIF will be sent to stdout. This is\n"
00822 "a good thing if you're using this in a CGI script, a very bad thing if you\n"
00823 "run this from a terminal and forget to redirect stdout.\n"
00824 "\n"
00825 "The output file (if any) and -loop _MUST_ be specified before any gif images.\n"
00826 "\n"
00827 "You can specify several delay statements on the command line to change\n"
00828 "the delay between images in the middle of an animation, e.g.\n"
00829 "\n"
00830 " whirlgif -time 5 a.gif b.gif c.gif -time 100 d.gif -time 5 e.gif f.gif\n"
00831 "\n"
00832 "Although it's generally considered to be evil, you can also specify\n"
00833 "several transparency statements on the command line, to change the transparent\n"
00834 "color in the middle of an animation. This may cause problems for some programs.\n"
00835 "\n"
00836 "\n"
00837 "BUGS\n"
00838 " + The loop 'count' is ineffective because Netspcape always loops infinitely.\n"
00839 " + Should be able to specify delay in an 'incfile' list (see next bug).\n"
00840 " + Does not handle filenames starting with a - (hypen), except in 'incfile'.\n"
00841 "\n"
00842 "This program is available from http://www.msg.net/utility/whirlgif/\n"
00843 "-------------------------------------------------------------------\n"
00844 "Kevin Kadow kadokev@msg.net\n"
00845 "Based on 'txtmerge' written by:\n"
00846 "Mark Podlipec podlipec@wellfleet.com\n"
00847 ) ;
00848 exit(0) ;
00849 }