www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1996/06/14/00:09:02

From: fredex AT fcshome DOT stoneham DOT ma DOT us
Message-Id: <199606140134.VAA06883@fcshome.stoneham.ma.us>
Subject: Re: Behavior of fscanf in V2
To: acmq AT coe DOT ufrj DOT br (Antonio Carlos Moreirao de Queiroz)
Date: Thu, 13 Jun 1996 21:34:21 -0400 (EDT)
Cc: djgpp AT delorie DOT com
In-Reply-To: <199606131829.PAA00693@coe.ufrj.br> from "Antonio Carlos Moreirao de Queiroz" at Jun 13, 96 03:29:30 pm

Thinking furiously, Antonio Carlos Moreirao de Queiroz wrote:
> 
> 
> Hi,
> 
> In djgpp V1, in Borland C, or in UNIX gnu C (Sun), I use a statement as:
> 
> while (fscanf(archive,"%s",str1)!=EOF) {...}
>...
> In djgpp V2 this is apparently not happening. fscanf reads again and again
> an empty line after the last item read...
> Exactly the same code works with the other compilers.
> Is this some bug, or am I doing something "nonstandard"?

Sounds somewhat like a bug I encountered recently in the scanf
family. Someone sent me a patch for it which I applied to the library
sources, recompiled, and voila! it's fixed.

The problem I encountered was that fscanf was returning a non-zero,
positive value even if the first token on the input  line did not
match the first item in the format string, causing the parser to
mis-diagnose the contents of the input stream.

I've got the patched library module (doscan.c) whhich I'll append
below for you to try. You'll need the library sources on your machine
to compile this.

Fred
------------------   /djgpp/src/libc/ansi/stdio/doscan.c  ------------------
/* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <libc/file.h>
#include <libc/local.h>

#define	SPC	01
#define	STP	02

#define	SHORT	0
#define	REGULAR	1
#define	LONG	2
#define LONGDOUBLE 4
#define	INT	0
#define	FLOAT	1

static int _innum(int **ptr, int type, int len, int size, FILE *iop, 
                  int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), 
                  int *eofptr);
static int _instr(char *ptr, int type, int len, FILE *iop, 
                  int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), 
                  int *eofptr);
static const char *_getccl(const unsigned char *s);

static char _sctab[256] = {
	0,0,0,0,0,0,0,0,
	0,SPC,SPC,SPC,SPC,SPC,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	SPC,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
	0,0,0,0,0,0,0,0,
};

static int nchars = 0;

int 
_doscan(FILE *iop, const char *fmt, void **argp)
{
  return(_doscan_low(iop, fgetc, ungetc, fmt, argp));
}

int
_doscan_low(FILE *iop, int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *),
            const char *fmt, void **argp)
{
  register int ch;
  int nmatch, len, ch1;
  int **ptr, fileended, size;

  nchars = 0;
  nmatch = 0;
  fileended = 0;
  for (;;) switch (ch = *fmt++) {
  case '\0': 
    return (nmatch);
  case '%':
    if ((ch = *fmt++) == '%')
      goto def;
    if (ch == 'n')
    {
      **(int **)argp++ = nchars;
      break;
    }
    if (fileended)
      return(nmatch? nmatch: -1);
    ptr = 0;
    if (ch != '*')
      ptr = (int **)argp++;
    else
      ch = *fmt++;
    len = 0;
    size = REGULAR;
    while (isdigit(ch)) {
      len = len*10 + ch - '0';
      ch = *fmt++;
    }
    if (len == 0)
      len = 30000;
    if (ch=='l') {
      size = LONG;
      ch = *fmt++;
    } else if (ch=='h') {
      size = SHORT;
      ch = *fmt++;
    } else if (ch=='L') {
      size = LONGDOUBLE;
      ch = *fmt++;
    } else if (ch=='[')
      fmt = _getccl((const unsigned char *)fmt);
    if (isupper(ch)) {
      /* ch = tolower(ch);
	 gcc gives warning: ANSI C forbids braced
	 groups within expressions */
      ch += 'a' - 'A';
      size = LONG;
    }
    if (ch == '\0')
      return(-1);
    if (_innum(ptr, ch, len, size, iop, scan_getc, scan_ungetc,
               &fileended)) {  /* HBB: returns true on successful match */
      if (ptr)
        nmatch++;        /* HBB: successful match, and no 'dummy' "%*" spec */
      break;             /* HBB: success, so go on scanning */
    } else if (fileended && !nmatch)
      return(-1);        /* HBB: input failure before any successful match, requests EOF-return */
    else
      return(nmatch);    /* HBB: 'normal' failure (matching ~, or input ~ after some successful match(es) */
  case ' ':
  case '\n':
  case '\t': 
  case '\r':
  case '\f':
  case '\v':
    while (((nchars++, ch1 = scan_getc(iop))!=EOF) && (_sctab[ch1] & SPC))
      ;
    if (ch1 != EOF)
    {
      scan_ungetc(ch1, iop);
    }
    nchars--;
    break;

  default:
  def:
    ch1 = scan_getc(iop);
    if (ch1 != EOF) nchars++;
    if (ch1 != ch) {
      if (ch1==EOF)
        return(nmatch?nmatch:-1); /* HBB: only return -1 if *no* success at all */
      scan_ungetc(ch1, iop);
      nchars--;
      return(nmatch);
    }
  }
}

static int
_innum(int **ptr, int type, int len, int size, FILE *iop,
       int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
{
  register char *np;
  char numbuf[64];
  register c, base;
  int expseen, scale, negflg, c1, ndigit;
  long lcval;
  int cpos;

  if (type=='c' || type=='s' || type=='[')
    return(_instr(ptr? *(char **)ptr: (char *)NULL, type, len,
		  iop, scan_getc, scan_ungetc, eofptr));
  lcval = 0;
  ndigit = 0;
  scale = INT;
  if (type=='e'||type=='f'||type=='g')
    scale = FLOAT;
  base = 10;
  if (type=='o')
    base = 8;
  else if (type=='x')
    base = 16;
  np = numbuf;
  expseen = 0;
  negflg = 0;
  while (((nchars++, c = scan_getc(iop)) != EOF) && (_sctab[c] & SPC))
    ;
  if (c == EOF) nchars--;
  if (c=='-') {
    negflg++;
    *np++ = c;
    c = scan_getc(iop);
    nchars++;
    len--;
  } else if (c=='+') {
    len--;
    c = scan_getc(iop);
    nchars++;
  }
  cpos = 0;
  for ( ; --len>=0; *np++ = c, c = scan_getc(iop), nchars++) {
    cpos++;
    if (c == '0' && cpos == 1 && type == 'i')
      base = 8;
    if ((c == 'x' || c == 'X') && (type == 'i' || type == 'x')
	&& cpos == 2 && lcval == 0)
    {
      base = 16;
      continue;
    }
    if (isdigit(c)
	|| (base==16 && (('a'<=c && c<='f') || ('A'<=c && c<='F')))) {
      ndigit++;
      if (base==8)
	lcval <<=3;
      else if (base==10)
	lcval = ((lcval<<2) + lcval)<<1;
      else
	lcval <<= 4;
      c1 = c;
      if (isdigit(c))
	c -= '0';
      else if ('a'<=c && c<='f')
	c -= 'a'-10;
      else
	c -= 'A'-10;
      lcval += c;
      c = c1;
      continue;
    } else if (c=='.') {
      if (base!=10 || scale==INT)
	break;
      ndigit++;
      continue;
    } else if ((c=='e'||c=='E') && expseen==0) {
      if (base!=10 || scale==INT || ndigit==0)
	break;
      expseen++;
      *np++ = c;
      c = scan_getc(iop);
      nchars++;
      if (c!='+'&&c!='-'&&('0'>c||c>'9'))
	break;
    } else
      break;
  }
  if (negflg)
    lcval = -lcval;
  if (c != EOF) {
    scan_ungetc(c, iop);
    *eofptr = 0;
  } else
    *eofptr = 1;
  nchars--;
  if (ptr==NULL || np==numbuf || (negflg && np==numbuf+1) ) /* gene dykes*/
    return(0);
  *np++ = 0;
  switch((scale<<4) | size) {

  case (FLOAT<<4) | SHORT:
  case (FLOAT<<4) | REGULAR:
    **(float **)ptr = atof(numbuf);
    break;

  case (FLOAT<<4) | LONG:
    **(double **)ptr = atof(numbuf);
    break;

  case (FLOAT<<4) | LONGDOUBLE:
    **(long double **)ptr = _atold(numbuf);
    break;

  case (INT<<4) | SHORT:
    **(short **)ptr = (short)lcval;
    break;

  case (INT<<4) | REGULAR:
    **(int **)ptr = (int)lcval;
    break;

  case (INT<<4) | LONG:
  case (INT<<4) | LONGDOUBLE:
    **(long **)ptr = lcval;
    break;
  }
  return(1);
}

static int
_instr(char *ptr, int type, int len, FILE *iop,
       int (*scan_getc)(FILE *), int (*scan_ungetc)(int, FILE *), int *eofptr)
{
  register ch;
  register char *optr;
  int ignstp;

  *eofptr = 0;
  optr = ptr;
  if (type=='c' && len==30000)
    len = 1;
  ignstp = 0;
  if (type=='s')
    ignstp = SPC;
  while ((nchars++, ch = scan_getc(iop)) != EOF && _sctab[ch] & ignstp)
    ;
  ignstp = SPC;
  if (type=='c')
    ignstp = 0;
  else if (type=='[')
    ignstp = STP;
  while (ch!=EOF && (_sctab[ch]&ignstp)==0) {
    if (ptr)
      *ptr++ = ch;
    if (--len <= 0)
      break;
    ch = scan_getc(iop);
    nchars++;
  }
  if (ch != EOF) {
    if (len > 0)
    {
      scan_ungetc(ch, iop);
      nchars--;
    }
    *eofptr = 0;
  } else
  {
    nchars--;
    *eofptr = 1;
  }
  if (ptr && ptr!=optr) {
    if (type!='c')
      *ptr++ = '\0';
    return(1);
  }
  return(0);
}

static const char *
_getccl(const unsigned char *s)
{
  register c, t;

  t = 0;
  if (*s == '^') {
    t++;
    s++;
  }
  for (c = 0; c < (sizeof _sctab / sizeof _sctab[0]); c++)
    if (t)
      _sctab[c] &= ~STP;
    else
      _sctab[c] |= STP;
  if ((c = *s) == ']' || c == '-') { /* first char is special */
    if (t)
      _sctab[c] |= STP;
    else
      _sctab[c] &= ~STP;
    s++;
  }
  while ((c = *s++) != ']') {
    if (c==0)
      return((const char *)--s);
    else if (c == '-' && *s != ']' && s[-2] < *s) {
      for (c = s[-2] + 1; c < *s; c++)
	if (t)
	  _sctab[c] |= STP;
	else
	  _sctab[c] &= ~STP;
    } else if (t)
      _sctab[c] |= STP;
    else
      _sctab[c] &= ~STP;
  }
  return((const char *)s);
}
-------------------------------------------------------------------------------
-- 
-------------------------------------------------------------------------------
 .----    Fred Smith    /                        Office: fred AT computrition DOT com 
( /__  ,__.   __   __ /  __   : /                                 508-663-2524 
 /    /  /   /__) /  /  /__) .+'           Home: fredex AT fcshome DOT stoneham DOT ma DOT us 
/    /  (__ (___ (__(_ (___ / :__                                 617-438-5471 
-------------------------------- Jude 1:24,25 ---------------------------------

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019