29 Mar, 2009, Kayle wrote in the 1st comment:
Votes: 0
So, I'm trying to write a function to parse descriptions for tags, and I'm drawing a blank on how to handle it. An example tag would look like:

[#season winter: The snow is piled up all around.]

I need a way to parse a full room description and grab anything formatted like the example, then parse what's grabbed for everything from the [# to the : and then check to see whether or not that's true, and then if true, tack the part after the : minus the ] into the description. Hmm. Maybe there's an easier way to show this…

Description:

You are standing within the expanse of the famous Darkhaven Square. A
stone statue of occupies the square's center, surrounded by gardens of
shrubbery which enhance the air of serenity and peace here in the center
of the city. The main road lead away in the cardinal directions, while
to the northeast and northwest are forested paths. The spires of a
cathedral can be seen rising to the northwest. [#season winter: The snow is
piled up all around.]


Darkhaven Square
+———–+ You are standing within the expanse of the famous Darkhaven
| : : | Square. A stone statue of occupies the square's center,
| | / | surrounded by gardens of shrubbery which enhance the air of
| :-: : + | serenity and peace here in the center of the city. The main
| \|/ | road lead away in the cardinal directions, while to the
| :-:-@-:-: | northeast and northwest are forested paths. The spires of a
| | | | cathedral can be seen rising to the northwest.
| O : |
| | |
| : |
+———–+
Exits: north east south west up northeast northwest.


During Winter:

Darkhaven Square
+———–+ You are standing within the expanse of the famous Darkhaven
| : : | Square. A stone statue of occupies the square's center,
| | / | surrounded by gardens of shrubbery which enhance the air of
| :-: : + | serenity and peace here in the center of the city. The main
| \|/ | road lead away in the cardinal directions, while to the
| :-:-@-:-: | northeast and northwest are forested paths. The spires of a
| | | | cathedral can be seen rising to the northwest. The snow is
| O : | piled up all around.
| | |
| : |
+———–+
Exits: north east south west up northeast northwest.


So. Any suggestions are more than welcome, C or C++ solutions acceptable.


[Edit:] I have to code to parse the tags, what I don't have is a handle on how to get the tags out of the description for parsing. >.>
29 Mar, 2009, ghasatta wrote in the 2nd comment:
Votes: 0
Sounds like a good time to use regular expressions. Check out boost::regex.

http://www.boost.org/doc/libs/1_38_0/lib...
http://www.onlamp.com/pub/a/onlamp/2006/...

Assuming your descriptions are std::string's, you should be able to then use std::string::replace() to swap out the tag and swap in the evaluated text.
29 Mar, 2009, Kayle wrote in the 3rd comment:
Votes: 0
Well, they're not stored as std::string, I haven't gotten that far in converting Smaug to use the STL. BUt it shouldn't be that difficult to copy them into a string object and then just return string.c_str( );

[Edit:] I should also add that I'm trying not to use external libraries so that I can keep this as close to Smaug as possible in case I decide to release the code at a later date. I don't want to have to require people to use additional libraries.
29 Mar, 2009, Kayle wrote in the 4th comment:
Votes: 0
Figure this might be a little easier if I showed what wasn't working. Also of note, I wrote this shortly after my recent foot surgery, and so I was pretty wasted on pain killers. So if it doesn't make any sense, well, there's the answer. :P
void CharData::sendTagline( const char *text )
{
char output[MSL], tagline[MSL], buf[MSL];
char arg[256], arg2[256];
int value;
bool found = false;
const char *desc;
char *p_output = output, *common;

for( desc = text; *desc; desc++ )
{
/* Reset. */
bGo = false;
value = 0;

if( *desc != '[' )
{
*p_output = *desc;
*++p_output = '\0';
continue;
}

if( *++desc != '#' )
{
*p_output = *–desc;
*++p_output = '\0';
continue;
}

/* Skip beginning '[#'. */
++desc;

/* Read in the tag. */
common = buf;
while( *desc != ':' )
{
if( *desc == '\0' )
{
log_printf( "Error: tag has no parser ':'. Room: %d.", m_InRoom->vnum );
*common = *desc;
break;
}
*common = *desc;
*++common = '\0';
++desc;
}

/* Skip the colon and space ': '. */
desc += 2;

/* Read in the description. */
common = tagline;
while( *desc != ']' )
{
if( *desc == '\0' )
{
log_printf( "Error: tag has no ending ']'. Room: %d.", m_InRoom->vnum );
*common = *desc;
break;
}
*common = *desc;
*++common = '\0';
++desc;
}

/* Separate the arguments. */
common = one_argument( common, arg );
common = one_argument( common, arg2 );

if( is_number( common ) )
value = atoi( common );
else if( strlen( common ) > 0 )
log_printf( "Tag in room %d is odd: %s %s %s.", m_InRoom->vnum, arg, arg2, common );

/* Begin Tag Parsing */
//Snip Tag Parsing
/* End Tag Parsing */

/* Copy in the tagline. */
if( found == true )
{
common = tagline;
while( *common != '\0' )
{
if( strlen( output ) >= ( MAX_STRING_LENGTH - 1 ) )
break;

*p_output = *common;
++common;
*++p_output = '\0';
}
}
}

/* Send the whole thing to the player. */
common = str_dup( strdup( output ) );
print( common );
return;
}
29 Mar, 2009, ghasatta wrote in the 5th comment:
Votes: 0
Er. Based on the function you posted, I'm not sure exactly what you are looking for. You are not sure how to implement your logic for replacing the tag with some evaluated text?

I think there are three parts to what you want to do:
1. Identify/Parse the tag
2. Evaluate the tag, determine text to insert into the description
3. Update the description by removing the tag and inserting the evaluated result.

It sounds like you have a solution for #'s 1 and 3, but not 2? I think #2 is open ended - it depends a lot on what you want to be able to do. Maybe you can let me know if I am understanding you or not.

Re. not using external libraries… It's a tradeoff to be sure, but you are going to have to reinvent certain wheels then.
29 Mar, 2009, Kayle wrote in the 6th comment:
Votes: 0
To start, I've never been really good at working with strings, so doing this type of thing is really one of my weak points that I've been trying to work on, but in this instance, the pain killers didn't help a whole lot.

My goal here is to be able to scan through descriptions looking for these tags, and then pull it aside, evaluate it, and if the tag evaluates to true, then add in the text for the tag. The problem I'm having is isolating the tag itself, everything I've tried hasn't worked, and being that I suck with strings, I figured it would be easiest to enlist the aid of those better with strings then me.

I want to be able to have builders go in and tack on a [#tag value: Message] and then parse out [#tag, value: and Message], then strip off the [#, :, and ] So that just the strings are there. Then I have a switch statement that goes off the first letter of the tag switch( tag[0] ) and once the tag is matched up, it then checks value based on what tag is. In my example, tag is season, and value is winter. So it would check to see that the current season in the mud is winter, and if true, then it adds the message to the description before sending it to the player viewing the room.

The problem I seem to be having is that the code isn't breaking the string up properly, and then it's just not displaying the message whether it should be true or not. The only form of message I've been able to get this to give me in the game is the one on line 73 of the code I posted.
29 Mar, 2009, ghasatta wrote in the 7th comment:
Votes: 0
Kayle said:
The problem I seem to be having is that the code isn't breaking the string up properly, and then it's just not displaying the message whether it should be true or not.
One of the points I was subtly trying to make is that I think it would pay to continue to break down what you are trying to do into smaller and smaller problems to solve. By continuing to drill down I think you will find it easier to deal with each piece. In my previous post I tried to break it into three parts for you.

You can use the c-string function strchr() to search for a character in a string. You can also the the function strstr() to look for a string in another string. Those should be helpful for you in identifying tags and parsing them. Once you know the beginning and ending position of your tag, you can extract it from the string, and pass it to the part of your logic that identifies the contents of the tag.

Here's a good little page on c-strings: http://www.cs.cf.ac.uk/Dave/C/node19.htm...

There's also this from Tyche which seems to be pretty much exactly what you are trying to do. His implementation relies on regular expressions, which I think would make this job much easier on you: http://sourcery.dyndns.org/wiki.cgi?Dyna...
29 Mar, 2009, Kayle wrote in the 8th comment:
Votes: 0
So, I realized, I've been looking at this totally wrong. And after reading the comment I placed at the top of the function, which wasn't included above, I think I need to clarify the bounds of what this is supposed to be doing.

/*
* Function for parsing descriptions for taglines.
* Example: [#dex < 9: You stumble over your own feet.]
* [#gold > 40: You draw the eye of every thief here.]
* [#wis = 10: You're no wiser than normal.]
* [#sun sunset: The sunset through the leaves is nice.]
*/


Now, I don't know if that changes anything, but it's probably worth mentioning.
29 Mar, 2009, ghasatta wrote in the 9th comment:
Votes: 0
Kayle said:
Now, I don't know if that changes anything, but it's probably worth mentioning.

Perhaps it would be helpful for you if you went through the exercise of creating a design in pseudo-code, so you don't have to worry about the implementation details. I'm trying to help you through the process, so I am being a little obtuse, but you'll thank me some day ;)

What do you have to identify for each tag? How many items? How many types of evaluations are there – true/false, numeric comparison…?
29 Mar, 2009, Kayle wrote in the 10th comment:
Votes: 0
I've spent the better part of the last 2 hours reading various explanations of c-style strings. And I'm just not grasping any of it. After a week of beating my head on this, I'm at the point where I don't care how, I just want it to work.

There are two types of tags, those that do numeric comparisons, and those that are just a plain true/false. For example:

switch( UPPER( tag[0] ) )
{
case 'A':
if( !str_cmp( tag, "age" ) )
{
if( val < 0 )
found = false;
else
{
switch( value[0] )
{
case '>':
if( calculateAge( ) > val )
found = true;
break;
case '<':
if( calculateAge( ) < val )
found = true;
break;
case '=':
if( calculateAge( ) == val )
found = true;
break;
default:
found = false;
break;
}
}
}
if( !str_cmp( tag, "align" ) || !str_cmp( tag, "alignment" ) )
{
if( !str_cmp( value, "good") && isGood( ) )
{
found = true;
break;
}
else if( !str_cmp( value, "evil") && isEvil( ) )
{
found = true;
break;
}
else if( !str_cmp( value, "neutral" ) && isNeutral( ) )
{
found = true;
break;
}
}
break;


For the first group, and more abundant group, there are three options, > < and =. For the second, the number of options isn't the same between them, because the options depends on what's being checked against. For alignment, there are 3 options, sun has 4, weather has quite a few, etc.

I'm looking for a simple solution, that's easy for me to understand and work with. I need to find the [#<tag> (value): {Message}] in a description, and then further break that down into the parts for evaluation. I understand what it needs to do, what I don't understand is how to make it do this effectively. I have trouble just reading a tutorial and understanding something, most times I need to see an example, something that relates exactly to what I'm trying to do for me to understand it. Like, I understand what the individual functions do. I get that strchr( ) searches for the first occurrence of the supplied char in the supplied string, and I get that strstr( ) searches for a substring in a given string, but I don't get how to put the two together to do what I'm trying to do. Manipulating strings at this level isn't something I do a lot, so I've never really gotten a lot of practice with it. And when I do attempt it, It generally ends in a disaster, much like this has.

The full function with nothing snipped out to save space is available to view here.

[Edit:] Hrm. My frustration with this whole tagline thing (and strings in general) seems to have shown through more than I would have liked…
29 Mar, 2009, Sandi wrote in the 11th comment:
Votes: 0
What's the advantage of putting them in the desc itself, rather than putting them in extras where they wouldn't require the parsing?

It looks like you might be adding standard lines to many rooms, and I think it would be way easier, either by hand or with regexp, to add a new line, rather than try to append something to an existing line of variable length and content.
29 Mar, 2009, Kayle wrote in the 12th comment:
Votes: 0
The point was so that you could do things like having a different description for the room based on the season, and doing it all in a single description instead of me adding another field to rooms for each season so that people could do seasonal descriptions and talk about flowers blooming in spring, leaves changing color in fall, children building snowmen in winter, etc.

[Edit:] To elaborate a bit:

Name: Darkhaven Square
Area: New Darkhaven Filename: newdark.are
Vnum: 21000 Sector: 1 (city) Light: 0
Room flags: nomob nodropall nosummon
Description:
[#season summer: You are standing within the expanse of the famous Darkhaven Square. A
stone statue of occupies the square's center, surrounded by gardens of
flowers in full bloom which enhance the air of serenity and peace here in
the center of the city. The main road lead away in the cardinal directions, while
to the northeast and northwest are forested paths. The spires of a
cathedral can be seen rising to the northwest.]
[#season spring: You are standing within the expanse of the famous Darkhaven Square. A
stone statue of occupies the square's center, surrounded by gardens of
budding flowers which fill the air with lovely fragrances here in the center
of the city. The main road lead away in the cardinal directions, while
to the northeast and northwest are forested paths. The spires of a
cathedral can be seen rising to the northwest.]
[#season fall: You are standing within the expanse of the famous Darkhaven Square. A
stone statue of occupies the square's center, surrounded by gardens of
wilting flowers as winter fast approaches here in the center of the city.
The main road lead away in the cardinal directions, while to the northeast
and northwest are forested paths of many color falling leaves. The spires of a
cathedral can be seen rising to the northwest.]
[#season winter: You are standing within the frigid expanse of the famous Darkhaven
Square. A stone statue of occupies the square's center, surrounded by an army
of snowmen the children of the city have built here in the center of the city.
The main roads have been cleared away in the cardinal directions, while
to the northeast and northwest are forested paths which are still lightly covered
in snow. The spires of a cathedral can be seen rising to the northwest.]
Extra description keywords: 'sign post signpost'
Permanent affects: None
Characters: Kayle
Objects:
——————- EXITS ——————-
1) n to 21001. Key: -1 Keywords: (none). Flags:
2) e to 21036. Key: -1 Keywords: (none). Flags:
3) s to 21042. Key: -1 Keywords: (none). Flags:
4) w to 21039. Key: -1 Keywords: (none). Flags:
5) u to 21337. Key: -1 Keywords: (none). Flags:
6) ne to 21200. Key: -1 Keywords: (none). Flags:
7) nw to 21163. Key: -1 Keywords: (none). Flags:
29 Mar, 2009, Davion wrote in the 13th comment:
Votes: 0
Are you aware that this snippet already exists? Not sure if you're doing this simply to build your experience with strings or simply trying to get it done, but this snippet not only has what you want, but seems to use the exact same syntax as your'e using.

Edit: Err, after actually looking at the snippet and the code you posted, it seems you're already aware of it :P. Also, post the log messages you're getting. Might help us find the problem (may actually be in the core snippet, so cbunting may need to be aware of the fix)


Ok! After actually reading the code you posted… wow :P. You've definitely butchered some things. Basically what you're trying to do is not insert stuff into the original string from the tag line, what you're doing is making a copy of it, but just altering the copy based on tag lines. The variable "common" is simply just a pointer. In the original snippet common changes which chunk of memory it's point to a few times… kinda hard to catch if you don't really get the whole concept of arrays.

/* Read in the tag. */
common = buf;
while( *desc != ':' )
{
if( *desc == '\0' )
{
log_printf( "Error: tag has no parser ':'. Room: %d.", m_InRoom->vnum );
*common = *desc;
break;
}
*common = *desc;
*++common = '\0';
++desc;
}

/* Skip the colon and space ': '. */
desc += 2;

/* Read in the description. */
common = message;
while( *desc != ']' )
{
if( *desc == '\0' )
{
log_printf( "Error: tag has no ending ']'. Room: %d.", m_InRoom->vnum );
*common = *desc;
break;
}
*common = *desc;
*++common = '\0';
++desc;
}

/* Separate the arguments. */
common = one_argument( common, tag );
common = one_argument( common, value );


This part is where you're most likely having the problem. You'll notice you're grabbing arguments from common. At his point in time, common is pointing to the message, this isn't what you want. Just point common back to buf, and -then- grab the arguments.
29 Mar, 2009, Sandi wrote in the 14th comment:
Votes: 0
I'm not familiar with Smaug, but ROM has 'extra' desc fields, and you can have as many as you want, so you don't have to add anything to the format, just get everyone to agree 'extra desc_night' is used for nightime descs, and have do_look replace or append as appropriate. Just a thought.

Another thought is get rid of the brackets and go from # to #.


BTW, I once had a room with 104 extra descs! Seasons, days, weather… it was a rose garden…. sort of a big clock/calendar, really. :)
29 Mar, 2009, Keberus wrote in the 15th comment:
Votes: 0
Not sure if this will help or not, but have you tried *(++ptr) instead of just *++ptr…I seem to vaguely recall having an issue with my resets because of something seeming simple like that.
29 Mar, 2009, Kayle wrote in the 16th comment:
Votes: 0
Wow. I was really trashed on pain killers then, because I didn't realize it was a snippet. Anyway.

There are no log messages, it's just not showing anything. Correction. changing it to
/* Separate the arguments. */
common = buf;
common = one_argument( common, tag );
common = one_argument( common, value );


Shows something, but absolutely destroys the format of the room:
<32700hp 30000m 30000mv>
[Area name: New Darkhaven] [Area filename: newdark.are]
[Sector Type: city] [Area Flags: nopkill]
[21000][Room Flags: nomob nodropall nosummon]
Darkhaven Square
+———–+ You are standing within the
| | | expanse of the famous Darkhaven Square. A stone statue of
| : | occupies the square's center, surrounded by gardens of budding
+———–+ flowers which fill the air with lovely fragrances here in the
center of the city. The main road lead away in the cardinal directions, while
to the northeast and northwest are forested paths. The spires of a cathedral
can be seen rising to the northwest.
Exits: north east south west up northeast northwest.


What I don't get is how common = buf; works. I don't see anywhere where anything is assigned to buf.
29 Mar, 2009, flumpy wrote in the 17th comment:
Votes: 0
You wanna do something like this:

http://bytes.com/groups/c/223500-how-rep...

i guess you're using some kind of c there? forgive me if i'm wrong


btw common = buf assigns the common pointer back to the start of the buf array.

strings in c are just arrays of chars with a null terminator.

so
char buf[123];

is the same as
char* buf;

buf = malloc(123);


forgive me, my c is a bit rusty :D
29 Mar, 2009, Davion wrote in the 18th comment:
Votes: 0
/* Read in the tag. */
common = buf;
while( *desc != ':' )
{
if( *desc == '\0' )
{
log_printf( "Error: tag has no parser ':'. Room: %d.", m_InRoom->vnum );
*common = *desc;
break;
}
*common = *desc;
*++common = '\0';
++desc;
}


It's assigned right there. common now points to the address of buf, then it reads the tag.

Also

/* Send the whole thing to the player. */
common = str_dup( strdup( output ) );
print( common );
return;


That's so ugly, and a memory leak. Something like this should really use a static buffer :S. I see no reason why you wouldn't. I don't think you'll be using this in multiple calls per statement.
29 Mar, 2009, Kayle wrote in the 19th comment:
Votes: 0
Like:
/* Send the whole thing to the player. */
static char *newDesc;
newDesc = str_dup( output );
return newDesc;
}
29 Mar, 2009, KaVir wrote in the 20th comment:
Votes: 0
Sandi said:
What's the advantage of putting them in the desc itself, rather than putting them in extras where they wouldn't require the parsing?

It saves you having to write out the static parts multiple times (for example, perhaps only one section of the description changes during the night). Creating multiple descriptions can also rapidly get out of hand when you want to take into account lots of different factors - supposing you want morning, afternoon, evening and night, that's 4 descriptions which isn't so bad. But if you also want to add spring, summer, autumn and winter, you've increased that to 16 descriptions. If you also want to factor in calm weather, windy weather, rainy weather, stormy weather, etc, the static descriptions soon become more effort than they're worth.

Of course I'm heavily biased, as I'm a big fan of dynamic descriptions and use them extensively for loads of things.
Random Picks
0.0/57