Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/util/printf.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include "types.h"
0019 #include "kernel.h"
0020 #include "acpi.h"
0021 #include "util/screen.h"
0022 #include "lwip/ip.h"
0023 #include "lwip/netif.h"
0024 #include "lwip/udp.h"
0025 #include "util/debug.h"
0026 
0027 static uint32 base10_u32_divisors[10] = {
0028   1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10, 1
0029 };
0030 
0031 #if 0
0032 static uint64 base10_u64_divisors[20] = {
0033   10000000000000000000ULL, 1000000000000000000ULL, 100000000000000000ULL,
0034   10000000000000000ULL, 1000000000000000ULL, 100000000000000ULL,
0035   10000000000000ULL, 1000000000000ULL, 100000000000ULL, 10000000000ULL,
0036   1000000000ULL, 100000000ULL, 10000000ULL, 1000000ULL, 100000ULL, 10000ULL,
0037   1000ULL, 100ULL, 10ULL, 1ULL
0038 };
0039 #endif
0040 
0041 void
0042 closure_vprintf (void putc_clo (void *, char), void *data, const char *fmt,
0043                  va_list args)
0044 {
0045   int precision, width, mode, upper, ells;
0046   char padding;
0047 #define putc(c) putc_clo(data,c)
0048   while (*fmt) {
0049     /* handle ordinary characters and directives */
0050     switch (*fmt) {
0051     case '\0':
0052       return;
0053     case '%':
0054       fmt++;
0055       precision = 0;
0056       width = 0;
0057       upper = 1;
0058       padding = ' ';
0059       ells = 0;
0060 #define PRINTF_MODE_PRECISION 1
0061       mode = 0;
0062       /* handle directive arguments */
0063       while (*fmt) {
0064         switch (*fmt) {
0065         case 'p':{
0066             /* pointer value */
0067             uint32 x = va_arg (args, uint32);
0068             int i, li;
0069 
0070             for (i = 0; i < 8; i++) {
0071               if ((li = (x >> ((7 - i) << 2)) & 0x0F) > 9)
0072                 putc ('A' + li - 0x0A);
0073               else
0074                 putc ('0' + li);
0075             }
0076             goto directive_finished;
0077           }
0078         case 'x':
0079           upper = 0;
0080         case 'X':{
0081             /* hexadecimal output */
0082             uint64 x;
0083             int i, li, print_padding = 0, print_digits = 0;
0084             int w = (ells == 2 ? 16 : 8);
0085 
0086             if (ells == 2)
0087               x = va_arg (args, uint64);
0088             else
0089               x = va_arg (args, uint32);
0090 
0091             for (i = 0; i < w; i++) {
0092               li = (x >> (((w - 1) - i) << 2)) & 0x0F;
0093 
0094 #define HANDLE_OPTIONS(q,max_w,end_i)                                   \
0095             if (q != 0 || i == end_i)                                   \
0096               print_digits = 1;                                         \
0097             if (q == 0 && !print_digits && i >= (max_w - width))        \
0098               print_padding = 1;                                        \
0099             if (q == 0 && !print_digits && i >= (max_w - precision))    \
0100               print_digits = 1;                                         \
0101             if (q == 0 && print_padding && !print_digits)               \
0102               putc(padding);
0103 
0104               HANDLE_OPTIONS (li, w, (w-1));
0105 
0106               if (print_digits) {
0107                 if (li > 9)
0108                   putc ((upper ? 'A' : 'a') + li - 0x0A);
0109                 else
0110                   putc ('0' + li);
0111               }
0112             }
0113 
0114             goto directive_finished;
0115           }
0116         case 'u':{
0117             /* decimal output */
0118             uint32 x = va_arg (args, uint32);
0119             int i, q, print_padding = 0, print_digits = 0;
0120             uint32 *divisors = base10_u32_divisors;
0121 
0122             for (i = 0; i < 10; i++) {
0123               q = x / divisors[i];
0124               x %= divisors[i];
0125 
0126               HANDLE_OPTIONS (q, 10, 9);
0127 
0128               if (print_digits)
0129                 putc ('0' + q);
0130             }
0131 
0132             goto directive_finished;
0133           }
0134         case 'd':{
0135             /* decimal output */
0136             signed long x = va_arg (args, signed long);
0137             int i, q, print_padding = 0, print_digits = 0;
0138             uint32 *divisors = base10_u32_divisors;
0139 
0140             if (x < 0) {
0141               putc ('-');
0142               x *= -1;
0143             }
0144             for (i = 0; i < 10; i++) {
0145               q = x / divisors[i];
0146               x %= divisors[i];
0147 
0148               HANDLE_OPTIONS (q, 10, 9);
0149 
0150               if (print_digits)
0151                 putc ('0' + q);
0152             }
0153 
0154             goto directive_finished;
0155           }
0156         case 's':{
0157             /* string argument */
0158             char *s = va_arg (args, char *);
0159             if (s) {
0160               if (precision > 0)
0161                 while (*s && precision-- > 0)
0162                   putc (*s++);
0163               else
0164                 while (*s)
0165                   putc (*s++);
0166             } else {
0167               putc ('('); putc ('n'); putc ('u'); putc ('l'); putc ('l'); putc (')');
0168             }
0169             goto directive_finished;
0170           }
0171         case 'c':{
0172             /* character argument */
0173             char c = (char) va_arg (args, int);
0174             /* char is promoted to int when passed through va_arg */
0175             putc (c);
0176             goto directive_finished;
0177           }
0178         case '%':{
0179             /* single % */
0180             putc ('%');
0181             goto directive_finished;
0182           }
0183         case 'l':
0184           /* "long" annotation */
0185           ells++;
0186           break;
0187         case '.':
0188           mode = PRINTF_MODE_PRECISION;
0189           break;
0190         default:
0191           if ('0' <= *fmt && *fmt <= '9') {
0192             if (mode == PRINTF_MODE_PRECISION) {
0193               /* precision specifier */
0194               precision *= 10;
0195               precision += *fmt - '0';
0196             } else if (mode == 0 && width == 0 && *fmt == '0') {
0197               /* padding char is zero */
0198               padding = '0';
0199             } else {
0200               /* field width */
0201               width *= 10;
0202               width += *fmt - '0';
0203             }
0204           }
0205           break;
0206         }
0207         fmt++;
0208       }
0209     directive_finished:
0210       break;
0211     default:
0212       /* regular character */
0213       putc (*fmt);
0214       break;
0215     }
0216     fmt++;
0217   }
0218 #undef putc
0219 }
0220 
0221 static void
0222 putc_fun (void *f, char c)
0223 {
0224   void (*g) (char) = f;
0225   g (c);
0226 }
0227 
0228 void
0229 fun_vprintf (void putc (char), const char *fmt, va_list args)
0230 {
0231   closure_vprintf (putc_fun, (void *) putc, fmt, args);
0232 }
0233 
0234 void
0235 fun_printf (void putc (char), const char *fmt, ...)
0236 {
0237   va_list args;
0238   va_start (args, fmt);
0239   fun_vprintf (putc, fmt, args);
0240   va_end (args);
0241 }
0242 
0243 void
0244 com1_printf (const char *fmt, ...)
0245 {
0246   va_list args;
0247   va_start (args, fmt);
0248   fun_vprintf (com1_putc, fmt, args);
0249   va_end (args);
0250 }
0251 
0252 /* Feature to send logging output over UDP to a server */
0253 //#define UDP_LOGGING
0254 
0255 #define UDP_LOGGING_PORT 4444
0256 #define UDP_LOGGING_NET_IF "en0"
0257 #define UDP_LOGGING_BUF_SIZE 256
0258 
0259 #ifdef UDP_LOGGING
0260 static struct netif *logging_if = NULL;
0261 static struct udp_pcb *logging_pcb = NULL;
0262 static char logging_buf[UDP_LOGGING_BUF_SIZE];
0263 static int logging_idx = 0;
0264 static void
0265 udp_logging_putc (char c)
0266 {
0267   if (logging_idx < UDP_LOGGING_BUF_SIZE)
0268     logging_buf[logging_idx++] = c;
0269 }
0270 
0271 static int
0272 send (uint8 *buf, uint32 len)
0273 {
0274   struct pbuf *p;
0275   struct ip_addr server_ip;
0276 
0277   /* assume gateway has logging server */
0278   server_ip.addr = logging_if->gw.addr;
0279   if (server_ip.addr == 0) return -1;
0280 
0281   p = pbuf_alloc (PBUF_TRANSPORT, len, PBUF_RAM);
0282 
0283   if (!p) return -1;
0284 
0285   if (pbuf_take (p, buf, len) != ERR_OK) {
0286     pbuf_free (p);
0287     return -1;
0288   }
0289 
0290   if (udp_sendto (logging_pcb, p, &server_ip, UDP_LOGGING_PORT) != ERR_OK) {
0291     pbuf_free (p);
0292     return -1;
0293   }
0294 
0295   pbuf_free (p);
0296 
0297   return len;
0298 }
0299 
0300 void
0301 logger_printf (const char *fmt, ...)
0302 {
0303 
0304   if (!mp_enabled) {
0305     va_list args;
0306     va_start (args, fmt);
0307     fun_vprintf (com1_putc, fmt, args);
0308     va_end (args);
0309   } else {
0310     if (!logging_if)
0311       logging_if = netif_find (UDP_LOGGING_NET_IF);
0312     if (!logging_pcb) {
0313       logging_pcb = udp_new ();
0314       if (!logging_pcb)
0315         panic ("logging_pcb == NULL");
0316       if (udp_bind (logging_pcb, IP_ADDR_ANY, 0) != ERR_OK)
0317         panic ("udp_bind of logging pcb failed");
0318       char *msg = "INITIALIZED UDP LOGGING\n";
0319       send ((u8 *) msg, strlen (msg));
0320     }
0321     logging_idx = 0;
0322     memset (logging_buf, 0, UDP_LOGGING_BUF_SIZE);
0323     va_list args;
0324     va_start (args, fmt);
0325     fun_vprintf (udp_logging_putc, fmt, args);
0326     va_end (args);
0327     send ((u8 *) logging_buf, logging_idx);
0328   }
0329 }
0330 
0331 #else
0332 
0333 void
0334 logger_printf (const char *fmt, ...)
0335 {
0336   va_list args;
0337   va_start (args, fmt);
0338   fun_vprintf (logger_putc, fmt, args);
0339   va_end (args);
0340 }
0341 #endif
0342 
0343 static void
0344 _putc (char c)
0345 {
0346   _putchar (c);
0347 }
0348 
0349 void
0350 printf (const char *fmt, ...)
0351 {
0352   va_list args;
0353   va_start (args, fmt);
0354   spinlock_lock (&screen_lock);
0355   fun_vprintf (_putc, fmt, args);
0356   spinlock_unlock (&screen_lock);
0357   va_end (args);
0358 }
0359 
0360 
0361 void
0362 _printf (const char *fmt, ...)
0363 {
0364   va_list args;
0365   va_start (args, fmt);
0366 
0367   fun_vprintf (_putc, fmt, args);
0368 
0369   va_end (args);
0370 }
0371 
0372 /*
0373  * Local Variables:
0374  * indent-tabs-mode: nil
0375  * mode: C
0376  * c-file-style: "gnu"
0377  * c-basic-offset: 2
0378  * End:
0379  */
0380 
0381 /* vi: set et sw=2 sts=2: */