Search code examples
coperating-systemosdev

Implementation of printf() function


I'm making a hobbyist kernel and I'm trying to implement a printf() function.

Here's my implementation:

void kprint(uint8_t *format, ...) {
  va_list ap;
  va_start(ap, format);

  uint8_t *ptr;

  for (ptr = format; *ptr != '\0'; ptr++) {
    if (*ptr == '%') {
      ptr++;
      switch (*ptr) {
        case 's':
          puts(va_arg(ap, uint8_t *), 0x0F, xPos, yPos);
          break;
      }
    } else {
      puts(ptr, 0x0F, xPos, yPos);
      ptr++;
    }
  }

  va_end(ap);
}

When I want to print "Hello World!" using this function it returns me that:

"Hello %sllo %so %sWorld"

Here's function call:

kprint("Hello %s", "World");

Solution

  • the main issue is that you're using puts to print the rest of the string instead of current char.

     } else {
       puts(ptr, 0x0F, xPos, yPos);
       ptr++;
    }
    

    also you're incrementing ptr when it's already done in the loop. Useful to consume format argument, but not in that case.

    A working implementation (not using the strange puts prototype) that works on a standard system (tested on windows gcc):

    #include <stdio.h>
    #include <stdint.h>
    #include <stdarg.h>
    
    void zprintf(uint8_t *format, ...)
      {
          va_list ap;
          va_start(ap, format);
    
          uint8_t *ptr;
    
          for (ptr = format; *ptr != '\0'; ptr++) {
              if (*ptr == '%') {
                  ptr++;
                  switch (*ptr) {
                      case 's':
                          fputs(va_arg(ap, uint8_t *),stdout);
                          break;
                     case '%':
                          putchar('%');
                          break;
                  }
                 } else {
                   putchar(*ptr);
    
                }
               }
    
               va_end(ap);
    }
    
    int main(){
    
        zprintf("%% Hello %s\n","World");    
        return 0;
    }
    

    prints:

    % Hello World
    

    (as a bonus, this implementation handles the escaped % char)

    Using only your special implementation of puts you could change

     } else {
       puts(ptr, 0x0F, xPos, yPos);
       ptr++;
    }
    

    to a working:

     } else {
       char c[2];
       c[0] = *ptr; c[1] = '\0';
       puts(c, 0x0F, xPos, yPos);
     }
    

    lame but would work :)