Printf ()

Standard

Descrizione

Riscrittura della funzione printf () della libreria standard senza utilizzo di librerie esterne.


Sorgente

#define NULL 0x00
#define pop_arg(list, mode) (sizeof(mode)==1 ? ((mode *) (list += 4))[-4] : \
                             sizeof(mode)==2 ? ((mode *) (list += 4))[-2] : \
                             ((mode *) (list += sizeof(mode)))[-1])


/* Richiamo le funzioni non implementate */
extern void *malloc (unsigned int size);
extern void free (void *ptr);
extern void *realloc (void *ptr, unsigned int size);

void _printf (char *, ...);
int strlen (char *);
void _print (char *);
void _putchar (int c);
char *int_to_string (int);
char *strdup (char *);

/* Funzione per la stampa a video di un carattere */
void
_putchar (int c)
{
  asm ("movl $4,%%eax\n"
       "movl $1,%%ebx\n"
       "movl %0,%%ecx\n"
       "movl $1,%%edx\n"
       "int  $0x80"
       :
       : "r" (&c)
       :"eax", "ebx", "ecx", "edx");
}

/* Calcolo lunghezza stringhe NULL-terminated */
int
strlen (char *str)
{
  int i;
  for (i = 0; str[i] != NULL; ++i);
  return i;
}

/* copia una stringa */
char *
strdup (char *str)
{
  int i = strlen (str), c = 0;
  char *l_str = (char *) malloc (i);

  for (; c < i; ++c)
    l_str[c] = str[c];
  l_str[c] = NULL;
  return l_str;
}

/* Converte un intero in una stringa */
char *
int_to_string (int n)
{
  int i, sign, x = n;
  char *str, *t_str;

  if (!n)
    {
      str = (char *) malloc (1);
      *str = 0x30;
      return str;
    }

  if ((sign = x) < 0)
    x *= -1;

  str = (char *) malloc (2);

  for (i = 0; x > 0; i++)
    {
      str[i] = (x % 10) + 0x30;
      x /= 10;
      str = realloc (str, i + 3);
    }

  if (sign < 0)
    {
      str[i] = '-';
      str[i + 1] = NULL;
    }
  else
    str[i] = NULL;

  t_str = strdup (str);

  for (sign = 0, i = strlen (str); sign < i; sign++)
    str[sign] = t_str[i - (1 + sign)];

  free (t_str);

  return str;
}

/* Funzione per la conversione in ottale */
char *
octal_to_string (int x)
{
  char *local_str, *tmp_str;
  int y = x, mem = 2;

  local_str = (char *) malloc (mem);

  while (!NULL)
    {
      local_str[mem - 2] = *(int_to_string (y % 8));

      local_str = (char *) realloc (local_str, mem++);

      if (y < 8)
        break;
      else
        y /= 8;
    }

  local_str[mem - 2] = NULL;

  mem = strlen (local_str);

  tmp_str = strdup (local_str);

  for (y = 0; y < mem; ++y)
    local_str[mem - (1 + y)] = tmp_str[y];


  free (tmp_str);

  return local_str;
}

/* Funzione per la conversione in esadecimale */
char *
hex_to_string (int x, int mode)
{
  char *local_str, *tmp_str, *alpha_hex;
  int y = x, mem = 2;

  local_str = (char *) malloc (mem);

  if (mode)
    alpha_hex = strdup ("ABCDEF");
  else
    alpha_hex = strdup ("abcdef");

  while (!NULL)
    {
      if (y % 16 < 0x0A)
        local_str[mem - 2] = *(int_to_string (y % 16));
      else
        local_str[mem - 2] = alpha_hex[(y % 16) - 10];

      local_str = (char *) realloc (local_str, mem++);

      if (y < 16)
        break;
      else
        y /= 16;
    }
  free (alpha_hex);
  local_str[mem - 2] = NULL;
  tmp_str = strdup (local_str);

  mem = strlen (tmp_str);
  free (local_str);

  local_str = strdup (tmp_str);
  for (y = 0; y < mem; ++y)
    local_str[mem - (1 + y)] = tmp_str[y];
  free (tmp_str);

  return local_str;
}

/* Funzione per la stampa a video */
void
_print (char *str)
{
  int i = strlen (str), c;

  for (c = 0; c < i; ++c)
    _putchar (str[c]);
}

/* Funzione per la stampa a video formattato */
void
_printf (char *str, ...)
{
  int i = strlen (str), c;
  char *list = (char *) (&(str) + 1), *temp;

  for (c = 0; c < i;)
    {
      if (c != i - 1 && str[c] == '%')
        {
          switch (str[++c])
            {
            case '%':
              _putchar ('%');
              break;
            case 's':
              _print (pop_arg (list, char *));
              break;
            case 'c':
              _putchar (pop_arg (list, char));
              break;
            case 'd':
              temp = int_to_string (pop_arg (list, int));
              _print (temp);
              free (temp);
              break;
            case 'o':
              temp = octal_to_string (pop_arg (list, int));
              _print (temp);
              free (temp);
              break;
            case 'x':
              temp = hex_to_string (pop_arg (list, int), NULL);
              _print (temp);
              free (temp);
              break;
            case 'X':
              temp = hex_to_string (pop_arg (list, int), !NULL);
              _print (temp);
              free (temp);
              break;
            default:
              _printf ("** ERROR: `%%%c` **", str[c]);
              break;
            }
          ++c;
        }
      else
        _putchar (str[c++]);
    }
}

int
main (void)
{
  _printf ("Stringa:   %s\n"
           "Intero:    %d\n"
           "Ottale:    %o\n"
           "Esadecimale ( min ): %x\n"
           "Esadecimale ( max ): %X\n"
           "Carattere: %c\n"
           "Percentuale: %%\n"
           "Errore opzione: %j\n",
           "Hello World!",
           123456,
           123456,
           123456,
           123456,
           'H');
}