printk - The standard C library routine printf()

发布时间 2023-05-23 00:05:43作者: 昆山皮皮虾
如下库我试过,只用定义下out_char函数即可,重定向一下 out_char
  1 /*
  2  * File:        printk.c
  3  * Purpose:     The standard C library routine printf(), but without
  4  *              all the baggage.
  5  */
  6 
  7 #include <stdarg.h>
  8 /********************************************************************/
  9 typedef struct
 10 {
 11   int dest;
 12   void (*func)( char );
 13   char * loc;
 14 } PRINTK_INFO;
 15 int printk( PRINTK_INFO *, const char *, va_list );
 16 /********************************************************************/
 17 #define DEST_CONSOLE              (1)
 18 #define DEST_STRING               (2)
 19 #define FLAGS_MINUS               (0x01)
 20 #define FLAGS_PLUS                (0x02)
 21 #define FLAGS_SPACE               (0x04)
 22 #define FLAGS_ZERO                (0x08)
 23 #define FLAGS_POUND               (0x10)
 24 #define IS_FLAG_MINUS(a)          (a & FLAGS_MINUS)
 25 #define IS_FLAG_PLUS(a)           (a & FLAGS_PLUS)
 26 #define IS_FLAG_SPACE(a)          (a & FLAGS_SPACE)
 27 #define IS_FLAG_ZERO(a)           (a & FLAGS_ZERO)
 28 #define IS_FLAG_POUND(a)          (a & FLAGS_POUND)
 29 #define LENMOD_h                  (0x01)
 30 #define LENMOD_l                  (0x02)
 31 #define LENMOD_L                  (0x04)
 32 #define IS_LENMOD_h(a)            (a & LENMOD_h)
 33 #define IS_LENMOD_l(a)            (a & LENMOD_l)
 34 #define IS_LENMOD_L(a)            (a & LENMOD_L)
 35 #define FMT_d                     (0x0001)
 36 #define FMT_o                     (0x0002)
 37 #define FMT_x                     (0x0004)
 38 #define FMT_X                     (0x0008)
 39 #define FMT_u                     (0x0010)
 40 #define FMT_c                     (0x0020)
 41 #define FMT_s                     (0x0040)
 42 #define FMT_p                     (0x0080)
 43 #define FMT_n                     (0x0100)
 44 #define IS_FMT_d(a)               (a & FMT_d)
 45 #define IS_FMT_o(a)               (a & FMT_o)
 46 #define IS_FMT_x(a)               (a & FMT_x)
 47 #define IS_FMT_X(a)               (a & FMT_X)
 48 #define IS_FMT_u(a)               (a & FMT_u)
 49 #define IS_FMT_c(a)               (a & FMT_c)
 50 #define IS_FMT_s(a)               (a & FMT_s)
 51 #define IS_FMT_p(a)               (a & FMT_p)
 52 #define IS_FMT_n(a)               (a & FMT_n)
 53 /********************************************************************/
 54 static void printk_putc( int c, int * count, PRINTK_INFO * info )
 55 {
 56   switch ( info->dest )
 57   {
 58     case DEST_CONSOLE:
 59       info->func( (char) c );
 60       break;
 61     case DEST_STRING:
 62       *( info->loc ) = (unsigned char) c;
 63       ++( info->loc );
 64       break;
 65     default:
 66       break;
 67   }
 68   *count += 1;
 69 }
 70 /********************************************************************/
 71 static int printk_mknumstr( char * numstr, void * nump, int neg, int radix )
 72 {
 73   int a, b, c;
 74   unsigned int ua, ub, uc;
 75   int nlen;
 76   char * nstrp;
 77   nlen = 0;
 78   nstrp = numstr;
 79   *nstrp++ = '\0';
 80   if ( neg )
 81   {
 82     a = *(int*) nump;
 83     if ( a == 0 )
 84     {
 85       *nstrp = '0';
 86       ++nlen;
 87       goto done;
 88     }
 89     while ( a != 0 )
 90     {
 91       b = (int) a / (int) radix;
 92       c = (int) a - ( (int) b * (int) radix );
 93       if ( c < 0 )
 94       {
 95         c = ~c + 1 + '0';
 96       }
 97       else
 98       {
 99         c = c + '0';
100       }
101       a = b;
102       *nstrp++ = (char) c;
103       ++nlen;
104     }
105   }
106   else
107   {
108     ua = *(unsigned int*) nump;
109     if ( ua == 0 )
110     {
111       *nstrp = '0';
112       ++nlen;
113       goto done;
114     }
115     while ( ua != 0 )
116     {
117       ub = (unsigned int) ua / (unsigned int) radix;
118       uc = (unsigned int) ua - ( (unsigned int) ub * (unsigned int) radix );
119       if ( uc < 10 )
120       {
121         uc = uc + '0';
122       }
123       else
124       {
125         uc = uc - 10 + 'A';
126       }
127       ua = ub;
128       *nstrp++ = (char) uc;
129       ++nlen;
130     }
131   }
132   done: return nlen;
133 }
134 /********************************************************************/
135 static void printk_pad_zero( int curlen, int field_width, int * count,
136   PRINTK_INFO * info )
137 {
138   int i;
139   for ( i = curlen; i < field_width; i++ )
140   {
141     printk_putc( '0', count, info );
142   }
143 }
144 /********************************************************************/
145 static void printk_pad_space( int curlen, int field_width, int * count,
146   PRINTK_INFO * info )
147 {
148   int i;
149   for ( i = curlen; i < field_width; i++ )
150   {
151     printk_putc( ' ', count, info );
152   }
153 }
154 /********************************************************************/
155 int printk( PRINTK_INFO * info, const char * fmt, va_list ap )
156 {
157   /* va_list ap; */
158   char * p;
159   int c;
160   char vstr[ 33 ];
161   char * vstrp;
162   int vlen;
163   int done;
164   int count = 0;
165   int flags_used;
166   int field_width;
167 #if 0
168   int precision_used;
169   int precision_width;
170   int length_modifier;
171 #endif
172   int ival;
173   int schar, dschar;
174   int * ivalp;
175   char * sval;
176   int cval;
177   unsigned int uval;
178   /*
179    * Start parsing apart the format string and display appropriate
180    * formats and data.
181    */
182   for ( p = (char*) fmt; ( c = *p ) != 0; p++ )
183   {
184     /*
185      * All formats begin with a '%' marker.  Special chars like
186      * '\n' or '\t' are normally converted to the appropriate
187      * character by the __compiler__.  Thus, no need for this
188      * routine to account for the '\' character.
189      */
190     if ( c != '%' )
191     {
192       /*
193        * This needs to be replaced with something like
194        * 'out_char()' or call an OS routine.
195        */
196 #ifndef UNIX_DEBUG
197       if ( c != '\n' )
198       {
199         printk_putc( c, &count, info );
200       }
201       else
202       {
203         printk_putc( 0x0D /* CR */, &count, info );
204         printk_putc( 0x0A /* LF */, &count, info );
205       }
206 #else
207       printk_putc( c, &count, info );
208 #endif
209       /*
210        * By using 'continue', the next iteration of the loop
211        * is used, skipping the code that follows.
212        */
213       continue;
214     }
215     /*
216      * First check for specification modifier flags.
217      */
218     flags_used = 0;
219     done = FALSE;
220     while ( !done )
221     {
222       switch ( /* c = */*++p )
223       {
224         case '-':
225           flags_used |= FLAGS_MINUS;
226           break;
227         case '+':
228           flags_used |= FLAGS_PLUS;
229           break;
230         case ' ':
231           flags_used |= FLAGS_SPACE;
232           break;
233         case '0':
234           flags_used |= FLAGS_ZERO;
235           break;
236         case '#':
237           flags_used |= FLAGS_POUND;
238           break;
239         default:
240           /* we've gone one char too far */
241           --p;
242           done = TRUE;
243           break;
244       }
245     }
246     /*
247      * Next check for minimum field width.
248      */
249     field_width = 0;
250     done = FALSE;
251     while ( !done )
252     {
253       switch ( c = *++p )
254       {
255         case '0':
256         case '1':
257         case '2':
258         case '3':
259         case '4':
260         case '5':
261         case '6':
262         case '7':
263         case '8':
264         case '9':
265           field_width = ( field_width * 10 ) + ( c - '0' );
266           break;
267         default:
268           /* we've gone one char too far */
269           --p;
270           done = TRUE;
271           break;
272       }
273     }
274     /*
275      * Next check for the width and precision field separator.
276      */
277     if ( /* (c = *++p) */*++p == '.' )
278     {
279       /* precision_used = TRUE; */
280       /*
281        * Must get precision field width, if present.
282        */
283       /* precision_width = 0; */
284       done = FALSE;
285       while ( !done )
286       {
287         switch ( /* c = uncomment if used below */*++p )
288         {
289           case '0':
290           case '1':
291           case '2':
292           case '3':
293           case '4':
294           case '5':
295           case '6':
296           case '7':
297           case '8':
298           case '9':
299 #if 0
300             precision_width = ( precision_width * 10 ) + ( c - '0' );
301 #endif
302             break;
303           default:
304             /* we've gone one char too far */
305             --p;
306             done = TRUE;
307             break;
308         }
309       }
310     }
311     else
312     {
313       /* we've gone one char too far */
314       --p;
315 #if 0
316       precision_used = FALSE;
317       precision_width = 0;
318 #endif
319     }
320     /*
321      * Check for the length modifier.
322      */
323     /* length_modifier = 0; */
324     switch ( /* c = */*++p )
325     {
326       case 'h':
327         /* length_modifier |= LENMOD_h; */
328         break;
329       case 'l':
330         /* length_modifier |= LENMOD_l; */
331         break;
332       case 'L':
333         /* length_modifier |= LENMOD_L; */
334         break;
335       default:
336         /* we've gone one char too far */
337         --p;
338         break;
339     }
340     /*
341      * Now we're ready to examine the format.
342      */
343     switch ( c = *++p )
344     {
345       case 'd':
346       case 'i':
347         ival = ( int )va_arg( ap, int );
348         vlen = printk_mknumstr( vstr, &ival, TRUE, 10 );
349         vstrp = &vstr[ vlen ];
350         if ( ival < 0 )
351         {
352           schar = '-';
353           ++vlen;
354         }
355         else
356         {
357           if ( IS_FLAG_PLUS( flags_used ) )
358           {
359             schar = '+';
360             ++vlen;
361           }
362           else
363           {
364             if ( IS_FLAG_SPACE( flags_used ) )
365             {
366               schar = ' ';
367               ++vlen;
368             }
369             else
370             {
371               schar = 0;
372             }
373           }
374         }
375         dschar = FALSE;
376         /*
377          * do the ZERO pad.
378          */
379         if ( IS_FLAG_ZERO( flags_used ) )
380         {
381           if ( schar )
382             printk_putc( schar, &count, info );
383           dschar = TRUE;
384           printk_pad_zero( vlen, field_width, &count, info );
385           vlen = field_width;
386         }
387         else
388         {
389           if ( !IS_FLAG_MINUS( flags_used ) )
390           {
391             printk_pad_space( vlen, field_width, &count, info );
392             if ( schar )
393               printk_putc( schar, &count, info );
394             dschar = TRUE;
395           }
396         }
397         /* the string was built in reverse order, now display in */
398         /* correct order */
399         if ( !dschar && schar )
400         {
401           printk_putc( schar, &count, info );
402         }
403         goto cont_xd;
404       case 'x':
405       case 'X':
406         uval = ( unsigned int )va_arg( ap, unsigned int );
407         vlen = printk_mknumstr( vstr, &uval, FALSE, 16 );
408         vstrp = &vstr[ vlen ];
409         dschar = FALSE;
410         if ( IS_FLAG_ZERO( flags_used ) )
411         {
412           if ( IS_FLAG_POUND( flags_used ) )
413           {
414             printk_putc( '0', &count, info );
415             printk_putc( 'x', &count, info );
416             /*vlen += 2;*/
417             dschar = TRUE;
418           }
419           printk_pad_zero( vlen, field_width, &count, info );
420           vlen = field_width;
421         }
422         else
423         {
424           if ( !IS_FLAG_MINUS( flags_used ) )
425           {
426             if ( IS_FLAG_POUND( flags_used ) )
427             {
428               vlen += 2;
429             }
430             printk_pad_space( vlen, field_width, &count, info );
431             if ( IS_FLAG_POUND( flags_used ) )
432             {
433               printk_putc( '0', &count, info );
434               printk_putc( 'x', &count, info );
435               dschar = TRUE;
436             }
437           }
438         }
439         if ( ( IS_FLAG_POUND( flags_used ) ) && !dschar )
440         {
441           printk_putc( '0', &count, info );
442           printk_putc( 'x', &count, info );
443           vlen += 2;
444         }
445         goto cont_xd;
446       case 'o':
447         uval = ( unsigned int )va_arg( ap, unsigned int );
448         vlen = printk_mknumstr( vstr, &uval, FALSE, 8 );
449         goto cont_u;
450       case 'b':
451         uval = ( unsigned int )va_arg( ap, unsigned int );
452         vlen = printk_mknumstr( vstr, &uval, FALSE, 2 );
453         goto cont_u;
454       case 'p':
455         uval = ( unsigned int )va_arg( ap, void* );
456         vlen = printk_mknumstr( vstr, &uval, FALSE, 16 );
457         goto cont_u;
458       case 'u':
459         uval = ( unsigned int )va_arg( ap, unsigned int );
460         vlen = printk_mknumstr( vstr, &uval, FALSE, 10 );
461         cont_u: vstrp = &vstr[ vlen ];
462         if ( IS_FLAG_ZERO( flags_used ) )
463         {
464           printk_pad_zero( vlen, field_width, &count, info );
465           vlen = field_width;
466         }
467         else
468         {
469           if ( !IS_FLAG_MINUS( flags_used ) )
470           {
471             printk_pad_space( vlen, field_width, &count, info );
472           }
473         }
474         cont_xd: while ( *vstrp )
475           printk_putc( *vstrp--, &count, info );
476         if ( IS_FLAG_MINUS( flags_used ) )
477         {
478           printk_pad_space( vlen, field_width, &count, info );
479         }
480         break;
481       case 'c':
482         cval = ( char )va_arg( ap, unsigned int );
483         printk_putc( cval, &count, info );
484         break;
485       case 's':
486         sval = ( char* )va_arg( ap, char* );
487         if ( sval )
488         {
489           vlen = strlen( sval );
490           if ( !IS_FLAG_MINUS( flags_used ) )
491           {
492             printk_pad_space( vlen, field_width, &count, info );
493           }
494           while ( *sval )
495             printk_putc( *sval++, &count, info );
496           if ( IS_FLAG_MINUS( flags_used ) )
497           {
498             printk_pad_space( vlen, field_width, &count, info );
499           }
500         }
501         break;
502       case 'n':
503         ivalp = ( int* )va_arg( ap, int* );
504         *ivalp = count;
505         break;
506       default:
507         printk_putc( c, &count, info );
508         break;
509     }
510   }
511   return count;
512 }
513 /********************************************************************/
514 int printf( const char * fmt, ... )
515 {
516   va_list ap;
517   int rvalue;
518   PRINTK_INFO info;
519   info.dest = DEST_CONSOLE;
520   info.func = &out_char;
521   /*
522    * Initialize the pointer to the variable length argument list.
523    */
524   va_start( ap, fmt );
525   rvalue = printk( &info, fmt, ap );
526   /*
527    * Cleanup the variable length argument list.
528    */
529   va_end( ap );
530   return rvalue;
531 }
532 /********************************************************************/
533 int sprintf( char * s, const char * fmt, ... )
534 {
535   va_list ap;
536   int rvalue = 0;
537   PRINTK_INFO info;
538   /*
539    * Initialize the pointer to the variable length argument list.
540    */
541   if ( s != 0 )
542   {
543     info.dest = DEST_STRING;
544     info.loc = s;
545     va_start( ap, fmt );
546     rvalue = printk( &info, fmt, ap );
547     *info.loc = '\0';
548     va_end( ap );
549   }
550   return rvalue;
551 }
552 /********************************************************************/