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
vsscanf implementation !?
Re:vsscanf implementation !?
the idea to implement C functions with a variable number of parameter is to use something like this :
In C, when you have, say three parameters, like in
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 :
va_start is something like :
and va_arg is something like :
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).
Code: Select all
your_function(char* string, ...)
{
}
Code: Select all
void f(int a, int b, int c)
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 */
}
Code: Select all
#define va_start(l, a) (l = (va_list)&a)
Code: Select all
#define va_arg(l, a) (l += (sizeof(a) + 3)&(~3); *(a*)l)
BTW, va_list has to be equivalent to void* (via a typedef, for example).
Re:vsscanf implementation !?
For varg source code use this:
I took it from Viridis OS and made very very few modifications (mainly for making it more ?readable? IMHO )
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
Re:vsscanf implementation !?
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 !?
I took the much easier route: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: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.
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;
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;
}