Thread overview
sscanf() and string "reads" via %s?
Apr 01, 2005
AEon
Apr 01, 2005
Regan Heath
Apr 01, 2005
AEon
Apr 02, 2005
AEon
Apr 02, 2005
AEon
Apr 02, 2005
AEon
Apr 02, 2005
Ben Hinkle
Apr 02, 2005
AEon
Apr 02, 2005
Regan Heath
April 01, 2005
Does anyone know how to make this work properly? The int's are fine, but I can't seem to get the fragger/fragged vars to work properly:

<code>
int min, sec, pl1, pl2, mod;
char[] fragger, fragged;

char[] logline = " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA";
printf("    Logline: \"%.*s\"\n", logline);

sscanf( logline, "%d:%d Kill: %d %d %d: %s killed %s by MOD_PLASMA",
	&min,&sec,&pl1,&pl2,&mod,&fragger,&fragged );

printf("    Min %d, Sec: %d, Pl1 %d, Pl2: %d, Mod: %2d, Fragger '%.*s', Fragged '%.*s' \n",
	min,sec,pl1,pl2,mod,fragger,fragged);
</code>

Yields:

    Logline: " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA"
    Min 59, Sec: 58, Pl1 0, Pl2: 3, Mod:  8, Fragger 'Error: Access Violation

AEon
April 01, 2005
On Fri, 01 Apr 2005 06:37:22 +0200, AEon <aeon2001@lycos.de> wrote:
> Does anyone know how to make this work properly? The int's are fine, but I can't seem to get the fragger/fragged vars to work properly:
>
> <code>
> int min, sec, pl1, pl2, mod;
> char[] fragger, fragged;
>
> char[] logline = " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA";
> printf("    Logline: \"%.*s\"\n", logline);
>
> sscanf( logline, "%d:%d Kill: %d %d %d: %s killed %s by MOD_PLASMA",
> 	&min,&sec,&pl1,&pl2,&mod,&fragger,&fragged );
>
> printf("    Min %d, Sec: %d, Pl1 %d, Pl2: %d, Mod: %2d, Fragger '%.*s', Fragged '%.*s' \n",
> 	min,sec,pl1,pl2,mod,fragger,fragged);
> </code>
>
> Yields:
>
>      Logline: " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA"
>      Min 59, Sec: 58, Pl1 0, Pl2: 3, Mod:  8, Fragger 'Error: Access Violation

Remember, sscanf is a C function, it expects a C "char*" not a D "char[]".
Try:

import std.c.stdio;

void main()
{
	int min, sec, pl1, pl2, mod;
	char[] fragger, fragged;

	char[] logline = " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA";
	printf("    Logline: \"%.*s\"\n", logline);

	//guess at length required
	fragger.length = 100;
	fragged.length = 100;
	
	sscanf( logline, "%d:%d Kill: %d %d %d: %s killed %s by MOD_PLASMA",
	&min,&sec,&pl1,&pl2,&mod,fragger.ptr,fragged.ptr );

	printf("    Min %d, Sec: %d, Pl1 %d, Pl2: %d, Mod: %2d, Fragger '%.*s', Fragged '%.*s' \n",
	min,sec,pl1,pl2,mod,fragger,fragged);
}

Regan
April 01, 2005
Regan Heath wrote:

>     sscanf( logline, "%d:%d Kill: %d %d %d: %s killed %s by MOD_PLASMA",
>     &min,&sec,&pl1,&pl2,&mod,fragger.ptr,fragged.ptr );

Thanx... sigh, I had skimmed the metion of .ptr, but had completely forgotten how the naming for C strings works.

Works wonderfully...

Ironically with the above I can save tons of coding I did to manually take the log lines appart. Live and learn or so... :)

AEon
April 02, 2005
Regan Heath wrote:
> import std.c.stdio;
> 
> void main()
> {
>     int min, sec, pl1, pl2, mod;
>     char[] fragger, fragged;
> 
>     char[] logline = " 59:58 Kill: 0 3 8: pezen killed AEon by MOD_PLASMA";
>     printf("    Logline: \"%.*s\"\n", logline);
> 
>     //guess at length required
>     fragger.length = 100;
>     fragged.length = 100;
>         sscanf( logline, "%d:%d Kill: %d %d %d: %s killed %s by MOD_PLASMA",
>     &min,&sec,&pl1,&pl2,&mod,fragger.ptr,fragged.ptr );
> 
>     printf("    Min %d, Sec: %d, Pl1 %d, Pl2: %d, Mod: %2d, Fragger '%.*s',  Fragged '%.*s' \n",
>     min,sec,pl1,pl2,mod,fragger,fragged);
> }

As mentioned in the other post, the above you suggested works wonderfully, but then I wanted to use the sscanf template to print to reconstruct the orgininal log line (primarily to test the sscanf scans):

char[] line = " 59:58 Kill: 0 3 8: pezen killed AEon by ROCKET_SPLASH";
char[] post = " by MOD_ROCKET_SPLASH";

char[] fragger, fragged;
fragger.length = line.length;	// Important! Safe case!
fragged.length = line.length;

// Generate proper frag line template on the fly
// e.g. "%d:%d Kill: %d %d %d: %s killed %s by MOD_ROCKET_SPLASH"
char[] templ = "%d:%d Kill: %d %d %d: %s killed %s"~post;
sscanf( line, templ, &min,&sec,&pl1,&pl2,&mod, fragger.ptr,fragged.ptr );

// (1)
fragger = format("%s",fragger).dup;
fragged = format("%s",fragged).dup;
		
// (2)
writefln("  %s", format(templ, min,sec,pl1,pl2,mod, fragger,fragged) );

printf("    Min %d, Sec: %d, Pl1 %d, Pl2: %d, Mod: %2d, Fragger '%.*s', Fragged '%.*s' Template '%.*s'\n", min, sec, pl1, pl2, mod, fragger, fragged, templ);


The sscanf works. But when I tried to use the templ in a printf like:

	printf(templ,    min,sec,pl1,pl2,mod, fragger,fragged );

it did not work.

I then tried (2)

writefln("  %s", format(templ, min,sec,pl1,pl2,mod, fragger,fragged) );

using format. That almost works perfectly. Only that fragger and fragged have trailing \0 filling up the strings upto the length line.length.


So the question is how do I turn the C strings fragger/fragged back to proper char[]? I tried something like (1) but that failed.


I find it very strange that the C strings seem to behave like normal D strings printf(" ... %.*s", fragger), and in other cases like C strings.
April 02, 2005
Even when trying to fix the fragger.ptr to a non-zero terminating string manually, the below fails.

char[] fr;	// = format("%s",fragger).dup;
char[] fd;	// = format("%s",fragged).dup;
foreach( int i, char Ch; fragger )
	if( Ch == '\0' )
        {
		fr = fragger[0..i];
		fr.length = i;
	}					
				
foreach( int i, char Ch; fragged )
        if( Ch == '\0' )
	{
		fd = fragged[0..i];
		fd.length = i;
 	}
		
writefln("    %s", format(templ, min,sec,pl1,pl2,mod, fr,fd) );

fr and fd, keep all the trailing \0...hmpf.

AEon
April 02, 2005
AEon wrote:
> Even when trying to fix the fragger.ptr to a non-zero terminating string manually, the below fails.
> 
> char[] fr;    // = format("%s",fragger).dup;
> char[] fd;    // = format("%s",fragged).dup;
> foreach( int i, char Ch; fragger )
>     if( Ch == '\0' )
>         {
>         fr = fragger[0..i];
>         fr.length = i;
>     }                                  foreach( int i, char Ch; fragged )
>         if( Ch == '\0' )
>     {
>         fd = fragged[0..i];
>         fd.length = i;
>      }
>        writefln("    %s", format(templ, min,sec,pl1,pl2,mod, fr,fd) );
> 
> fr and fd, keep all the trailing \0...hmpf.

Finally, this at least seems to work:

char[] fr;	// = format("%s",fragger).dup;
char[] fd;	// = format("%s",fragged).dup;
foreach( int i, char Ch; fragger )
	if( Ch != '\0' )
		fr ~= Ch;
					
foreach( int i, char Ch; fragged )
	if( Ch != '\0' )
		fd ~= Ch;

writefln("    %s", format(templ, min,sec,pl1,pl2,mod, fr,fd) );


But I doubt this is the way one handles C strings.

AEon
April 02, 2005
> So the question is how do I turn the C strings fragger/fragged back to proper char[]? I tried something like (1) but that failed.

fragger = fragger[0 .. strlen(fragger.ptr)];
you can find strlen in std.string.


April 02, 2005
Ben Hinkle wrote:

>>So the question is how do I turn the C strings fragger/fragged back to proper char[]? I tried something like (1) but that failed.
> 
> 
> fragger = fragger[0 .. strlen(fragger.ptr)];
> you can find strlen in std.string. 

Thanx, works just fine.

AEon
April 02, 2005
On Fri, 1 Apr 2005 20:53:02 -0500, Ben Hinkle <ben.hinkle@gmail.com> wrote:
>> So the question is how do I turn the C strings fragger/fragged back to
>> proper char[]? I tried something like (1) but that failed.
>
> fragger = fragger[0 .. strlen(fragger.ptr)];
> you can find strlen in std.string.

Will this also work:
fragger.length = strlen(fragger.ptr);

Regan