void Particles<ParticleTraits>::destroy(Iter begin, Iter end,
                                        PatchID_t pid, bool renum)
{
  // Ask the attribute layout to ask all registered attributes
  // to destroy these elements.

  if (destroyMethod_m == DynamicEvents::backfill)
    {
      if (pid < 0) {
	Pooma::IteratorPairDomain<Iter> domain(begin,end);
        attributeLayout_m.destroy(domain, BackFill());
      }
      else {
	Pooma::IteratorPairDomain<const int*> domain(begin,end);
        attributeLayout_m.destroy(domain, pid, BackFill());
      }
    }
  else if (destroyMethod_m == DynamicEvents::shiftup)
    {
      if (pid < 0) {
	Pooma::IteratorPairDomain<Iter> domain(begin,end);
        attributeLayout_m.destroy(domain, ShiftUp());
      }
      else {
	Pooma::IteratorPairDomain<const int*> domain(begin,end);
        attributeLayout_m.destroy(domain, pid, ShiftUp());
      }
    }
  else
    {
      PInsist(false, "Unknown destroy method in Particles::destroy!");
    }

  // If requested, renumber the domain now.
  
  if (renum)
    renumber();
}
ArrayData *ZendArray::dequeue(Variant &value) {
  if (getCount() > 1) {
    ZendArray *a = copyImpl();
    a->dequeue(value);
    return a;
  }
  // To match PHP-like semantics, we invalidate all strong iterators
  // when an element is removed from the beginning of the array
  if (!m_strongIterators.empty()) {
    freeStrongIterators();
  }
  if (m_pListHead) {
    value = m_pListHead->data;
    erase(findForErase(m_pListHead));
    renumber();
  } else {
    value = null;
  }
  // To match PHP-like semantics, the dequeue operation resets the array's
  // internal iterator
  m_pos = (ssize_t)m_pListHead;
  return NULL;
}
main()
{
 LINE *listHead;
 char s[100],string[100],fName[20],reply;
 int index,i,j,flag=1;
 
 system("clear");
 
 listHead=createList();
 
 printf("=========================================Welcome to LinEd==========================================\n\n\n");	 
 
 while(1)
 {
  
  printf(">");
  gets(s);
  index=0;
  
  if(s[0]=='c' && s[1]=='r' && s[2]=='e' && s[3]=='a' && s[4]=='t' && s[5]=='e' && s[6]==' ')
  {
  	
  	if(s[7]=='\0')
  		printf("Provide a <filename> to create <filename>.BAS !\n");
  		
  	else
  	{
  		for(i=0;i<20;i++)
  			fName[i]='\0';
  		
  		for(i=7,j=0;s[i]!='\0';i++,j++)
  			fName[j]=s[i];
  			
  		createFile(fName);
  	}
  }
  
  else if(s[0]=='o' && s[1]=='p' && s[2]=='e' && s[3]=='n' && s[4]==' ')
  {
  	if(listHead->index!=0)
  	{
  		printf("Opening new file will result in loss of data! Are you sure you want to continue?(y/n)\n");
  		scanf("%c",&reply);
  		getchar();
  		
  		if(reply=='n' || reply=='N')
  			continue;
  			
  		if(reply=='y' || reply=='Y')
  		{
  			listHead=destroyList(listHead);
  			listHead=createList();
  		}		
  	}
  		
  	if(s[5]=='\0')
  		printf("Provide a <filename> to open <filename>.BAS !\n");
  		
  	else
  	{
  		for(i=0;i<20;i++)
  			fName[i]='\0';
  		
  		for(i=5,j=0;s[i]!='\0';i++,j++)
  			fName[j]=s[i];
  			
  		listHead=openFile(fName);
  		
  		if(listHead==NULL)
  		{
  			printf("NO such file EXISTS!\n");
  			
  			listHead=createList();
  		}	
  	}
  }
  
  else if(s[0]=='s' && s[1]=='a' && s[2]=='v' && s[3]=='e' && s[4]==' ')
  {
  	 if(s[5]=='\0')
  		printf("Provide a <filename> to save <filename>.BAS !\n");
  		
  	else
  	{
  		for(i=0;i<20;i++)
  			fName[i]='\0';				
  			
  		for(i=5,j=0;s[i]!='\0';i++,j++)
  			fName[j]=s[i];
  			
  		if(!(saveFile(fName,listHead)))
  			printf("NO such file EXISTS!\n");
  	}
  	
  	flag=1;
  }
  
  else if(s[0]=='r' && s[1]=='e' && s[2]=='m' && s[3]=='o' && s[4]=='v' && s[5]=='e' && s[6]==' ')
  {
  	if(s[7]=='\0')
  		printf("Provide a <filename> to remove <filename>.BAS !\n");											
  	
  	else
  	{
  		for(i=0;i<20;i++)
  			fName[i]='\0';
  		
  		for(i=7,j=0;s[i]!='\0';i++,j++)
  			fName[j]=s[i];
  			
  		if(removeFile(fName)==0)
  			printf("NO such file EXISTS!\n");
  	}
  }
  				
  else if(s[0]=='e' && s[1]=='x' && s[2]=='i' && s[3]=='t' && s[4]=='\0')
  {
  	if(flag==1)
  		break;
  		
  	else
  	{
  		printf("Are you sure you want to exit without saving?(y/n)\n");	
  		scanf("%c",&reply);
  		getchar();
  		
  		if(reply=='Y' || reply=='y')
  			break;
  	}
  }			
  
  else if(s[0]>='0' && s[0]<='9')
  {
  	for(i=0;s[i]!='\0' && s[i]!=' ';i++)
  		index=10*index + (s[i]-'0');
  		
  	if(s[i]=='\0')
  		listHead=erase(listHead,index);
  		
  	else if(s[i]==' ')
  	{
  		i++;
  		
  		for(i=i,j=0;s[i]!='\0';i++,j++)
  			string[j]=s[i];
  			
  		string[j]='\0';
  		
  		listHead=insert(listHead,index,string);
  	}
  	
  	flag=0;
  }
  
  else if(s[0]=='r' && s[1]=='\0')
  {
  	listHead=renumber(listHead);
  	
  	flag=0;
  }	
  	
  else if(s[0]=='l' && s[1]=='\0')
  	printList(listHead);				
  
  else
  	printf("UNIDENTIFIED COMMAND INPUT!\n");
 }
 
 listHead=destroyList(listHead);

 system("clear");
 
}
uint8_t                 dmxHeader::open(char *name)
{
                FILE *file;
        
                uint32_t w=720,h=576,fps=0;
                uint8_t  type,progressif;
                char     realname[1024];
                uint32_t dummy;
                uint32_t vPid,vTsId;
                
                char string[MAX_LINE+1]; //,str[1024];;
                uint8_t interlac=0;
                int multi;
                        
                printf("\n  opening d2v file : %s\n",name);
                file=fopen(name,"rt");
                if(!file) 
                        {
                                printf("\n Error !!\n");
                                return 0;
                        }
                
                fgets(string,MAX_LINE,file);        // File header
                if(strncmp(string,"ADMX",4))
                {
                        fclose(file);
                        printf("This is not a mpeg index G2\n");
                         return 0;
                }
        
                
                fgets(string,MAX_LINE,file);
                sscanf(string,"Type     : %c\n",&type); // ES for now
                

                fgets(string,MAX_LINE,file);
              //  sscanf(string,"File     : %s\n",realname);
char *start;
 
                 start=strstr(string,":");
                ADM_assert(start);
                strcpy(realname,start+2);
                int l=strlen(realname)-1;
                while(l&&(realname[l]==0x0a || realname[l]==0x0d))
                {
                        realname[l]=0;
                        l--;
                }
                

                
                fgets (string, MAX_LINE, file);
                sscanf(string,"Append   : %d\n",&multi);

                fgets(string,MAX_LINE,file);
                sscanf(string,"Image    : %c\n",&progressif); // Progressive
                if(progressif=='I') _fieldEncoded=1;
                fgets(string,MAX_LINE,file);
                sscanf(string,"Picture  : %u x %u %u fps\n",&w,&h,&fps); // width...

                fgets(string,MAX_LINE,file);
                sscanf(string,"Nb Gop   : %u \n",&_nbGop); // width...

                fgets(string,MAX_LINE,file);
                sscanf(string,"Nb Images: %u \n",&_nbFrames); // width...

                fgets(string,MAX_LINE,file);
                //fscanf(string,"Nb Audio : %u\n",0); 

                fgets(string,MAX_LINE,file);
                //fprintf(out,"Main aud : %u\n",preferedAudio); 

                fgets(string,MAX_LINE,file);
                sscanf(string,"Streams  : V%X:%X \n",&vTsId,&vPid); 

                printf("For file :%s\n",realname);                
                printf("Pic      :%dx%d, %d fps\n",w,h,fps);
                printf("#Gop     :%lu\n",_nbGop);
                printf("#Img     :%lu\n",_nbFrames);

                
                switch(type)
                {
                        case 'M':
                                {
                                  MPEG_TRACK track;
                                  track.pid=vTsId;
                                  track.pes=vPid;
                                  demuxer=new dmx_demuxerMSDVR(1,&track,0);
                                  break;
                                }
                        case 'T' :
                                {
                                        MPEG_TRACK track;
                                        track.pid=vTsId;
                                        track.pes=vPid;
                                        demuxer=new dmx_demuxerTS(1,&track,0);
                                        break;

                                }
                        case 'P':
                                {
                                        MPEG_TRACK track;
                                        track.pid=0;
                                        track.pes=vPid;
                                        demuxer=new dmx_demuxerPS(1,&track,multi);
                                        break;
                                }
                        case 'E':
                                demuxer=new dmx_demuxerES();
                                break;
                        default:
                                ADM_assert(0);
                }


                if(!demuxer->open(realname))
                {
                                printf("\n cannot open mpeg >%s<\n",realname);
                                delete demuxer;
                                demuxer=NULL;
                                fclose(file);
                                return 0;
                }
                
                _index=new dmxIndex[_nbFrames+1];
                if(!_index)
                        {
                          GUI_Error_HIG(_("Out of memory"), NULL);
                                        ADM_assert(0);
                        }
                memset(_index,0,_nbFrames*sizeof(dmxIndex));
                
                // -------------- Read the file (video)---------------------
                uint32_t read=0;
                uint32_t currentImage=0;
                uint32_t gop,imageStart,imageNb;
                uint64_t abs,rel;
                uint8_t  imgtype;
                uint32_t imgsize;
                uint64_t imgrel,imgabs;
                char *str,*needle;
                
                DIA_working *work=new DIA_working("Opening mpeg..");
                while(read<_nbGop)
                {
                        if(!fgets(string,MAX_LINE,file)) break;
                        if(string[0]!='V') continue;
                        //printf("%s\n",string);
                        // # NGop NImg nbImg Pos rel type:size type:size
                        sscanf(string,"V %u %u %u ",&gop,&imageStart,&imageNb);
                                ADM_assert(read==gop);
                                if(currentImage!=imageStart)
				{
					printf("At gop :%u read:%u, expected image %u, got %u,imagenb:%u\n",gop,read,currentImage,imageStart,imageNb);
					printf("String :%s\n",string);
					ADM_assert(0);
				}
                        
                                
                                // now split the image
                                needle=strstr(string,":");
                                ADM_assert(needle);
                                needle--;
                                // 
                                
                                for(uint32_t i=currentImage;i<currentImage+imageNb;i++)
                                {
                                        str=strstr(needle,":"); 
                                        if(!str)
                                        {
                                                printf("****** Error reading index, index damaged ?****\n");
                                                printf("Gop: %d/%d\n",read,_nbGop);
                                                printf("Img: %d/%d/%d\n",i,i-currentImage,imageNb);
                                                printf("Str:%s\n",string);
                                                printf("****** Error reading index, index damaged ?****\n");
                                                ADM_assert(0);
                                        }
                                        str--;
#ifdef CYG_MANGLING                                        
                                        sscanf(str,"%c:%I64x,%I64x,%x",&imgtype,&imgabs,&imgrel,&imgsize);
#else                                      
                                        sscanf(str,"%c:%llx,%llx,%x",&imgtype,&imgabs,&imgrel,&imgsize);
#endif                                          
                                        if(i>=_nbFrames)         
                                        {
                                                printf("Max frame exceeded :%d/%d\n",i,_nbFrames);
                                                ADM_assert(i<_nbFrames);
                                        }
                                        
                                        _index[i].type=imgtype;
                                        _index[i].size=imgsize;
                                       
                                       
                                        _index[i].absolute=imgabs;
                                        _index[i].relative=imgrel;
                                        

                                        str[1]=' '; // remove :
                                }
                                currentImage+=imageNb;
                                read++;
	                        work->update(  read,_nbGop)   ;
                }
                delete work;
                fclose(file);
                if(!_nbFrames)
                {
                  printf("No image!\n");
                  return 0; 
                }
                        // Drop the last P/B frames as we won't be able to decode them
                        // (last frame must be an I frame for decodeGop to work)
                        uint32_t dropped=0;
                        for(uint32_t y=_nbFrames-1;y>0;y--)
                        {
                                        if(_index[y].type!='B') break;
                                        _nbFrames--;
                                        dropped++;
                        }
                        printf("Dropping %d last B/P frames\n",dropped);                        
                        printf(" Creating start sequence (%llu)..\n",_index[0].absolute);
                        
                        //
                        
                        uint32_t scancode=0;
                        uint32_t count=0,found=0;
                        uint32_t firstPic=_index[0].size;
                        uint8_t *tmp=new uint8_t[firstPic];
                        

                        
                        demuxer->setPos(_index[0].absolute,
                                        _index[0].relative);
                        
                        
                        demuxer->read(tmp,firstPic);
                        _extraDataLen=0;
                        _extraData=NULL;
                        // lookup up gop start
                        while(count<firstPic)
                        {
                                scancode<<=8;
                                scancode+=tmp[count];
                                count++;
                                if(scancode==0x000001b8 || scancode==0x00000100)
                                {
                                        found=1;
                                        break;
                                }                                                       
                        }
                        if(found && count>4)
                        {
                                
                                _extraDataLen=count-4;
                                _extraData=new uint8_t[_extraDataLen];
                                memcpy(_extraData,tmp,_extraDataLen);
                                mixDump(tmp,50);
                                printf("\n");
                                printf("Image :%d, seqLen : %u seq %x %x %x %x\n",
                                        firstPic,
                                        _extraDataLen, _extraData[0],
                                                        _extraData[1],
                                                        _extraData[2],
                                                        _extraData[3]);                                          
                        }
                        else
                        {
                                printf("Mmm cound not find a gop start.....\n");
                        }
                        delete [] tmp;                                                
                   
                         demuxer->setPos(_index[0].absolute,
                                        _index[0].relative);

                                                 
                        if(_fieldEncoded) 
                        {
                                printf("This is field encoded...\n");
                                mergeFields();
                        }
                        _isaudiopresent=0; 
                        _isvideopresent=1; 
                        _videostream.dwScale=1000;
                        _videostream.dwRate=fps;
    
                        _mainaviheader.dwMicroSecPerFrame=(uint32_t)floor(50);;     
                        _videostream.fccType=fourCC::get((uint8_t *)"vids");
                        _video_bih.biBitCount=24;
      
                        _videostream.fccHandler=_video_bih.biCompression=fourCC::get((uint8_t *)"MPEG");;
      
                        _videostream.dwInitialFrames= 0;
                        _videostream.dwStart= 0;
                        _video_bih.biWidth=_mainaviheader.dwWidth=w ;
                        _video_bih.biHeight=_mainaviheader.dwHeight=h;
     
                        _lastFrame=0xffffffff;

                       _videostream.dwLength= _mainaviheader.dwTotalFrames=_nbFrames;     
                       // Dump();                      
                        
                        // switch DTS->PTS
                        if(!renumber())
                        {
                          GUI_Error_HIG(_("MPEG renumbering error"), NULL);
                                return 0;
                        }
                        //Dump();
                        if(type=='P' || type=='T' || type=='M')
                        {
                                // We have potentially some audio
                                // Try to get it
                                dmxAudioStream *tmp;
                                tmp=new dmxAudioStream;
                                if(!tmp->open(name)) delete tmp;
                                else
                                {
                                        _audioStream=tmp;
                                }

                        }
                        
     printf("Mpeg index file successfully read\n");         
     return 1; 
}
void Particles<ParticleTraits>::performDestroy(PatchID_t pid, bool renum)
{
  PatchID_t i, npatch = attributeLayout_m.sizeLocal();

  if (pid < 0)
    {
      for (i = 0; i < npatch; ++i)
	{
	  // skip this patch if there are no destroy requests for it.

	  if (destroyList(i).domain().empty())
	    continue;

	  // do the destroys on this patch

	  if (destroyMethod_m == DynamicEvents::backfill)
	    {
	      attributeLayout_m.destroy(IndirectionList<int>(destroyList(i)),
					i, BackFill());
	    }
	  else if (destroyMethod_m == DynamicEvents::shiftup)
	    {
	      attributeLayout_m.destroy(IndirectionList<int>(destroyList(i)),
					i, ShiftUp());
	    }
	  else
	    {
	      PInsist(false, "Unknown destroy method in Particles::destroy!");
	    }

	  // clear the destroy list for this patch

	  destroyList(i).destroy(destroyList(i).domain());
	}
    }
  else
    {
      // Just destroy for the given patch

      PAssert(pid < npatch);
      i = pid;

      // Do the destroy if we have something to do

      if (!destroyList(i).domain().empty())
	{
	  if (destroyMethod_m == DynamicEvents::backfill)
	    {
	      attributeLayout_m.destroy(IndirectionList<int>(destroyList(i)),
					i, BackFill());
	    }
	  else if (destroyMethod_m == DynamicEvents::shiftup)
	    {
	      attributeLayout_m.destroy(IndirectionList<int>(destroyList(i)),
					i, ShiftUp());
	    }
	  else
	    {
	      PInsist(false, "Unknown destroy method in Particles::destroy!");
	    }

	  // clear the destroy list for this patch
	  
	  destroyList(i).destroy(destroyList(i).domain());
	}
    }

  // if requested, recompute the global domain of the Attributes

  if (renum)
    renumber();
}
Exemple #6
0
int
stabs2acid(Stab *stabs, Biobuf *b)
{
	volatile int fno, i;
	char c, *desc, *p;
	char *volatile dir, *volatile fn, *volatile name;
	Ftypes *f;
	Type *t, *tt;
	StabSym sym;

	dir = nil;
	fno = 0;
	fn = nil;
	for(i=0; stabsym(stabs, i, &sym)>=0; i++){
		if(verbose)
			print("%d %s\n", sym.type, sym.name);
		switch(sym.type){
		case N_SO:
			if(sym.name){
				if(sym.name[0] && sym.name[strlen(sym.name)-1] == '/')
					dir = sym.name;
			}
			denumber();
			fstack = nil;
			fno = 0;
			break;
		case N_BINCL:
			fno++;
			f = mkftypes(dir, sym.name);
			f->down = fstack;
			fstack = f;
			break;
		case N_EINCL:
			if(fstack)
				fstack = fstack->down;
			break;
		case N_EXCL:
			fno++;
			if((f = findftypes(dir, sym.name)) == nil){
				static int cannotprint;
				
				if(cannotprint++ == 0)
					fprint(2, "cannot find remembered %s\n", sym.name);
				continue;
			}
			renumber(f->list, fno);
			break;
		case N_GSYM:
		case N_FUN:
		case N_PSYM:
		case N_LSYM:
		case N_LCSYM:
		case N_STSYM:
		case N_RSYM:
			name = sym.name;
			if(name == nil){
				if(sym.type==N_FUN)
					fn = nil;
				continue;
			}
			if((p = findcolon(name)) == nil)
				continue;
			name = estrndup(name, p-name);
			desc = ++p;
			c = *desc;
			if(c == 'c'){
				fprint(2, "skip constant %s\n", name);
				continue;
			}
			if(setjmp(kaboom)){
				static int cannotparse;
				
				if(cannotparse++ == 0)
					fprint(2, "cannot parse %s\n", name);
				continue;
			}
			t = parsename(desc, &p);
			if(t == nil)
				continue;
			if(*p != 0){
				static int extradesc;
				
				if(extradesc++ == 0)
					fprint(2, "extra desc '%s' in '%s'\n", p, desc);
			}
			/* void is defined as itself */
			if(t->ty==Defer && t->sub==t && strcmp(name, "void")==0){
				t->ty = Base;
				t->xsizeof = 0;
				t->printfmt = '0';
			}
			if(*name==' ' && *(name+1) == 0)
				*name = 0;
			/* attach names to structs, unions, enums */
			if(c=='T' && *name && t->sue){
				t->suename = name;
				if(t->name == nil)
					t->name = name;
				tt = typebysue(t->sue, name);
				tt->ty = Defer;
				tt->sub = t;
			}
			if(c=='t'){
				tt = newtype();
				tt->ty = Typedef;
				tt->name = name;
				tt->sub = t;
			}
			/* define base c types */
			if(t->ty==None || t->ty==Range){
				if(strcmp(name, "char") == 0){
					t->ty = Base;
					t->xsizeof = 1;
					t->printfmt = 'x';
				}
				if(strcmp(name, "int") == 0){
					t->ty = Base;
					t->xsizeof = 4;
					t->printfmt = 'd';
				}
			}
			/* record declaration in list for later. */
			if(c != 't' && c != 'T')
			switch(sym.type){
			case N_GSYM:
				addsymx(nil, name, t);
				break;
			case N_FUN:
				fn = name;
				break;
			case N_PSYM:
			case N_LSYM:
			case N_LCSYM:
			case N_STSYM:
			case N_RSYM:
				addsymx(fn, name, t);
				break;
			}
			break;
		}
if(1) print("");
	}

	printtypes(b);
	dumpsyms(b);
	freetypes();

	return 0;
}
Exemple #7
0
// Normalizes a CFG.  Normalization has a few major components:
// 1) Removing unreachable blocks.
// 2) Computing dominators and post-dominators
// 3) Topologically sorting the blocks into the "Blocks" array.
void SCFG::computeNormalForm() {
  // Clear existing block IDs.
  for (auto &B : Blocks) {
    B->BlockID     = BasicBlock::InvalidBlockID;
    B->PostBlockID = BasicBlock::InvalidBlockID;
  }

  // Allocate new vector to store the blocks in sorted order
  std::vector<BasicBlock*> Blks(Blocks.size(), nullptr);

  // Sort the blocks in post-topological order, starting from the exit.
  unsigned PostUnreachable = Exit->postTopologicalSort(&Blks[0], Blocks.size());

  // Fix up numbers if we have unreachable blocks.
  if (PostUnreachable > 0) {
    for (unsigned i = PostUnreachable, n = Blocks.size(); i < n; ++i)
      Blks[i]->PostBlockID -= PostUnreachable;
  }

  // Compute post-dominators, which improves the topological sort.
  for (unsigned i = PostUnreachable, n = Blocks.size(); i < n; ++i)
    Blks[i]->computePostDominator();

  // Now re-sort the blocks in topological order, starting from the entry.
  unsigned NumUnreachable = Entry->topologicalSort(&Blks[0], Blocks.size());

  // Collect any unreachable blocks, and fix up numbers.
  std::vector<BasicBlock*> Unreachables;
  if (NumUnreachable > 0) {
    for (unsigned i = NumUnreachable, n = Blocks.size(); i < n; ++i)
      Blks[i]->BlockID -= NumUnreachable;

    for (auto &B : Blocks) {
      if (B->BlockID == BasicBlock::InvalidBlockID)
        Unreachables.push_back(B.get());
    }
    assert(Unreachables.size() == NumUnreachable && "Error counting blocks.");
  }

  // Copy sorted blocks back to blocks array.
  int Bid = 0;
  int Nr  = Blocks.size() - NumUnreachable;
  for (; Bid < Nr;) {
    Blocks[Bid].reset( Blks[Bid + NumUnreachable] );
    ++Bid;
  }
  for (unsigned i = 0; i < NumUnreachable; ++i) {
    Blocks[Bid].reset( Unreachables[i] );
    ++Bid;
  }

  // Renumber blocks and instructions now that we have a final sort.
  renumber();

  // Calculate dominators.
  // Compute sizes and IDs for the (post)dominator trees.
  for (auto &B : Blocks) {
    B->computeDominator();
    computeNodeSize(B.get(), &BasicBlock::PostDominatorNode);
  }
  for (auto &B : Blocks.reverse()) {
    computeNodeSize(B.get(), &BasicBlock::DominatorNode);
    computeNodeID(B.get(), &BasicBlock::PostDominatorNode);
  }
  for (auto &B : Blocks) {
    computeNodeID(B.get(), &BasicBlock::DominatorNode);
  }
}
Exemple #8
0
int main(int argc, char *argv[])
{
    int fd[NFILES];
    int outfd;
    int i;
    const char *name;
    const char *output;
    const char *mapset;
    int non_zero;
    struct Range range;
    CELL ncats, max_cats;
    int primary;
    struct Categories pcats;
    struct Colors pcolr;
    char buf[1024];
    CELL result;
    struct GModule *module;
    struct
    {
	struct Option *input, *output;
    } parm;
    struct
    {
	struct Flag *z;
    } flag;

    G_gisinit(argv[0]);

    /* Define the different options */

    module = G_define_module();
    G_add_keyword(_("raster"));
    G_add_keyword(_("statistics"));
    module->description =
	_("Creates a cross product of the category values from "
	  "multiple raster map layers.");

    parm.input = G_define_option();
    parm.input->key = "input";
    parm.input->type = TYPE_STRING;
    parm.input->required = YES;
    parm.input->multiple = YES;
    parm.input->gisprompt = "old,cell,raster";
    sprintf(buf, _("Names of 2-%d input raster maps"), NFILES);
    parm.input->description = G_store(buf);

    parm.output = G_define_standard_option(G_OPT_R_OUTPUT);

    /* Define the different flags */

    flag.z = G_define_flag();
    flag.z->key = 'z';
    flag.z->description = _("Non-zero data only");

    if (G_parser(argc, argv))
	exit(EXIT_FAILURE);

    nrows = Rast_window_rows();
    ncols = Rast_window_cols();

    nfiles = 0;
    non_zero = flag.z->answer;

    for (nfiles = 0; (name = parm.input->answers[nfiles]); nfiles++) {
	if (nfiles >= NFILES)
	    G_fatal_error(_("More than %d files not allowed"), NFILES);
	mapset = G_find_raster2(name, "");
	if (!mapset)
	    G_fatal_error(_("Raster map <%s> not found"), name);
	names[nfiles] = name;
	fd[nfiles] = Rast_open_old(name, mapset);
	Rast_read_range(name, mapset, &range);
	ncats = range.max - range.min;

	if (nfiles == 0 || ncats > max_cats) {
	    primary = nfiles;
	    max_cats = ncats;
	}
    }

    if (nfiles <= 1)
	G_fatal_error(_("Must specify 2 or more input maps"));
    output = parm.output->answer;
    outfd = Rast_open_c_new(output);

    sprintf(buf, "Cross of %s", names[0]);
    for (i = 1; i < nfiles - 1; i++) {
	strcat(buf, ", ");
	strcat(buf, names[i]);
    }
    strcat(buf, " and ");
    strcat(buf, names[i]);
    Rast_init_cats(buf, &pcats);

    /* first step is cross product, but un-ordered */
    result = cross(fd, non_zero, primary, outfd);

    /* print message STEP mesage */
    G_message(_("%s: STEP 2 ..."), G_program_name());

    /* now close all files */
    for (i = 0; i < nfiles; i++)
	Rast_close(fd[i]);
    Rast_close(outfd);

    if (result <= 0)
	exit(0);


    /* build the renumbering/reclass and the new cats file */
    qsort(reclass, result + 1, sizeof(RECLASS), cmp);
    table = (CELL *) G_calloc(result + 1, sizeof(CELL));
    for (i = 0; i < nfiles; i++) {
	mapset = G_find_raster2(names[i], "");
	Rast_read_cats(names[i], mapset, &labels[i]);
    }

    for (ncats = 0; ncats <= result; ncats++) {
	table[reclass[ncats].result] = ncats;
	set_cat(ncats, reclass[ncats].cat, &pcats);
    }

    for (i = 0; i < nfiles; i++)
	Rast_free_cats(&labels[i]);

    /* reopen the output cell for reading and for writing */
    fd[0] = Rast_open_old(output, G_mapset());
    outfd = Rast_open_c_new(output);

    renumber(fd[0], outfd);

    G_message(_("Creating support files for <%s>..."), output);
    Rast_close(fd[0]);
    Rast_close(outfd);
    Rast_write_cats(output, &pcats);
    Rast_free_cats(&pcats);
    if (result > 0) {
	Rast_make_random_colors(&pcolr, (CELL) 1, result);
	Rast_write_colors(output, G_mapset(), &pcolr);
    }

    G_message(_("%ld categories"), (long)result);
    exit(EXIT_SUCCESS);
}