Page 1 of 1

vsscanf implementation !?

Posted: Wed Jul 13, 2005 6:24 am
by mar-rih
Salam.. :)

I have written keyboard driver, and write the getch system call for reading the input from keyboard.

and i want to build a scanf interface.

i reviewed the scanf implementation in linux and some simple operating system, i found that the scanf implementation is standard, and depend on :

1- va_list arguments
2- vsscanf() function.
3- sscanf() function

i searched about this things, but i could't understand the global idea.

could help me by some documentation about, please ?

Thanx ;)

Re:vsscanf implementation !?

Posted: Wed Jul 13, 2005 9:01 am
by pini
the idea to implement C functions with a variable number of parameter is to use something like this :

Code: Select all

your_function(char* string, ...)
{
}
In C, when you have, say three parameters, like in

Code: Select all

void f(int a, int b, int c)
the parameters are pushed on the stack with the first argument pushed last, so that the first to be popped will be the first argument (I don't know if I explained it correctly).

In the case of ... arguments, you have to find the address of the next parameter you want, and you know that it's on the stack.
But 'string' is also on the stack, and you can get its address by '&string'. The second argument of the function will be at '&string + sizeof(string)'. lets this address be 'A'.
The third argument will be at 'A + sizeof(parameter at A)', etc...

va_start is usally a macro which takes the first argument of the function as parameter and returns the address where it can be found.

then, each time you retrieve an argument, you also have to call va_arg (IIRC), which takes the 'list pointer' and an integer as parameter, mostly given with a 'sizeof()' or even a type and increments the 'list pointer' with the integer (possibly rounded to fit stack element size).

Example :

Code: Select all

void f(char* string, ...)
{
   va_list list_pointer;
   int i;

   va_start(list_pointer, string);
   /* Do whatever you have to do */
   /* Now you want to retrieve the second argument, which should be an int (you know it, because of the %d or whatever you found when parsing the string. */
   i = va_arg(list_pointer, int);
   /* Continue to do whatever you have to do */
}
va_start is something like :

Code: Select all

#define va_start(l, a) (l = (va_list)&a)
and va_arg is something like :

Code: Select all

#define va_arg(l, a) (l += (sizeof(a) + 3)&(~3); *(a*)l)
I don't remember if its a , or a ; that must be used in va_arg, but one of the two means 'return the last value of the list'.

BTW, va_list has to be equivalent to void* (via a typedef, for example).

Re:vsscanf implementation !?

Posted: Wed Jul 13, 2005 2:15 pm
by marcio.f
For varg source code use this:

Code: Select all

#ifndef __STDARG__
#define __STDARG__

/* varg - variable argument list type */
typedef unsigned char *va_list;

/* Initialize varg list
   IN:    AP - varg list
       LASTAR - last argument name */
#define   va_start(AP, LASTARG) \
   ( AP = ( (va_list) & (LASTARG) + VA_SIZE(LASTARG) ) )

/* Return the value of the next unnamed argument
   IN:    AP - varg list
       TYPE - type of the next unnamed argument
   OUT: type of the argument */
#define va_arg(AP, TYPE) \
   ( AP += __va_rounded_size(TYPE), \
   *( (TYPE *) ( AP - __va_rounded_size(TYPE) ) ) )

#define __va_rounded_size(TYPE) \
   ( ( ( sizeof(TYPE) + sizeof(int) - 1 ) / sizeof(int)) * sizeof(int) )

#define   VA_SIZE(TYPE) \
   ( ( sizeof(TYPE) + sizeof(STACKITEM) - 1 ) \
   & ~( sizeof(STACKITEM) - 1 ) )

#define STACKITEM int

/* Finalize use of varg list
   IN:    AP - varg list */
#define va_end(AP)

#endif
I took it from Viridis OS and made very very few modifications (mainly for making it more ?readable? IMHO ;) )

Re:vsscanf implementation !?

Posted: Wed Jul 13, 2005 3:13 pm
by GLneo
heres my entire stdarg.h:

Code: Select all

typedef void *va_list;
void va_end (va_list);
#define va_rounded_size(TYPE) (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
#define va_start(AP, LASTARG) (AP = ((va_list) __builtin_next_arg (LASTARG)))
#define va_arg(AP, TYPE) (AP = (va_list) ((char *) (AP) + va_rounded_size(TYPE)), *((TYPE *) (void *) ((char *) (AP) - va_rounded_size (TYPE))))

Re:vsscanf implementation !?

Posted: Wed Jul 13, 2005 4:07 pm
by AR
I took the much easier route:

Code: Select all

#define va_start(v, l)   __builtin_va_start(v, l)
#define va_end(v)      __builtin_va_end(v)
#define va_arg(v, l)   __builtin_va_arg(v, l)
typedef __builtin_va_list   va_list;
Works on GCC 3.x (IIRC).
A note for the slow: __builtin_* is a prefix for features built in to the compiler itself.

Basically you'll just want to end up with something like:

Code: Select all

int scanf(const char *format, ...)
{
    bool IgnoreSpaces;
    int SearchPhase = 1;
    va_args va;
    int RetVal = 0;
    int Trash;

    va_start(va, format); /* Start variable length arguments */
    /* Loop the string */
    while(*format)
    {
        /* Analyse the character */
        switch(*format)
        {
        case '\t':
        case ' ':
            IgnoreSpaces = true;
            break;
        case '%':
            SearchPhase = 2;
            break;
        case '*':
            SearchPhase = 3;
            break;
        case 'c':
            switch(SearchPhase)
            case 2:
                Keyboard_GetChar( va_arg(va, char*) );
                break;
            case 3:
                Keyboard_GetChar( (char*)&Trash );
                break;
            }
            SearchPhase = 1;
            ++RetVal;
            break;
         case 'd':
            switch(SearchPhase)
            case 2:
                Keyboard_GetInt32( va_arg(va, int*) );
                break;
            case 3:
                Keyboard_GetInt32( &Trash );
                break;
            }
            SearchPhase = 1;
            ++RetVal;
         default:
            /* ??? */
         }
         format++;
     }
     va_end(va);
     return RetVal;
}
This is a very approximate concept to give you an idea of how you could implement it, the "[...]" operator will require some additional flags but this should work. Naturally the Keyboard_* functions are functions that operate on the keyboard buffer.