conv.c

00001 const char *conv_id = "@(#)conv.c: 1.1 92/04/11 23:08:45 - Ian Clark\n";
00002 /*----------------------------------------------------------------------*
00003  * Description:                                                         *
00004  *      The conversion functions used in typical "C" programs are       *
00005  *      provided in this module. They have been based on the standard   *
00006  *      C I/O library where possible, making testing on a different     *
00007  *      host possible before testing on some target system. All these   *
00008  *      functions operate on passed strings and output data into the    *
00009  *      address passed by the calling function. This module should      *
00010  *      work independently of any I/O locations, and should work on     *
00011  *      most target systems.                                            *
00012  *                                                                      *
00013  * Functions in this file are :-                                        *
00014  *      atoi    -       ASCII string to integer conversion              *
00015  *      gethex  -       returns the hex value of an ASCII hex char      *
00016  *      htoi    -       hex string to integer conversion                *
00017  *      hex32   -       long to hex string conversion                   *
00018  *      hex16   -       word to hex string conversion                   *
00019  *      hex8    -       byte to hex string conversion                   *
00020  *      itoa    -       integer to ASCII conversion                     *
00021  *      sprintf -       formatted print to a string                     *
00022  *                                                                      *
00023  * The common C string functions in this module are :-                  *
00024  *      strcat  -   cat one string after another                        *
00025  *      strcmp  -   compare two strings                                 *
00026  *      strcpy  -   string copy                                         *
00027  *      strlen  -   returns the length of a NULL terminated string.     *
00028  *      memcpy  -   block move                                          *
00029  *                                                                      *
00030  * All the above operate on NULL terminated strings, and when copying   *
00031  * etc, it is the calling function's responsibility to ensure enough    *
00032  * space is available for the operation.                                *
00033  *                                                                      *
00034  * Note:                                                                *
00035  *      The functions using divide and multiply have been written for   *
00036  *      the MC68000 which does not have 32-bit ALU and the Paragon "C"  *
00037  *      compiler calls LDIV and LMOD which are not supplied in source   *
00038  *      form. For other processors, 'itoi' will be changed.             *
00039  *----------------------------------------------------------------------*/
00040 
00041 #include "string.h"
00042 
00043 static char hexstr[] = "0123456789abcdef";
00044 
00045 /*----------------------------------------------------------------------*
00046  *                              ATOI                                    *
00047  *----------------------------------------------------------------------*
00048  * Interface:                                                           *
00049  *      val = atoi(s);                                                  *
00050  *      int     val;                                                    *
00051  *      char    s;              passed string (ASCII & NULL terminated) *
00052  *      Assumption is that ASCII string contains values (0 to 9)        *
00053  *                                                                      *
00054  * Returns:                                                             *
00055  *      binary value representing the ASCII string 's'.                 *
00056  *      There are no error conditions! - make sure passed data is OK    *
00057  *                                                                      *
00058  * Description:                                                         *
00059  *      atoi() converts ASCII strings to a binary integer. No           *
00060  *      assumptions are made for the size of integers on different      *
00061  *      processors, and it is up to the user to ensure correct data is  *
00062  *      passed to atoi(), as no error conditions are available.         *
00063  *      This version is a modified version of K & R pg 58 (uses "for")  *
00064  *----------------------------------------------------------------------*/
00065 int atoi(char *s)       {
00066 
00067         int     n = 0;          /* value returned by atoi       */
00068         char    ch;
00069         int     sign = 1;               /* assume positive      */
00070 
00071         while (*s == ' ' || *s == '\t')
00072                 s++;                    /* skip leading white spaces    */
00073 
00074         if (*s == '-' || *s == '+')   {
00075                 if (*s == '-')
00076                         sign = -1;
00077                 s++;
00078         }
00079 
00080         while ( (ch = *s++) >= '0' && ch <= '9')  {
00081                 n *= 10;
00082                 n += ch - '0';
00083         }
00084         n = (sign > 0 ? n : -n);
00085         return (n);
00086 }
00087 
00088 /*----------------------------------------------------------------------*
00089  *                              GETHEX                                  *
00090  *----------------------------------------------------------------------*
00091  * Interface:                                                           *
00092  *      hexchar = gethex(ch);                                           *
00093  *      int     hexchar;                                                *
00094  *      char            ch;     passed for conversion                   *
00095  *                                                                      *
00096  * Returns:                                                             *
00097  *      hex equivalent of ASCII characters in the ranges - '0' to '9',  *
00098  *      'a' to 'f' and 'A' to 'F'. Any other characters are considered  *
00099  *      error conditions and -1 is returned.                            *
00100  *                                                                      *
00101  * Description:                                                         *
00102  *      gethex() indexes into an ASCII string and returns the hex       *
00103  *      equivalent at the indexed position ie. 'A' = 65 returns the     *
00104  *      value at hexconv[65] which is 10. Similarly 'b' is 66, so       *
00105  *      hexconv[66] returns 11. A check is made that the character will *
00106  *      fall in the 128 ASCII character range by masking off bit 7, as  *
00107  *      no useful information exists above index 127. Some versions for *
00108  *      functions returning hex equivalents of ASCII characters do      *
00109  *      tests to see if the characters are in the correct range - eg.   *
00110  *      if (ch >= '0' && ch <= '9')                                     *
00111  *              return(ch - '0');                                       *
00112  *      else if (ch >= 'A' && ch <= 'F')                                *
00113  *              return(ch - 'A' + 10);                                  *
00114  *      else if (ch >= 'a' && ch <= 'f')                                *
00115  *              return(ch -'a' + 10);                                   *
00116  *      else                                                            *
00117  *              return(-1);             error condition                 *
00118  *                                                                      *
00119  *      The gethex() function is used by the S record and Intel hex     *
00120  *      download programs, and has to be as fast as possible. For       *
00121  *      16- and 32-bit processors, indexing is fairly easy and the      *
00122  *      128 byte lookup string does not take up much more space than    *
00123  *      the compiled version of the above function in the comments.     *
00124  *      For 16/32 embedded systems with problems with 30 or so bytes,   *
00125  *      best change the hardware before changing gethex().              *
00126  *----------------------------------------------------------------------*/
00127 int     gethex(char ch) {
00128 
00129         int     i;
00130 
00131 #if 0   /* Does not seem to be working  */
00132         /* made values 0x7f so when sign extended, they are still       */
00133         /* positive. That makes the test below (i < 16) still valid     */
00134 
00135         const   char    hexconv[128] = {
00136         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 0-9 */
00137         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 10-19 */
00138         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 20-29 */
00139         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 30-39 */
00140         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,                /* 40-47 */
00141           0 ,  1 ,  2 ,  3 ,  4 ,  5 ,  6 ,  7 ,  8 ,  9 ,      /* 48-57 */
00142         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,                     /* 58-64 */
00143          10 , 11 , 12 , 13 , 14 , 15 ,0x7f,0x7f,0x7f,0x7f,      /* 65-74 */
00144         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 75-84 */
00145         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 85-94 */
00146         0x7f,0x7f, 10 , 11 , 12 , 13 , 14 , 15 ,0x7f,0x7f,      /* 95-104 */
00147         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 105-114 */
00148         0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,      /* 115-124 */
00149         0x7f,0x7f,0x7f                                          /* 125-127 */
00150         };
00151 
00152         i = (int) hexconv[ch & 0x7f];           /* make sure ch < 128   */
00153         if (i < 16)
00154                 return(i);      /* Values 0 -> 15 or 0->9, A->F, a->f   */
00155         else
00156                 return(-1);             /* not valid ASCII hex value    */
00157 #endif
00158         if (ch >= '0' && ch <= '9')
00159                 return(ch - '0');
00160         else if (ch >= 'A' && ch <= 'F')
00161                 return(ch - 'A' + 10);
00162         else if (ch >= 'a' && ch <= 'f')
00163                 return(ch - 'a' + 10);
00164         else
00165                 return(-1);
00166 }
00167 
00168 
00169 /*----------------------------------------------------------------------*
00170  *                              HTOI                                    *
00171  *----------------------------------------------------------------------*
00172  * Interface:                                                           *
00173  *      val = htoi(s);                                                  *
00174  *      int     val;                                                    *
00175  *      char    *s;     passed string of ASCII hex values               *
00176  *      Assumption: Values are in range '0'->'9', 'A'->'F', 'a'->'f'    *
00177  *                                                                      *
00178  * Returns:                                                             *
00179  *      binary value representing ASCII hex values in passed string     *
00180  *      There are no error conditions, and conversion terminates on     *
00181  *      any non-hex value.                                              *
00182  *                                                                      *
00183  * Description:                                                         *
00184  *      htoi() - hex to integer conversion function. Converts one hex   *
00185  *      character at a time to binary starting from the most            *
00186  *      significant value and continuing until the string NULL          *
00187  *      termination or on any non-hex input, eg \n, \r etc. No          *
00188  *      assumption is made for the size of integers, and the calling    *
00189  *      function must ensure the value passed will fit into an INT.     *
00190  *----------------------------------------------------------------------*/
00191 int htoi(char *s)       {
00192         /* passed a pointer to hex string       */
00193 
00194         unsigned int  n = 0;            /* returned value       */
00195         unsigned char ch;               /* char to convert      */
00196         int     t;              /* offset for upper/lower case A, a     */
00197 
00198         while (*s == ' ' || *s == '\t')
00199                 s++;                    /* skip leading white spaces    */
00200 
00201         while (ch = *s++)  {
00202                 if ((t = gethex(ch)) == -1)
00203                         break;          /* stops on invalid input       */
00204                 n <<= 4;
00205                 n |= t & 0x0f;
00206         }
00207         return (n);
00208 }
00209 
00210 
00211 /*----------------------------------------------------------------------*
00212  *                      HEX8, HEX16, HEX32                              *
00213  *----------------------------------------------------------------------*
00214  * Interface:                                                           *
00215  *      void    hex8(s, n);     put 1 hex pair at 's' representing n    *
00216  *      void    hex16(s, n);    put 2 hex pairs at 's' representing n   *
00217  *      void    hex32(s, n);    put 4 hex pairs at 's' representing n   *
00218  *      char    *s;             address of string for output            *
00219  *      int     n;              value to convert                        *
00220  *                                                                      *
00221  * Returns:                                                             *
00222  *      nothing, output is placed into the strings passed ('s').        *
00223  *      It is the user's responsibility to ensure enough space is       *
00224  *      available in 's'.                                               *
00225  *                                                                      *
00226  * Description:                                                         *
00227  *      The hex??() functions output characters in reverse order.       *
00228  *      ie - The least significant value is obtained by masking and     *
00229  *      then indexing into hexstr[]. The returned value is written      *
00230  *      into the output but is offset. The reason for getting the LSB   *
00231  *      first is due to using the value as an index into hexstr[]. If   *
00232  *      the value was taken from the MSB, the index would have to be    *
00233  *      shifted to get a value in the range of 0->15 for an index into  *
00234  *      hexstr[]. The amount to shift would be different for each       *
00235  *      value and the algorithm would be longer and more complicated.   *
00236  *      By left shifting and using the same mask each time, a more      *
00237  *      elegant solution is available. See Xinu by Douglas Comer, pg    *
00238  *      354 to 356 for similar work, except he does not offset the      *
00239  *      output immediately, but rather reverses the local string and    *
00240  *      then copies it to the passed string.                            *
00241  *      hex8() is slightly different - due to only one shift being      *
00242  *      required.
00243  *----------------------------------------------------------------------*/
00244 void    hex32(char *s, long n)  {
00245 
00246         char    *t;
00247         int     j = 7;                                  /* 7 + 1 chars  */
00248 
00249         t = s;
00250         t[8] = '\0';
00251         while (j >= 0)  {
00252                 t[j] = hexstr[n & 0x0f];        /* 4 bits at a time     */
00253                 n >>= 4;
00254                 j--;
00255         }  /* copies into string in reverse (location 7 to 0) */
00256 }
00257 
00258 void    hex16(char *s, int n)   {
00259 
00260         char    *t;
00261         int     j = 3;                                  /* 3 + 1 chars */
00262 
00263         t = s;
00264         t[4] = '\0';
00265         while (j >= 0)  {
00266                 t[j] = hexstr[n & 0x0f];
00267                 n >>= 4;
00268                 j--;
00269         }
00270 }
00271         /* due to right shifting but needing string printed from the    *
00272          * left and not the right, the hex values are put into the      *
00273          * string in reverse order - eg location 3, 2, 1, 0             */
00274 
00275 
00276 
00277 void    hex8(char *s,  unsigned char n) {
00278 
00279         *s++ = hexstr[ (n >> 4) & 0x0f];
00280         hexstr[n & 0x0f];
00281         *s = '\0';
00282 }
00283 
00284 
00285 /*----------------------------------------------------------------------*
00286  *                      ITOA (for MC68000)                              *
00287  *----------------------------------------------------------------------*
00288  * Interface:                                                           *
00289  *      void    itoa(value, buffer);                                    *
00290  *      int     value;                  passed for conversion           *
00291  *      char    *buffer;                output is put in 'buffer'       *
00292  *                                                                      *
00293  * Returns:                                                             *
00294  *      nothing, the output is placed into 'buffer' which must be       *
00295  *      large enough. There are no error codes.                         *
00296  *                                                                      *
00297  * Description:                                                         *
00298  *      The version below was written for the MC68000 processor. Other  *
00299  *      versions in the source files for the "C" I/O libraries supplied *
00300  *      with various compilers use the modulus (%) operator. The "C"    *
00301  *      compiler from Microtek (Paragon) calls LMODT & LDIV which are   *
00302  *      not supplied in source form. The 68000 does 16-bit division and *
00303  *      16-bit modulus, but then the values passed to 'itoa' would have *
00304  *      to be limited to a 16-bit signed quantity. For the Z8000 and    *
00305  *      NS32000, a simplified version would be used and is is provided  *
00306  *      below in comments for reference purposes.                       *
00307  *                                                                      *
00308  *      do {                                                            *
00309  *              *(ptr--) = n % 10 + '0';                                *
00310  *      } while ( (n /= 10) > 0);                                       *
00311  *                                                                      *
00312  * Note:                                                                *
00313  *      No assumptions are made for the size of an INT, but the user    *
00314  *      must ensure passed values are within range if INT's are assumed *
00315  *      to be 16-bits for 80286 and Z8000.                              *
00316  *----------------------------------------------------------------------*/
00317 void    itoa(int value, char *buffer)   {
00318 
00319         int     digit;          /* added to the string on each loop     */
00320         int     leading = 0;    /* set once there is a digit to print   */
00321         int     val;
00322         char    *cp;
00323 
00324         val = value;
00325         cp = buffer;
00326 
00327         if (val < 0)  {
00328                 *cp++ = '-';
00329                 val = -val;
00330         }
00331         if (val > 1000000000)  {
00332                 strcpy(cp, ">1000,000,000");
00333                 return;
00334         }
00335 
00336         digit = 0;
00337         while (val > 999999999)  {      /* checking for 1000 million    */
00338                 val -= 1000000000;
00339                 digit++;
00340                 leading = 1;    /* any trailing zero's are printed      */
00341         }
00342         if (digit > 0)
00343                 *cp++ = digit + '0';
00344         else if (leading)
00345                 *cp++ = '0';
00346 
00347         digit = 0;
00348         while (val > 99999999)  {       /* checking for 100 million     */
00349                 val -= 100000000;
00350                 digit++;
00351                 leading = 1;    /* any trailing zero's are printed      */
00352         }
00353         if (digit > 0)
00354                 *cp++ = digit + '0';
00355         else if (leading)
00356                 *cp++ = '0';
00357 
00358         digit = 0;
00359         while (val > 9999999)  {        /* checking for 10 million      */
00360                 val -= 10000000;
00361                 digit++;
00362                 leading = 1;    /* any trailing zero's are printed      */
00363         }
00364         if (digit > 0)
00365                 *cp++ = digit + '0';
00366         else if (leading)
00367                 *cp++ = '0';
00368 
00369         digit = 0;
00370         while (val > 999999)  {         /* checking for  million        */
00371                 val -= 1000000;
00372                 digit++;
00373                 leading = 1;    /* any trailing zero's are printed      */
00374         }
00375         if (digit > 0)
00376                 *cp++ = digit + '0';
00377         else if (leading)
00378                 *cp++ = '0';
00379 
00380         digit = 0;
00381         while (val > 99999)  {          /* checking for 100 thousands   */
00382                 val -= 100000;
00383                 digit++;
00384                 leading = 1;    /* any trailing zero's are printed      */
00385         }
00386         if (digit > 0)
00387                 *cp++ = digit + '0';
00388         else if (leading)
00389                 *cp++ = '0';
00390 
00391         digit = 0;
00392         while (val > 9999)  {           /* checking for 10 thousands    */
00393                 val -= 10000;
00394                 digit++;
00395                 leading = 1;    /* any trailing zero's are printed      */
00396         }
00397         if (digit > 0)
00398                 *cp++ = digit + '0';
00399         else if (leading)
00400                 *cp++ = '0';
00401 
00402         digit = 0;
00403         while (val > 999)  {            /* checking for thousasnds      */
00404                 val -= 1000;
00405                 digit++;
00406                 leading = 1;    /* any trailing zero's are printed      */
00407         }
00408         if (digit > 0)
00409                 *cp++ = digit + '0';
00410         else if (leading)
00411                 *cp++ = '0';
00412 
00413         digit = 0;
00414         while (val > 99)  {             /* checking for hundreds        */
00415                 val -= 100;
00416                 digit++;
00417                 leading = 1;    /* any trailing zero's are printed      */
00418         }
00419         if (digit > 0)
00420                 *cp++ = digit + '0';
00421         else if (leading)
00422                 *cp++ = '0';
00423 
00424         digit = 0;
00425         while (val > 9)  {                      /* checking for tens    */
00426                 val -= 10;
00427                 digit++;
00428         }                       /* leading not set here, as not checked */
00429                                 /* in units, and 'else if' below not    */
00430                                 /* reached if digits > 0.               */
00431         if (digit > 0)
00432                 *cp++ = digit + '0';
00433         else if (leading)
00434                 *cp++ = '0';
00435 
00436         *cp++ = val + '0';      /* what is left over is units, print    */
00437                                 /* a zero for no units if val == 0      */
00438         *cp = '\0';                             /* end of string        */
00439 }
00440 
00441 /******Still need to sort out precision eg %02d etc******/
00442 
00443 /*----------------------------------------------------------------------*
00444  *                              SPRINTF                                 *
00445  *----------------------------------------------------------------------*
00446  * Interface:                                                           *
00447  *      no_chars = sprintf(buf, format [, arg]...);                     *
00448  *      int     no_chars;       number of chars output to buf (not \0)  *
00449  *      char    *buf;           string to store output                  *
00450  *      char    *format;        format string                           *
00451  *      args are determined from the format string                      *
00452  *                                                                      *
00453  * Returns:                                                             *
00454  *      The number of characters output to the string 'buf'.            *
00455  *      Note: This has been implemented, however, the only version      *
00456  *      of the documentation on sprintf, printf etc that is consistant  *
00457  *      is the Unix version. Others return (OK), status and often       *
00458  *      values that have not been initialized. Left padding and field   *
00459  *      widths must still be implemented.                               * 
00460  *                                                                      *
00461  * Description:                                                         *
00462  *      All I/O in the embedded systems by Ian Clark is done via        *
00463  *      read() and write(). To print formated output as per Unix        *
00464  *      printf(), first call sprintf(buf, ...) and then write the       *
00465  *      output. This allows tasks or traps to be called and possibly    *
00466  *      real-time implementations for printf type output.               *
00467  *      The Unix description for sprintf follows:-                      *
00468  *      Sprintf places output, followed by the null character (\0)      *
00469  *      in consecutive bytes starting at buf; it is the user's          *
00470  *      responsibility to ensure that enough storage is available.      *
00471  *      Each function (printf, fprintf, sprintf) returns the number     *
00472  *      of characters placed (not including the \0 in the case of       *
00473  *      sprintf), or a negative value if an output error was            *
00474  *      encountered.                                                    *
00475  *      The output of these functions converts, formats, and prints     *
00476  *      is 'args' under control of the format string.                   *
00477  *----------------------------------------------------------------------*/
00478 /* based on source from Zilog, Xinu and MIX for printf.c - Ian Clark    */
00479 /* made enough changes and original stuff to be different. Tested on 68008 */
00480 sprintf(char *buf, char *fmt, int stack)        {
00481 
00482         int     i;              /* looping counter & string index       */
00483         int     longflag = 0;   /* != 0 for long numerics - not used    */
00484         int     n;              /* values returned by itoa, hex32 etc   */
00485         int     no_chars;       /* return the number of chars output    */
00486         int     *args;          /* Pointer to integer - all values on   */
00487                                 /* the 68000 are passed as 32-bit ints  */
00488                                 /* using Paragon C (except floats).     */
00489         char    c;              /* char bumping along format string     */
00490         char    *str;           /* Running pointer in string (passed parm)  */
00491         char    temp[20];       /* The string str points to this output */
00492                                 /* from number conversion              */
00493         void    itoa();
00494 
00495         args = &stack;          /* stack address of parameters pushed   */
00496                                 /* as an integer array onto the stack   */
00497 
00498         no_chars = 0;                   /* output nothing so far        */
00499 
00500         while (1)  {                    /*  only exit when all done     */
00501                 /* Echo characters until '%' or end of fmt string */
00502                 while( (c = *fmt++) != '%' ) {
00503                         if( c == '\0' )   {     /* have to terminate    */
00504                                 *buf = '\0';    /* buf, so strlen works */
00505                                                 /* when write is called */
00506                                 return(no_chars);
00507                         }
00508                         *buf++ = c;     /* copy to buf (no I/O in here) */
00509                         no_chars++;
00510                 }
00511 
00512 SWITCHLONG:     /* come back through this loop if a long format         */
00513                 /* requested without having to go to 'while' above      */
00514 
00515                 switch(*fmt++)  {
00516                 case '%':               /* Echo "...%%..." as '%'       */
00517                         *buf++ = '%';
00518                         no_chars++;
00519                         break;
00520                 case 'c':               /* one character                */
00521                         *buf++ = (char) *args++;
00522                         no_chars++;
00523                         break;
00524                 case 'd':               /* decimal < 32k for 68000      */
00525                         if ((n = *args++) < 0)  {
00526                                 *buf++ = '-';
00527                                 no_chars++;
00528                                 n = -n;
00529                         }
00530                         itoa(n, temp);
00531                         i = 0;
00532                         while (temp[i] != '\0')  {
00533                                 *buf++ = temp[i++]; /* cat onto buf     */
00534                                 no_chars++;
00535                         }
00536                         longflag = 0;           /* clear each time      */
00537                         break;  /* do later     */
00538                 case 'l':                               /* long         */
00539                         longflag = 1;
00540                         goto SWITCHLONG;
00541                         break;
00542         /* avoids having another case switch for 'x', 'd' & 'o' and     */
00543         /* going back would result in (c=*fmt++) printing the format    */
00544         /* character instead of the value on the parameter stack.       */
00545                 case 's':                               /* string       */
00546                         str = (char *) *args++;
00547                         while (*str != '\0')  { /* don't want NULL in buf */
00548                                 *buf++ = *str++;        /* cat onto buf */
00549                                 no_chars++;
00550                         }
00551                         break;
00552                 case 'x':
00553                         n = *args++;
00554                         if (longflag)
00555                                 hex32(temp, n);
00556                         else
00557                                 hex16(temp, n);
00558                         i = 0;
00559                         while (temp[i] != '\0')  { /* don't want NULL in buf */
00560                                 *buf++ = temp[i++];     /* cat onto buf */
00561                                 no_chars++;
00562                         }
00563                         longflag = 0;                   /* clear each time */
00564                         break;
00565                 default:
00566                         *buf++ = '%';           /* Put a % in output    */
00567                         *buf++ = *--fmt;        /* for invalid option   */
00568                         no_chars += 2;
00569                         fmt++;                  /* rather than 'error'. */
00570                         break;                  /* Also include the     */
00571                 }                               /* incorrect option.    */
00572         }
00573 }       /* returns no_chars in exit from while loop in test for '%'     */
00574 
00575 /*----------------------------------------------------------------------*
00576  *                      STRING FUNCTIONS                                *
00577  *----------------------------------------------------------------------*
00578  * Interface:                                                           *
00579  *      char    *strcat(s, t)                                           *
00580  *      char    *s, *t;                                                 *
00581  *                                                                      *
00582  *      char    *strncat(s, t, n)                                       *
00583  *      char    *s, *t;                                                 *
00584  *      int     n;                                                      *
00585  *                                                                      *
00586  *      int     strcmp(s, t)                                            *
00587  *      char    *s, *t;                                                 *
00588  *                                                                      *
00589  *      int     strncmp(s, t, n)                                        *
00590  *      char    *s, *t;                                                 *
00591  *      int     n;                                                      *
00592  *                                                                      *
00593  *      char    *strcpy(s, t)                                           *
00594  *      char    *s, *t;                                                 *
00595  *                                                                      *
00596  *      char    *strncpy(s, t, n)                                       *
00597  *      char    *s, *t;                                                 *
00598  *      int     n;                                                      *
00599  *                                                                      *
00600  *      int     strlen(s)                                               *
00601  *      char    *s;                                                     *
00602  *                                                                      *
00603  *      char    *strchr(s, c)                                           *
00604  *      char    *s, c;                                                  *
00605  *                                                                      *
00606  *      char    *strrchr(s, c)                                          *
00607  *      char    *s, c;                                                  *
00608  *                                                                      *
00609  * Description:                                                         *
00610  *      strcat() appends a copy of string 't' to the end of 's'.        *
00611  *      strncat() copies at most n characters. Both return a pointer    *
00612  *      to the first character of 's'. (What use that is, I don't       *
00613  *      know!)                                                          *
00614  *                                                                      *
00615  *      strcmp() compares its arguments and returns an integer          *
00616  *      greater than, equal to, or less than zero, according as 's'     *
00617  *      is lexicgraphically greater than, equal to, or less than 't'.   *
00618  *      strncmp() makes the same comparison but looks at at most 'n'    *
00619  *      characters.                                                     *
00620  *                                                                      *
00621  *      strcpy() copies string 't' to 's', stopping after the null      *
00622  *      character has been moved. strncpy() copies exactly 'n' chars,   *
00623  *      truncating or null-padding 's'; the target may not be null-     *
00624  *      terminated if the length of 't' is 'n' or more. Both return     *
00625  *      a pointer to the first char in 's'. (Why, I don't know)         *
00626  *                                                                      *
00627  *      strlen() returns the number of non-null characters in 's'.      *
00628  *                                                                      *
00629  *      strchr() (strrchar() ) returns a pointer to the first (last)    *
00630  *      occurrence of the character 'c' in the string 's', or NULL      *
00631  *      if 'c' does not occur in the string. The null character         *
00632  *      terminating the string is considered to be part of the string.  *
00633  *----------------------------------------------------------------------*/
00634 
00635 /* strcat: cat 't' onto end of 's', 's' must be big enough. Modified    *
00636  * version of K & R pg 44 which uses indeces (two extra variables)      *
00637  * and does not return a pointer to the first char in 's' (C Ref Man)   *
00638  * See also K & R pg 101 - strcpy pointer version.                      */
00639 
00640 #if 0
00641 char    *strcat(char *s, char *t)       {
00642 
00643         char    *p;                     /* have to return pointer to s  */
00644 
00645         p = s;
00646         while (*s)                              /* while char != \0     */
00647                 s++;    /* first finds end of string s, then copies t   */
00648         while (*s++ = *t++)     /* strings must be null terminated      */
00649                 ;
00650         return(p);
00651 }
00652 
00653 
00654 /* strncat: Just copied above and test for 'n'. Unfortunately, all      *
00655  * original as no source to peruse.                                     */
00656 
00657 char    *strncat(char *s, char *t, int n)       {
00658 
00659         char    *p;                     /* have to return pointer to s  */
00660 
00661         p = s;
00662         while (*s)                              /* while char != \0     */
00663                 s++;    /* first finds end of string s, then copies t   */
00664         while ( (*s = *t) != '\0' && n > 0)  {
00665                 s++;
00666                 t++;
00667                 n--;
00668         }
00669         if (n > 0)                      /* pad with NULL's for 'n'      */
00670         /* to get here, *s == '\0' as that terminated above while       */
00671                 while (n > 0)  {
00672                         *s++ = '\0';
00673                         n--;
00674                 }
00675 
00676         return(p);
00677 }
00678 
00679 /* strcmp.c : returns < 0 if s<t, 0 if s==t, >0 if s>t. K & R pg 102    *
00680  * uses a "for loop", and pg 101 uses a "while" loop with indeces.      */
00681 
00682 strcmp (char *s, char *t)       {
00683 
00684         while (*s == *t)  {
00685                 if (*s == '\0')
00686                         return(0);
00687                 s++;
00688                 t++;
00689         }
00690         return(*s - *t);
00691 }
00692 
00693 /* strncmp: Copied above strcmp() and check for 'n' > 0.        */
00694 
00695 strncmp (char *s, char *t, int n)       {
00696 
00697         while ( (*s == *t) && n > 0)  {
00698                 if (*s == '\0')
00699                         return(0);
00700                 s++;
00701                 t++;
00702                 n--;
00703         }
00704         return(*s - *t);
00705 }
00706 #endif
00707 
00708 /* strcpy: copy strings K & R pg 101. Added returning character pointer *
00709  * to the first char in 'to' as per Xenix documentation and "A C        *
00710  * Reference Manual" - by Tartan Laboratories.                          */
00711 
00712 char    *strcpy (char *to, char *from)  {
00713 
00714         char    *p;
00715 
00716         p = to;
00717         while (*to++ = *from++)
00718                 ;
00719         return(p);
00720 }
00721 
00722 
00723 /* strncpy: copied above strcpy() and check for 'n' > 0.        */
00724 
00725 char    *strncpy (char *to, char *from, int n)  {
00726 
00727         char    *p;
00728 
00729         p = to;
00730         while ( (*to = *from) != '\0' && n > 0)  {
00731                 to++;
00732                 from++;
00733                 n--;
00734         }
00735 
00736         if (n > 0)                      /* still have to pad    */
00737         /* to get here, *s == '\0' as that terminated above while       */
00738                 while (n > 0)  {
00739                         *to++ = '\0';
00740                         n--;
00741                 }
00742 
00743         return(p);
00744 }
00745 
00746 /* strlen: returns length of NULL terminated string. See K & R pg 98    *
00747  * for similar function but subtracting pointers.                       */
00748 
00749 int strlen(char *s)     {
00750 
00751         int i = 0;
00752 
00753         while (*s++)                            /* while char != \0     */
00754                 i++;
00755         return (i);
00756 }
00757 
00758 
00759 /*----------------------------------------------------------------------*
00760  *                              MEMCPY                                  *
00761  *----------------------------------------------------------------------*
00762  * Interface:                                                           *
00763  *      got_to = memcpy(to, from, count);                               *
00764  *      char    *got_to;        where copied to (to+count)              *
00765  *      char    *to;            destination                             *
00766  *      char    from;           source                                  *
00767  *      int     count;          number of bytes to copy                 *
00768  *                                                                      *
00769  * Returns:                                                             *
00770  *      A character pointer to where memcpy() copied to.                *
00771  *                                                                      *
00772  * Description:                                                         *
00773  *      Memory copy or block move function. Uses bytes so no problem    *
00774  *      with Z8000 or 68000 with odd byte alignment on word transfers.  *
00775  *      Count can be odd. A check is done for overlapping memory areas. *
00776  *      Memcpy is passed two addresses and a count value, and returns   *
00777  *      a pointer to the destination.                                   *
00778  *                                                                      *
00779  * Class:                                                               *
00780  *      Standard C function and System V compatible.                    *
00781  *----------------------------------------------------------------------*/
00782 char    *memcpy (char *to, char *from, int count)       {
00783 
00784         /* If (to < from) or (to > from + count) then there is no       *
00785          * overlap problem assuming count is positive. If (to > from)   *
00786          * and (from+count) are greater than 'to', there is an overlap. *
00787          * If there is an overlap, transfer memory from top to bottom.  */
00788 
00789         char *temp;     /* in case of an overlap, return a correct pointer */
00790 
00791 
00792         if ( (to < from) || (to > (from + count) ) )  { /* no overlap   */
00793         /* case below handles normal block moves with no overlaps */
00794                 while (count--)
00795                         *to++ = *from++;
00796                 return (to);
00797         }
00798 
00799         else   {                                        /* overlap      */
00800                 from += count - 1; /* -1 as string index starts at 0, not 1 */
00801                 to += count - 1;
00802                 temp = to;      /* have to return a pointer to the
00803                                  * destination block */
00804                 while (count--)
00805                         *to-- = *from--;
00806                 return (temp);
00807         }
00808 }