/*
 * Scanf code.  Extend File namespace with reading code
 */
extend namespace File {
    
    /*
     * Include existing public File members
     */
    public import File;
    
    /*
     * vfscanf
     */
    public int function vfscanf (file f, string format, (*poly)[*] args)
    {
	int function iswhite (int c)
	{
	    switch (c) {
	    case ' ':
	    case '\t':
	    case '\n':
		return 1;
	    }
	    return 0;
	}

	/* Skip whitespace */
	function whitespace ()
	{
	    int c;

	    while (iswhite (c = File::getc (f)))
		;
	    File::ungetc (c, f);
	}

	int function isnumber (int c)
	{
	    if ('0' <= c && c <= '9')
		return 1;
	    if ('a' <= c && c <= 'f')
		return 1;
	    if ('A' <= c && c <= 'F')
		return 1;
	    if (c == '-')
		return 1;
	    if (c == '.')
		return 1;
	    return 0;
	}

	/* return next number in input */
	real function number ()
	{
	    int	    c;
	    string  s;

	    whitespace();
	    s = "";
	    while (isnumber (c = File::getc (f)))
		s = s + String::new(c);
	    File::ungetc (c, f);
	    return string_to_real (s);
	}

	string function word ()
	{
	    int	    c;
	    string  s;

	    whitespace();
	    s = "";
	    while (!iswhite (c = File::getc(f)))
		s = s + String::new(c);
	    File::ungetc (c, f);
	    return s;
	}

	int	i = 0;
	int	argc = 0;
	int	c;

	while (i < String::length (format) && !File::end(f) && !File::error(f))
	{
	    switch (format[i]) {
	    case ' ':
	    case '\t':
		whitespace ();
		break;
	    case '%':
		i++;
		switch (format[i]) {
		case 'd':
		case 'e':
		case 'f':
		    *args[argc++] = number();
		    break;
		case 'c':
		    *args[argc++] = File::getc(f);
		    break;
		case 's':
		    *args[argc++] = word();
		    break;
		default:
		    c = File::getc(f);
		    if (c != format[i])
		    {
			File::ungetc (c, f);
			return argc;
		    }
		}
		break;
	    default:
		c = File::getc(f);
		if (c != format[i])
		{
		    File::ungetc (c, f);
		    return argc;
		}
		break;
	    }
	    i++;
	}
	return argc;
    }

    public int function fscanf (file f, string format, *poly args...)
    {
	return vfscanf (f, format, args);
    }

    public string function fgets (file f)
    {
	string	s;
	int	c;

	s = "";
	for (;;)
	{
	    c = getc (f);
	    switch (c) {
	    case '\n':
	    case -1:
		return s;
	    default:
		s = s + String::new (c);
	    }
	}
    }
}

public int function scanf (string format, *poly args...)
{
    return File::vfscanf (stdin, format, args);
}

public int function vscanf (string format, (*poly)[*] args)
{
    return File::vfscanf (stdin, format, args);
}    

public string function gets ()
{
    return File::fgets (stdin);
}
