undefined reference to `_KEY'

Posted by Toy on Fri 03 Dec 2004 03:44 PM — 9 posts, 30,812 views.

#0
I've spent the past 2 weeks combining the SWRIP and SMAUG1.4a codebases together into one, and I'm down to my last error, just sorta stuck on it. it's coming from fread_vendor:

$ make
make smaug
make[1]: Entering directory `/home/KK and Li Li/smaug/src'
gcc -c -O -g3 -Wall -Wuninitialized -DNOCRYPT -DSMAUG -DTIMEFORMAT -DREGEX shops.c
shops.c: In function `fread_vendor':
shops.c:2378: warning: implicit declaration of function `KEY'
rm -f smaug.exe
gcc -lcrypt -o smaug act_comm.o act_info.o act_move.o act_obj.o act_wiz.o alias.o antitank.o
archery.o backup.o ban.o bank.o bits.o boards.o build.o charge.o clans.o color.o comm.o commen
ts.o const.o db.o editor.o fight.o finger.o grub.o handler.o hashstr.o hotboot.o house.o ibuild
.o ident.o imm_host.o infochan.o interp.o liquids.o magic.o makeobjs.o misc.o mpxset.o mud_comm
.o mud_prog.o newarena.o pfiles.o planes.o player.o polymorph.o quest.o renumber.o reset.o save
.o services.o sharpen.o shops.o skills.o slay.o special.o starmap.o stat_obj.o tables.o track.o
update.o space.o space2.o bounty.o mapper.o swskills.o
shops.o(.text+0x51c7): In function `fread_vendor':
/home/KK and Li Li/smaug/src/shops.c:2423: undefined reference to `_KEY'
shops.o(.text+0x52c0):/home/KK and Li Li/smaug/src/shops.c:2447: undefined reference to `_KEY'
collect2: ld returned 1 exit status
make[1]: *** [smaug] Error 1
make[1]: Leaving directory `/home/KK and Li Li/smaug/src'

/* Write vendor to file */
void fwrite_vendor( FILE *fp, CHAR_DATA *mob )
{
	if ( !IS_NPC( mob ) || !fp )
		return;
  
	fprintf( fp, "#VENDOR\n" );
	fprintf( fp, "Vnum     %d\n", mob->pIndexData->vnum );
  
	if (mob->gold > 0)
		fprintf (fp, "Gold     %d\n",mob->gold);
  
	if ( mob->home )
		fprintf( fp, "Home     %d\n", mob->home->vnum );
  
	if (mob->owner != NULL )
		fprintf (fp, "Owner    %s~\n", mob->owner );

	if ( QUICKMATCH( mob->description, mob->pIndexData->description) == 0 )
  		fprintf( fp, "Description %s~\n", mob->description );
	
	if ( QUICKMATCH( mob->short_descr, mob->pIndexData->short_descr) == 0 )
  		fprintf( fp, "Short	   %s~\n", mob->short_descr );
  
	if ( QUICKMATCH( mob->long_descr, mob->pIndexData->long_descr) == 0 )
  		fprintf( fp, "Long	%s~\n", mob->long_descr );

	fprintf( fp, "Position %d\n", mob->position );
	fprintf( fp, "Flags    %s\n",   print_bitvector(&mob->act) );
	fprintf( fp, "Endvendor\n" );
	return;
}


That's fwrite_vendor. The lines it's calling errors to is in fread_vendor right below:

line 2378:
KEY( "Description", mob->description, fread_string(fp));

line 2423:
KEY( "Flags", mob->act, fread_bitvector(fp));

line 2447:
KEY( "Short", mob->short_descr, fread_string(fp));

Can anyone help me with this?
Toy

#1
/* read vendor from file */
CHAR_DATA *  fread_vendor( FILE *fp )
{
	CHAR_DATA *mob = NULL;
	char *word;
	bool fMatch;
	int inroom = 0;
	ROOM_INDEX_DATA *pRoomIndex = NULL;
	CHAR_DATA *victim;
	CHAR_DATA *vnext;
	char buf [MAX_INPUT_LENGTH];
	char vnum1 [MAX_INPUT_LENGTH];
  
	word   = feof( fp ) ? "Endvendor" : fread_word( fp );
  
	if ( !strcmp(word, "Vnum") )
	{
		int vnum;

		vnum = fread_number( fp );
		mob = create_mobile(  get_mob_index(vnum));
    
		if ( !mob )
		{
			for ( ; ; )
			{
				word   = feof( fp ) ? "Endvendor" : fread_word( fp );
	  
				if ( !strcmp( word, "Endvendor" ) )
					break;
			}
	
			bug("Fread_mobile: No index data for vnum %d", vnum );
			return NULL;
		}
	}
	else
	{
		for ( ; ; )
		{
			word   = feof( fp ) ? "Endvendor" : fread_word( fp );
	  
			if ( !strcmp( word, "Endvendor" ) )
				break;
        }
	
		extract_char(mob, TRUE);
		bug("Fread_vendor: Vnum not found", 0 );
		return NULL;
	}
  
	for ( ; ;) 
	{
       word   = feof( fp ) ? "Endvendor" : fread_word( fp );
       fMatch = FALSE;
       
		switch ( UPPER(word[0]) ) 
	   {
			case '*':
				fMatch = TRUE;
				fread_to_eol( fp );
			break;
	
			case '#':
				if ( !strcmp( word, "#OBJECT" ) )
				{
					fread_obj ( mob, fp, OS_CARRY );
				}
			break;
	
			case 'D':
				KEY( "Description", mob->description, fread_string(fp));
			break;
	
			case 'E':
				if ( !strcmp( word, "Endvendor" ) )
				{
					if ( inroom == 0 )
						inroom = ROOM_VNUM_VENSTOR;
		
					mob->home = get_room_index(inroom);
					pRoomIndex = get_room_index( inroom );
		
					if ( !pRoomIndex )
					{
						pRoomIndex = get_room_index( ROOM_VNUM_VENSTOR );
						mob->home = get_room_index( ROOM_VNUM_VENSTOR );
					}

					mob->in_room = pRoomIndex;
	  
/* the following code is to make sure no more then one player owned vendor
   is in the room - meckteck */
					for ( victim = mob->in_room->first_person; victim; victim = vnext )
					{
						vnext = victim->next_in_room;
					
						if (victim->home != NULL)
						{
							extract_char( victim, TRUE);
							break;
						}
					}

					char_to_room(mob, pRoomIndex);
					sprintf(vnum1,"%d", mob->pIndexData->vnum);
					do_makeshop (mob, vnum1 );
					sprintf (buf, mob->long_descr, mob->owner);
					mob->long_descr =  STRALLOC( buf );
					mob->hit = 10000;
					mob->max_hit = 10000;
					return mob;
				}
			break;
 	
			case 'F':
				KEY( "Flags", mob->act, fread_bitvector(fp));
			break;
	
			case 'G':
				KEY("Gold", mob->gold, fread_number(fp));
			break;
   
			case 'H':
				KEY("Home", inroom, fread_number(fp) );
			break;

			case 'L':
				KEY( "Long", mob->long_descr, fread_string(fp ) );
			break;

			case 'O':
				KEY ("Owner", mob->owner, fread_string (fp) );
			break;
	
			case 'P':
				KEY( "Position", mob->position, fread_number( fp ) );
			break;
	
			case 'S':
				KEY( "Short", mob->short_descr, fread_string(fp));
			break;
		}
	
		if ( !fMatch )
		{
			bug ( "Fread_mobile: no match.", 0 );
			bug ( word, 0 );
		}
	}
	return NULL;
}


Here's fread_vendor if needed.
Toy
Amended on Fri 03 Dec 2004 03:47 PM by Toy
USA #2
Looks like fread_bitvector is the problem. Can you post that function here? Seems like you didn't include a required library.
#3
/* Read an extended bitvector from a file. - Thoric */
EXT_BV fread_bitvector( FILE *fp )
{
    EXT_BV ret;
    int c, x = 0;
    int num = 0;
    
    memset( &ret, '\0', sizeof(ret) );
    	
	for ( ;; )
    {
		num = fread_number(fp);
		
		if ( x < XBI )
	    	ret.bits[x] = num;
			
		++x;
	
		if ( (c=getc(fp)) != '&' )
		{
	    	ungetc(c, fp);
	    	break;
		}
    }

    return ret;
}


Here ya go. Hope this helps.
Toy
Amended on Fri 03 Dec 2004 05:24 PM by Toy
USA #4
gcc -c -O -g3 -Wall -Wuninitialized -DNOCRYPT -DSMAUG -DTIMEFORMAT -DREGEX shops.c
shops.c: In function `fread_vendor':
shops.c:2378: warning: implicit declaration of function `KEY'
There's your problem - shops.c doesn't know what the 'KEY' function is. Go steal it from save.c or wherever it is, or declare its prototype properly so that it knows where to go looking for the function.

(This is one reason why people should compile with g++ and not gcc if anything because it is much stricter and would tell you about this kind of error more explicitly)
#5
Found it in save.c. Figure i'll post it in case someone runs into the same issue anytime.

/* Read in a char. */
#if defined(KEY)
#undef KEY
#endif

#define KEY( literal, field, value )					\
				if ( !strcmp( word, literal ) )	\
				{					\
				    field  = value;			\
				    fMatch = TRUE;			\
				    break;				\
				}



thanks Ksilyan.

Toy
USA #6
Yes, the infamous KEY macro. This is why I eventually just moved the definition to the mud.h file so it would be included everywhere it was ever needed and I didn't need to have 50 copies of it spread all over all my source files.
USA #7
With C++ it could be handled super cleanly using a reference based function; even in C you could do it with pointers but it's a little less elegant. Then you would have the declaration in the header file, but have the definition in only one spot - much, much better program design.

I'm against lumping everything into one header file because:
- it dramatically increases compile time, which is annoying because changing a structure in mud.h requires recompiling everything as opposed to simply the files that depend on that structure
- it flies in the face of program modularity: logical units should be placed separately
- by having such a massive hunk of stuff, it becomes difficult to know what is where, and if it's already there - it's really easy to add redundancy by not finding whatever you were looking for

There are a few other reasons, but I'm too sleepy at the moment to think of them. :-)
#8
HOLY THREAD RESERRECTION!

i wrote this vendor snippet when i was 14 or 15 years old close to 10 years ago.

whoever made this SWRIP stuff stole my code and removed my comment header without my permission and is passing it off as his own. im the "meckteck" still mentioned in one comment line of the code.

hilarious. i love finding old code i wrote on the web. makes me feel special.