/*************************************************************************** * Project : shakti devt board * Name of the file : printf.c * Brief Description of file : Print based command and control by uart * Name of Author : Sathya Narayanan N & Balaji venkat * Email ID : sathya281@gmail.com Copyright (C) 2019 IIT Madras. All rights reserved. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***************************************************************************/ /** @file printf.c @brief Print based command and control by uart @detail This file hosts a list of routines that helps in displaying variable's value based on there data type. Currently, shakti-sdk supports few formatting options. */ #include #include #include "utils.h" #include "uart.h" /** @fn static inline void itoa (unsigned long long int number, unsigned base) * @brief integer to string conversion * @param unsigned long long int * @param unsigned */ static inline void itoa (unsigned long long int number, unsigned base) { int i = 0; unsigned int intermediate = 0; unsigned int digits[sizeof(number)*8]; while (1) { digits[i] = number % base; if (number < base) break; number /= base; i++; } i++; while (i-- > 0) { if (digits[i] >= 10) intermediate = 'a' - 10; else intermediate = '0'; putchar(digits[i] + intermediate); } } /** @fn void _printf_(const char *fmt, va_list ap) * @brief Handles the input stream of characters to print on screen * @details Identifies the type of format string, number of arguments and prints the right characer on screen * @param const char * fmt - formatting strings * @param const va_list ap - arg list */ void _printf_(const char *fmt, va_list ap) { register const char* p; const char* last_fmt; register int ch; unsigned long long num; int base, lflag, i; float float_num = 0; char float_arr[30] = {'\0'}; int backtothebeginning; for (;;) { for (;(ch = *(unsigned char *) fmt) != '%'; fmt++) { if (ch == '\0') return; putchar(ch); } fmt++; // Process a %-escape sequence last_fmt = fmt; lflag = 0; backtothebeginning = 0; for (;;) { switch (ch = *(unsigned char *) fmt++) { // long flag (doubled for long long) case 'l': lflag++; backtothebeginning = 1; break; // character case 'c': putchar(va_arg(ap, int)); break; // string case 's': if ((p = va_arg(ap, char *)) == NULL) p = "(null)"; for (; (ch = *p) != '\0' ;) { putchar(ch); p++; } break; // (signed) decimal case 'd': base = 10; if (lflag >= 2) num = va_arg(ap, long long); else if (lflag ==1) num = va_arg(ap, long); else num = va_arg(ap, int); if ((long long) num < 0) { putchar('-'); num = -(long long) num; } itoa( num, base); break; case 'f': float_num = va_arg(ap, double); ftoa(float_num, float_arr, 6); for( i = 0; float_arr[i] != '\0'; i++) { putchar(float_arr[i]); if(i > 29) break; } break; // unsigned decimal case 'u': base = 10; if (lflag >= 2) num = va_arg(ap, unsigned long long); else if (lflag) num = va_arg(ap, unsigned long); else num = va_arg(ap, unsigned int); itoa( num, base); break; // (unsigned) octal case 'o': // should do something with padding so it's always 3 octits base = 8; if (lflag >= 2) num = va_arg(ap, unsigned long long); else if (lflag) num = va_arg(ap, unsigned long); else num = va_arg(ap, unsigned int); itoa( num, base); break; case 'x': base = 16; if (lflag >= 2) num = va_arg(ap, unsigned long long); else if (lflag) num = va_arg(ap, unsigned long); else num = va_arg(ap, unsigned int); itoa( num, base); break; // escaped '%' character case '%': putchar(ch); break; // unrecognized escape sequence - just print it literally default: putchar('%'); fmt = last_fmt; break; } if (backtothebeginning) { backtothebeginning = 0; continue; } else break; } } } /** @fn int printf(const char* fmt, ...) * @brief function to print characters on file * @details prints the characters on terminal * @param const char* * @return int */ int printf(const char* fmt, ...) { va_list ap; va_start(ap, fmt); _printf_(fmt, ap); va_end(ap); return 0;// incorrect return value, but who cares, anyway? }