[Search for users] [Overall Top Noters] [List of all Conferences] [Download this site]

Conference turris::vaxc

Title:VAX C Notes
Notice:READ 1.* BEFORE WRITING; USE KEYWORDS TO FIND EXISTING NOTES
Moderator:DECC::VMCCUTCHEON
Created:Sat Jan 25 1986
Last Modified:Mon Jun 02 1997
Last Successful Update:Fri Jun 06 1997
Number of topics:5611
Total number of notes:27963

5602.0. "sscanf with eight parameters" by FORTY2::BOYES (My karma ran over my dogma) Mon Feb 10 1997 07:05

VAX C V3.2-044

sscanf seems claims to have read seven values when it failed to read the
seventh: or am I coding it wrong?

The code scans a string which may be of one of two formats

year-month-date-hours-mins-vers
or
year-month-date-hours-mins-secs-vers


Year is a four digit integer, the others are two digit integers.
The string ends with a period (its a filename).

     if ((sts=sscanf(name, "%04d%02d%02d%02d%02d%02d%2d.", &year, &month, &date,
                                &hours, &mins, &secs, &vers)) != 7)
         if ((sts1=sscanf(name, "%04d%02d%02d%02d%02d%2d.", &year, &month,&date,
                                                  &hours, &mins, &vers)) != 6)
        return FALSE;

printf("sts=%d, sts1=%d\n",sts,sts1)

m_irr_dbg(printf("Cp1   name is %s\n",name));
m_irr_dbg(printf("year =%d, mins=%d, secs=%d, vers=%d",year,mins,secs,vers));



This produces output
sts=7, sts1=536870912
Cp1   name is 1997020716590588.
year =1997, mins=59, secs=5, vers=0

sts1 was not set and sts is 7, so the first test passed, but vers was not set 
to 88. The code works OK on the shorter form of input (no "seconds"). 

+Mark+  
T.RTitleUserPersonal
Name
DateLines
5602.1Cockpit error?CADSYS::GROSSThe bug stops hereMon Feb 10 1997 08:477
My C Reference Manual (Steele) says that %2d will accept a minimum of ZERO
digits (and a maximum of 2 digits). Therefore, VAXC is behaving correctly
according to the manual. Maybe you could reverse the order of the two scans.
The scan for 6 fields will fail if there are 7 fields present because the first
digit of "vers" will not match the "." in the scan string.

Dave
5602.2cannot reproduce the problemTAVENG::BORISBoris Gubenko, ISEMon Feb 10 1997 10:2482
  Your code seems to be correct (while leading zeros in the field width are
  unnecessary, this is not a bug).

  I was unable to reproduce the problem on OpenVMS VAX V6.1 and V6.2.

  Could you check the scope of the the 'vers' variable ?

  Boris

X.C
===
#include <stdio.h>

main()
{
    char *name = "1997020716590588.";
    int year, month, date, hours, mins, secs, vers;
    int sts, sts1;

     if ((sts=sscanf(name, "%04d%02d%02d%02d%02d%02d%2d.", &year, &month, &date,
                                &hours, &mins, &secs, &vers)) != 7)
         sts1=sscanf(name, "%04d%02d%02d%02d%02d%2d.", &year, &month,&date,
                                                  &hours, &mins, &vers);

     printf("sts=%d, sts1=%d\n",sts,sts1);
     printf("year =%d, mins=%d, secs=%d, vers=%d",year,mins,secs,vers);
}

result on OpenVMS VAX V6.1 with VAXC
====================================

	Image Identification Information

		image name: "VAXCRTL"
		image file identification: "V06-007"
		link date/time:  9-MAR-1994 01:37:39.79


$ say f$getsyi("version")
V6.1    
$ say f$getsyi("hw_name")
VAXstation 4000-VLC
$ cc/vaxc x
$ lin x, sys$input:/opt
sys$share:vaxcrtl/share
$ run x
sts=7, sts1=2146017341
year =1997, mins=59, secs=5, vers=88

result on OpenVMS VAX V6.2 with VAXC
====================================

	Image Identification Information

		image name: "VAXCRTL"
		image file identification: "V06-007"
		link date/time: 22-APR-1995 00:15:52.76

$ say f$getsyi("version")
V6.2    
$ say f$getsyi("hw_name")
VAX 6000-540
$ cc/vaxc x
$ lin x, sys$input:/opt
sys$share:vaxcrtl/share
$ run x
sts=7, sts1=2144683069
year =1997, mins=59, secs=5, vers=88

result on OpenVMS V6.2 Alpha (with DECC)
========================================
$ say f$getsyi("version")
V6.2-1H1
$ say f$getsyi("hw_name")
AlphaServer 2100 4/275
$ cc x
$ lin x, sys$input:/opt
sys$share:decc$shr/share
$ run x
sts=7, sts1=17
year =1997, mins=59, secs=5, vers=88
5602.3This is a reply to .1: clash happensFORTY2::BOYESMy karma ran over my dogmaMon Feb 10 1997 10:4120
Thanks for your input, but reversing the order of the 'if' produces a match on
six fields when there are seven...


     if ((sts1=sscanf(name, "%04d%02d%02d%02d%02d%2d.", &year, &month, &date,
                                                  &hours, &mins, &vers)) != 6)

Produces sts1=6


1997020716270188.

produces

year =1997, mins=27, secs=0, vers=1


(Hang on: does "." need escaping to be interpreted correctly?)

+Mark+
5602.4FORTY2::BOYESMy karma ran over my dogmaMon Feb 10 1997 12:2224
I ran the test program in .2 successfully.

Vers is a local variable to the routine. Worryingly one of the output variables
to the relevant routine is called version, and a module level comment in the
code I am modifying says...

**                      Use stack copy of version in check_file to avoid stack
**                      trampling problems.


After the scanf calls, 


*version = (uint8)vers;

where uint8 is a typedef for unsigned char.


Could it be an aliasing problem? I've tried renaming vers to 'perverse',
and declaring it as  'volatile int' to no effect. Would it be better to declare
year,month...secs,vers as pointers?

+Mark+

5602.5Reply to .4TAVENG::BORISBoris Gubenko, ISEMon Feb 10 1997 13:0213
> 
> I ran the test program in .2 successfully.
> 
  So, this is not a [s]scanf() problem. I'm almost sure, that locale variable
  'vers' contains the right value after sscanf() call.

  Casting 'vers' to unsigned char should not hurt (as long as the value is
  not truncated); declaring year,month... etc as pointers does not seem to fix
  any problem.

  Without seeing the code, it is difficult to say what is wrong.

  Boris
5602.6FORTY2::BOYESMy karma ran over my dogmaMon Feb 10 1997 15:13133
    
    
    Here is the whole routine: m_irr_dbg is an unexciting trace macro.
    The code is supposed to work on multiple patforms: the VMS macro *is*
    set on VMS (logging info in the ifdef is displayed int the trace file).
    
    I'm not expecting anyone to write my project for me, but if anyone 
    can confrim that this is valid (if currently very straggly due to all
    the  debug code) then something context dependednt is happening. Which
    is probably a valid point for this conference.
    
    +Mark+
    
    
extern boolean ir__def_msg_check_file ( name, length, version, time_check )
uint8	*name;
uint32	length;
uint8	*version;
boolean	time_check;
/*	 
**  FUNCTIONAL DESCRIPTION:
**
**	This routine is called to see if the given filename of a deferred
**	message indicates that the message has timed-out, and therefore needs
**	bringing into the MTA.
**


**	The deferred-until time is in the filename followed by 84 or 88
**	indicating the protocol used by the client.
**
**	If the time_check flag is NOT set, then only the name is checked for
**	validity, and not whether its timed-out yet.
**
**      edit 28: Expand the filename to include seconds: that way if two
**      messages are deferred to the same time, they do not have to be faked
**      to have filenames (and hence submission times) one minute apart to
**      ensure unique filenames. Watch out for old format messages, though.
*/	 
{   volatile int perverse;
    int	c,
	year=0,
	month=0,
	date=0,
	hours=0,
	mins=0,
	secs=0,
	sts,sts1;
    time_t  now, deftim;
    uint8   tmputc[20];


perverse=0;
m_irr_dbg(printf("Start of bad code\n"));
m_irr_dbg(printf("1.perverse %x=%x\n",&perverse,perverse));


#if defined (unix) || defined (_WIN32)
    if (sscanf(name, "%04d%02d%02d%02d%02d%02d%02d", &year, &month, &date,
				&hours, &mins, &secs, &perverse) != 7)
        if (sscanf(name, "%04d%02d%02d%02d%02d%02d", &year, &month, &date,
						  &hours, &mins, &perverse) != 6)

	return FALSE;



    if (length != 16)
	if (length !=14)
	return FALSE;
#endif
#ifdef vms
    if ((sts=sscanf(name, "%04d%02d%02d%02d%02d%02d%2d.", &year, &month, &date,
				&hours, &mins, &secs, &perverse)) != 7)
     if ((sts1=sscanf(name, "%04d%02d%02d%02d%02d%2d.", &year, &month, &date,
						  &hours, &mins, &perverse)) != 6)
	return FALSE;
m_irr_dbg(printf("2.perverse %x=%x\n",&perverse,perverse));
m_irr_dbg(printf("sts=%d, sts1=%d\n",sts,sts1));

    if (length != 17)
	if (length !=15)
	return FALSE;

m_irr_dbg(printf("Cp1   name is **%s**\n",name));
m_irr_dbg(printf("year =%d, mins=%d, secs=%d, vers=%d\n",year,mins,secs,perverse)); 
#endif
m_irr_dbg(printf("3.perverse %x=%x\n",&perverse,perverse));

    if ((perverse != 84) && (perverse != 88))
	return FALSE;

m_irr_dbg(printf("Cp2\n"));

    *version = (uint8)perverse;

    if (length > 15) /* i.e. new format, on either platform, so do not have to
                     pretend that the seconds are zero   */
    {
	strncpy(tmputc, name+2,12);
	tmputc[12]=0;
	strcat(tmputc,"Z");
    }
    else 
    {
        strncpy (tmputc, name+2, 10);
        tmputc[10] = 0;
        strcat (tmputc, "00Z");
    }

    if (!ok(mta_cnv_utc_to_secs (strlen(tmputc), tmputc, &deftim)))
	return FALSE;

m_irr_dbg(printf("CP3\n"));


    if (!time_check)
	return TRUE;

    now = mta_time((long*)0);



    if (deftim > now)
	return FALSE;

    m_irr_dbg(printf("CP4\n"));

    return TRUE;
}

    
5602.7FORTY2::BOYESMy karma ran over my dogmaWed Feb 12 1997 05:546
FYI the problem was finally fixed by copying the first 10 bytes to another
string, using sscanf on that string, and then parsing byte by byte through the
remainder of 'name'. It works, but whatever was breaking sscanf may still be
hanging around waiting to break my new code it in a certain context...

+Mark+
5602.8uint8 is a charTAVENG::BORISBoris Gubenko, ISEThu Feb 13 1997 06:34107
> FYI the problem was finally fixed by copying the first 10 bytes to another
> string, using sscanf on that string, and then parsing byte by byte through the
> remainder of 'name'. It works, but whatever was breaking sscanf may still be
> hanging around waiting to break my new code it in a certain context...

  In the code example in .6 you failed to show the calling routine.

  If in the calling routine the 'version' variable, whose address is passed
  to the ir__def_msg_check_file() routine, is declared as int (or short), the
  following assignment

    *version = (uint8)perverse;

  leaves untouched three (for int) or 1 (for short) high order byte(s) of the
  variable.

  printf() for the "%d" conversion specifier fetches the whole int, so you
  can see a garbage value of the 'version' variable after the call to
  ir__def_msg_check_file() routine.

  Attached example, based on your code, which illustrates this behaviour.

  Boris

X.C
===

#include <ints.h>
#include <stdio.h>
#include <string.h>

typedef int boolean;

#define m_irr_dbg(X) X

static boolean func ( name, length, version, time_check )
uint8	*name;
uint32	length;
uint8	*version;
boolean	time_check;
{   volatile int perverse;
    int	c,
	year=0,
	month=0,
	date=0,
	hours=0,
	mins=0,
	secs=0,
	sts,sts1;

perverse=0;
m_irr_dbg(printf("Start of bad code\n"));
m_irr_dbg(printf("1.perverse %x=%x\n",&perverse,perverse));

    if ((sts=sscanf(name, "%04d%02d%02d%02d%02d%02d%2d.", &year, &month, &date,
				&hours, &mins, &secs, &perverse)) != 7)
     if ((sts1=sscanf(name, "%04d%02d%02d%02d%02d%2d.", &year, &month, &date,
					  &hours, &mins, &perverse)) != 6)
	return FALSE;
m_irr_dbg(printf("2.perverse %x=%x\n",&perverse,perverse));
m_irr_dbg(printf("sts=%d, sts1=%d\n",sts,sts1));

    if (length != 17)
	if (length !=15)
	return FALSE;

m_irr_dbg(printf("Cp1   name is **%s**\n",name));
m_irr_dbg(printf("year =%d, mins=%d, secs=%d, vers=%d\n",year,mins,secs,perverse)); 
m_irr_dbg(printf("3.perverse %x=%x\n",&perverse,perverse));

    if ((perverse != 84) && (perverse != 88))
	return FALSE;

    *version = (uint8)perverse;
    printf("in func() version = %08x\n", *version);

    return TRUE;
}

main()
{
    char *name = "1997020716590588.";
    int version;

    func ( (uint8 *)name, strlen(name), &version, TRUE );
    printf("in main() version = %08x\n", version);
}

Result
======

$ cc/ver/noobj _nl0:
DEC C V5.0-003 on OpenVMS Alpha V6.2-1H1
$ cc/stand=vax x.c
$ lin x
$ run x
Start of bad code
1.perverse 7edf7a18=0
2.perverse 7edf7a18=58
sts=7, sts1=2147076576
Cp1   name is **1997020716590588.**
year =1997, mins=59, secs=5, vers=88
3.perverse 7edf7a18=58
in func() version = 00000058
in main() version = 00030058
                    ^^^^^^
                    garbage