Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

sscanf seems o loop forever

Status
Not open for further replies.

riteshshah

Programmer
Feb 8, 2005
12
US
Hi Guys,

Been looking at a problem with fscanf for a few days now. It seems to stop converting hex to binary (infile, "%2x", &ch ) towards the end of the data, although all the data is legit. Soo, I thought, because of some of the problems with the scanf family, I'd change to use fgets and then sscanf the resultant string. Now however, it seems to loop forever!!..

Any thoughts on how to get round this??

Much app'd!

<code>
dbuf = malloc( tifsize+1 );
memset(dbuf, ' ', tifsize+1);

fgets(dbuf, tifsize+1,infile);
while (sscanf(dbuf, "%2x", &ch )==1)
{
fputc(ch, outfile);
}
free (dbuf);
fclose(infile);
fclose(outfile);

<\code>
 
Code:
while (sscanf(dbuf, "%2x", &ch )==1)
You're always converting the same character forever.

Try something like this:
Code:
char* temp = NULL;

...

temp = dbuf;
while (sscanf(temp, "%2x", &ch )==1)
{
   fputc(ch, outfile);
   ++temp;
}

Then this line will cause you some problems too:
Code:
fgets(dbuf, tifsize+1,infile);
You should only read in tifsize bytes, not tifsize+1, otherwise you're overwriting your NULL at the end of the string buffer.
 
Perhaps something like this.
Code:
#include <stdio.h>

int main()
{
   const char filename[] = "file.txt";
   FILE *file = fopen(filename, "r");
   if ( file )
   {
      char dbuf[100];
      while ( fgets(dbuf, sizeof dbuf, file) != NULL )
      {
         unsigned int ch;
         int n;
         char *ptr = dbuf;
         while ( sscanf(ptr, "%2x%n", &ch, &n ) == 1 )
         {
            fputc(ch, stdout);
            ptr += 2;
         }
         putchar('\n');
      }
      fclose(file);
   }
   return 0;
}

/* file.txt
31323433
364152
*/

/* my output
1243
6AR
*/
 
In cpjust's answer, ++temp should be temp += 2. It is reading 2 chars.

Not sure what %n is meant to do in DaveSinkula's answer. What is the purpose of n?
 
> Not sure what %n is meant to do in DaveSinkula's answer. What is the purpose of n?
It tells you how many characters have been used (so far) in the conversions.

Which means ptr+=2 should really be ptr+=n

> char dbuf[100];
Subtle bug - if the buffer is filled, there will be an odd number of characters stored. The last "%2x" conversion on the line will produce an unexpected result.

--
 
Learn something new everyday. I've never seen %n in 27 years of using C. I suppose if there is no need for it, you'll never see it. Wonder how many people have used j0.
 
Ok.. thanks for all the thoughts above guys.. I've done the changes and it now reads along the string and converts... BUT, I'm back to sq. 1 which is that not the whole string gets converted. I originally used Dave's code that he kindly posted on my hextobin query a while back which used fscanf. This was fine until I came towards the end of the hex at which point it seemd to stop converting even though the character it stopped on was a repeating sequence that it earlier converted successfully. Sooo, I guess my question now is how do I get around using sscanf/fscanf all together. I still need to do the same thing - i.e, convert from hex to binary but I need to use something else to do it.

Again, any thoughts much appreciated!.

Cheers!
 
Try these (fast and robust;) functions:
Code:
/**
 *  Convert hex text string to bin.
 *	String of hex digit pairs: <c0><c1>
 *	with or w/o delimiters (ignored).
 *	May convert in place (implosion).
 *	Returns number of bin data bytes.
 */
int	hex2bin(const char* hex, int n, void* pbin)
{
  char*	bin = (char*)pbin;
  int	c0, c1;
  int	i, h;
  int	j = 0;

  if (!pbin || !hex)
     return 0;
  if (n <= 0) 
     n = strlen(hex); /* Get hex string length */
  for (i = j = 0; i < n; i += 2)
  {
    c0 = hex[i];
    if (i + 1 < n)
       c1 = hex[i+1];
    else
       c1 = c0, c0 = '0';
    if (isxdigit(c0) && isxdigit(c1))
    {
       if (isdigit(c1))
          c1 -= '0';
       else
          c1 -= (c1 < 'G'?'A':'a') - 10;
       if (isdigit(c0))
          c0 -= '0';
       else
          c0 -= (c0 < 'G'?'A':'a') - 10;
       h = (c0 << 4)|c1;
       bin[j++] = h;
    }
    else /* Ignore orphan hex digits.  */
      --i; /* Try from the next char */
  }
  return j;
}

/// File i/o and conversion buffer length
/// (the more - the better;)
#define BSZ	(16*1024)
/**
 *  Convert a text file with hex strings into a bin file.
 *	hex == 0 => use stdio.
 *	We do not want to use stdout (text mode stream).
 *	Returns output length or a number < 0 on error.
 */
int file2bin(const char* binfname, const char* hexfname)
{
  int	total = 0;
  FILE*	bin;
  FILE*	hex;
  void*	p;
  int	k;
  size_t m;

  if (!hexfname)
     hex = stdin;
  else
    hex = fopen(hexfname,"rb");

  if (!hex)
     return -1;
  bin = fopen(binfname,"wb");
  if (!bin)
  {
     if (hexfname)
        fclose(hex);
     return -2;
  }
  p = malloc(BSZ);

  while ((k=fread(p,1,BSZ,hex)) != EOF)
  {
    m = hex2bin((const char*)p,k,p);
    if (m > 0)
    {
       if (fwrite(p,1,m,bin) != m)
       {
	  total = -3;
          break;
       }
       total += m;
    }
  }
  free(p);
  fflush(bin);
  fclose(bin);
  if (hexfname) /* Don't close stdin */
     fclose(hex);
  return total;
}
NO sscanf, fscanf et al, large portions i/o etc...
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top