Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /libc/src/stdio.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 
0019 /* --??-- Future development: possbily break this file into separate
0020    files for time, string maipulation, etc etc functionality */
0021 
0022 
0023 #include "stdio.h"
0024 #include "stdlib.h"
0025 #include "buffer.h"
0026 #include "time.h"
0027 
0028 #define ALIGN 8
0029 
0030 #define ceil(size, align) (( size ) + ( align ) - 1 ) / ( align )
0031 #define rdtsc(x)      __asm__ __volatile__("rdtsc \n\t" : "=A" (*(x)))
0032 
0033 static frec_p frhead;           /* Free record-list head.                  */
0034 static frec_p frecs;            /* Allocatable records from free-list.     */
0035 
0036 static void MergeRecords (frec_p frp);
0037 static void DelRecord (frec_p prev_frp, frec_p frp);
0038 
0039 /* Convert the integer D to a string and save the string in BUF. If
0040    BASE is equal to 'd', interpret that D is decimal, and if BASE is
0041    equal to 'x', interpret that D is hexadecimal. */
0042 void itoa (char *buf, int base, int d)
0043 {
0044   char *p = buf;
0045   char *p1, *p2;
0046   unsigned long ud = d;
0047   int divisor = 10;
0048      
0049   /* If %d is specified and D is minus, put `-' in the head. */
0050   if (base == 'd' && d < 0)
0051     {
0052       *p++ = '-';
0053       buf++;
0054       ud = -d;
0055     }
0056   else if (base == 'x')
0057     divisor = 16;
0058      
0059   /* Divide UD by DIVISOR until UD == 0. */
0060   do
0061     {
0062       int remainder = ud % divisor;
0063      
0064       *p++ = (remainder < 10) ? remainder + '0' : remainder + 'a' - 10;
0065     }
0066   while (ud /= divisor);
0067      
0068   /* Terminate BUF. */
0069   *p = 0;
0070      
0071   /* Reverse BUF. */
0072   p1 = buf;
0073   p2 = p - 1;
0074   while (p1 < p2)
0075     {
0076       char tmp = *p1;
0077       *p1 = *p2;
0078       *p2 = tmp;
0079       p1++;
0080       p2--;
0081     }
0082 }
0083 
0084 
0085 int printf (const char *format, ...) {
0086   char **arg = (char **) &format;
0087   int c;
0088   char buf[20];
0089   int count = 0;
0090   
0091   arg++;
0092   
0093   while ((c = *format++) != 0)
0094     {
0095       if (c != '%') {
0096         putchar (c);
0097         count++;
0098       }
0099       else
0100         {
0101           char *p;
0102           
0103           c = *format++;
0104           switch (c)
0105             {
0106             case 'd':
0107             case 'u':
0108             case 'x':
0109               itoa (buf, c, *((int *) arg++));
0110               p = buf;
0111               goto string;
0112               break;
0113 
0114             case 's':
0115               p = *arg++;
0116               if (! p)
0117                 p = "(null)";
0118 
0119             string:
0120               while (*p) {
0121                 putchar (*p++);
0122                 count++;
0123               }
0124               break;
0125 
0126             default:
0127               putchar (*((int *) arg++));
0128               count++;
0129               break;
0130             }
0131         }
0132     }
0133   return count;
0134 }
0135 
0136 
0137 int sprintf (char *str, const char *format, ...) {
0138   char **arg = (char **) &format;
0139   int c;
0140   char buf[20];
0141   int count = 0;
0142   
0143   arg++;
0144   
0145   while ((c = *format++) != 0)
0146     {
0147       if (c != '%') {
0148         *str++ = c;
0149         count++;
0150       }
0151       else
0152         {
0153           char *p;
0154           
0155           c = *format++;
0156           switch (c)
0157             {
0158             case 'd':
0159             case 'u':
0160             case 'x':
0161               itoa (buf, c, *((int *) arg++));
0162               p = buf;
0163               goto string;
0164               break;
0165 
0166             case 's':
0167               p = *arg++;
0168               if (! p)
0169                 p = "(null)";
0170 
0171             string:
0172               while (*p) {
0173                 *str++ = *p++;
0174                 count++;
0175               }
0176               break;
0177 
0178             default:
0179               *str++ = (*((int *) arg++));
0180               count++;
0181               break;
0182             }
0183         }
0184     }
0185   
0186   *str = '\0';
0187 
0188   return count;
0189 }
0190 
0191 
0192 static char arena[1000000];     /* --??-- To configure later for d.m.a. */
0193 
0194 void mem_init ( void ) {
0195   void *memset( void *p, int ch, size_t cb );
0196   addrs_t baseptr;
0197   frec_p frp;
0198 
0199   int size = 800000;            /* --??-- (See above) */
0200 
0201   memset(arena, 0, 1000000);
0202 
0203   baseptr = arena; 
0204   frhead = (frec_p)(baseptr + size); 
0205 
0206   for (frp = frhead; frp < frhead + MAXBLKS; frp++)
0207     frp->next = frp + 1;
0208 
0209   frhead->next = NULL;
0210   (frhead + MAXBLKS - 1)->next = NULL;
0211   frecs = frhead + 1;
0212   frhead->fbp = baseptr;
0213   frhead->size = size;
0214 }
0215 
0216 
0217 void *malloc (size_t size) {
0218 
0219   frec_p frp, prev_frp;
0220   addrs_t frstart;
0221 
0222   size += 8;                    /* Allocate space for tracking size 
0223                                    of actual allocation */
0224 
0225   prev_frp = frp = frhead;
0226 
0227   while (frp) {
0228     if (frp->size >= (int)(ALIGN * ceil(size, ALIGN))) {
0229 
0230       /* Have found space. */
0231       frstart = frp->fbp;
0232       frp->fbp += (int)(ALIGN * ceil(size, ALIGN));
0233       frp->size -= (int)(ALIGN * ceil(size, ALIGN));
0234       *((int *)frstart) = size; /* Store size allocated */
0235       
0236       /* If block is only partially allocated then return. */
0237       if (frp->size)
0238         return (frstart+8);
0239 
0240       /* Complete block is allocated. Adjust free record list. */
0241       DelRecord (prev_frp, frp);
0242       return (frstart+8);
0243 
0244     }
0245     prev_frp = frp;
0246     frp = frp->next;
0247   }
0248   return NULL;
0249 }
0250 
0251 
0252 static void DelRecord (frec_p prev_frp, frec_p frp) {
0253 
0254   if (frp == frhead)
0255     frhead = frp->next;
0256   else
0257     prev_frp->next = frp->next;
0258 
0259   frp->next = frecs;
0260   frecs = frp;
0261 }
0262 
0263 
0264 void free (void *addr) {
0265 
0266   frec_p frp, new_frp, prev_frp;
0267   size_t size;
0268 
0269   addr -= 8;                    /* Decrement address to find size field */
0270 
0271   size = *((int *) addr );
0272 
0273   if ((new_frp = frecs) == NULL) {
0274     /* fprintf (stderr, "No free records.\n"); --??-- */
0275     exit (1);
0276   }
0277 
0278   new_frp->fbp = (addrs_t) addr;
0279   new_frp->size = (int)(ALIGN * ceil(size, ALIGN));
0280   frecs = new_frp->next;
0281   frp = frhead;
0282 
0283   /* If this block's address is less than lowest block address
0284      currently available, or if no block records are available at this
0285      time, put this block on the front of the free record list. */
0286 
0287   if (frp == NULL || (addrs_t)addr <= frp->fbp) {
0288     new_frp->next = frp;
0289     frhead = new_frp;
0290     MergeRecords (new_frp);
0291     return;
0292   }
0293 
0294   /* Deallocated block does not go on front of free record list. */
0295 
0296   while (frp && (addrs_t)addr > frp->fbp) {
0297     prev_frp = frp;
0298     frp = frp->next;
0299   }
0300 
0301   new_frp->next = prev_frp->next;
0302   prev_frp->next = new_frp;
0303   MergeRecords (prev_frp);
0304 }
0305 
0306 
0307 static void MergeRecords (frec_p frp) {
0308 
0309   frec_p next_frp;
0310 
0311   /* Merge contiguous records if possible. */
0312   
0313   if ((next_frp = frp->next) == NULL)
0314     return;
0315 
0316   if (frp->fbp + frp->size == next_frp->fbp) {
0317     frp->size += next_frp->size;
0318     DelRecord (frp, next_frp);
0319   }
0320   else
0321     frp = next_frp;
0322 
0323   if ((next_frp = frp->next) == NULL)
0324     return;
0325 
0326   if (frp->fbp + frp->size == next_frp->fbp) {
0327     frp->size += next_frp->size;
0328     DelRecord (frp, next_frp);
0329   }
0330 }
0331 
0332 __attribute__((noreturn)) void exit( int status ) {
0333 
0334   /* --??--Add functionality here for cleaning up user-level resources e.g., in
0335      UNIX this would be stdio-related buffers etc, followed by calling exit
0336      handlers... */
0337 
0338   _exit( status );
0339 
0340 }
0341 
0342 
0343 static unsigned long int next = 1;
0344 
0345 int rand(void) { /* RAND_MAX assumed to be 32767 */
0346 
0347   next = next * 1103515245 + 12345;
0348   return (unsigned int)(next/65536) % 32768;
0349 }
0350 
0351 void srand(unsigned int seed) {
0352   next = seed;
0353 }
0354 
0355 /* --??-- To be implemented */
0356 int atoi(const char *nptr) {
0357 
0358   return -1;
0359 }
0360 
0361 
0362 clock_t clock( void ) {
0363 
0364   return( time() * 10000 );     /* Time returned in microseconds */
0365 }
0366 
0367 size_t strlen( const char *s ) {
0368 
0369   int i;
0370 
0371   i = 0;
0372   while( s[i] != '\0' )
0373     ++i;
0374   return i;
0375 
0376 }
0377 
0378 
0379 char *strcpy( char *s1, const char *s2 ) {
0380 
0381   while( *s1++ = *s2++ );
0382   
0383   return s1;
0384 }
0385 
0386 
0387 char *strncpy( char *s1, const char *s2, int length ) {
0388 
0389   while( ( length-- ) && ( *s1++ = *s2++ ) );
0390   
0391   if( length < 0 )
0392     *(s1-1) = '\0';
0393   
0394   return s1;
0395 }
0396 
0397 
0398 int strcmp(const char *s1, const char *s2) {
0399 
0400   for( ; *s1 == *s2; s1++, s2++ )
0401     if( *s1 == '\0' )
0402       return 0;
0403   return *s1 - *s2;
0404 
0405 }
0406 
0407 
0408 void *memset( void *p, int ch, size_t cb ) {
0409 
0410     asm volatile( "rep stosb" : : "D" (p), "a" (ch), "c" (cb) );
0411     return p;
0412 }
0413 
0414 
0415 void *memcpy( void *pDest, const void *pSrc, size_t cb ) {
0416 
0417     asm volatile( "rep movsb" : : "D" (pDest), "S" (pSrc), "c" (cb) );
0418     return pDest;
0419 }
0420 
0421 
0422 int memcmp( const void *p1, const void *p2, size_t cb ) {
0423 
0424   const char *s1 = p1, *s2 = p2;
0425 
0426   for( ; cb && *s1 == *s2; s1++, s2++, cb-- );
0427   if( !cb )
0428     return 0;
0429   
0430   return *s1 - *s2;
0431 }
0432 
0433 
0434 /* --??-- Needs future enhancement. Right now, strongly tied to fopen */
0435 static int fp;
0436 static int filesize;
0437 static char tmp_buf[8192];              /* Ugly! */
0438 
0439 size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
0440   
0441   /* Don't actually read -- just index into tmp_buf */
0442   if( size * nmemb + fp > filesize )
0443     nmemb = ( filesize - fp ) / size;
0444 
0445   memcpy( ptr, tmp_buf + fp, size * nmemb );
0446   fp += size * nmemb;
0447   
0448   return nmemb;
0449 }
0450 
0451 
0452 /* --??-- Needs future enhancement */
0453 FILE *fopen(const char *path, const char *mode) {
0454   
0455   static FILE f;
0456 
0457   if( ( filesize = open( path, 0 ) ) < 0 )
0458     return NULL;
0459   read( (char *)path, tmp_buf, filesize );
0460   fp = 0;
0461 
0462   return &f;
0463   
0464 }
0465 
0466 
0467 /* --??-- To be implemented */
0468 size_t   fwrite(const  void  *ptr,  size_t  size,  size_t  nmemb,  FILE *stream) {
0469 
0470 
0471   return 0;
0472 }
0473 
0474 
0475 /* --??-- To be implemented */
0476 int fclose(FILE *stream) {
0477 
0478   return 0;
0479 }
0480 
0481 
0482 /* --??-- To be implemented */
0483 int fprintf(FILE *stream, const char *format, ...) {
0484 
0485 }
0486 
0487 
0488 int puts(const char *s) {
0489   
0490   while( *s )
0491     putchar( *s++ );
0492 
0493   putchar( '\n' );
0494   
0495   return( 1 );
0496 }
0497 
0498 
0499 void _start ( int argc, char *argv[] ) {
0500 
0501   mem_init();
0502   exit ( main( argc, argv ) );
0503 }
0504 
0505 /* 
0506  * Local Variables:
0507  * indent-tabs-mode: nil
0508  * mode: C
0509  * c-file-style: "gnu"
0510  * c-basic-offset: 2
0511  * End: 
0512  */
0513 
0514 /* vi: set et sw=2 sts=2: */