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 }