193 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			193 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
| FUNCTION
 | |
| <<a64l>>,<<l64a>>---convert between radix-64 ascii string and long
 | |
| 
 | |
| INDEX
 | |
|         a64l
 | |
| INDEX
 | |
| 	l64a
 | |
| 
 | |
| ANSI_SYNOPSIS
 | |
|         #include <stdlib.h>
 | |
|         long a64l(const char *<[input]>);
 | |
|         char *l64a(long <[input]>);
 | |
| 
 | |
| TRAD_SYNOPSIS
 | |
|         #include <stdlib.h>
 | |
|         long a64l(<[input]>)
 | |
|         const char *<[input]>;
 | |
| 
 | |
|         char *l64a(<[input]>)
 | |
|         long <[input]>;
 | |
| 
 | |
| DESCRIPTION
 | |
| Conversion is performed between long and radix-64 characters.  The <<l64a>> routine
 | |
| transforms up to 32-bits of input value starting from least significant bits to
 | |
| the most significant bits.  The input value is split up into a maximum of 5
 | |
| groups of 6-bits and possibly one group of 2 bits (bits 31 and 30).
 | |
| 
 | |
| Each group of 6 bits forms a value from 0-63 which is translated into a character
 | |
| as follows:
 | |
| 
 | |
|       0 = '.'
 | |
|       1 = '/'
 | |
|       2-11 = '0' to '9'
 | |
|       12-37 = 'A' to 'Z'
 | |
|       38-63 = 'a' to 'z'
 | |
| 
 | |
| When remaining bits are zero or all bits have been translated, a nul terminator
 | |
| is appended to the string.  An input value of 0 results in the empty string.
 | |
| 
 | |
| The <<a64l>> performs the reverse translation.  Each character is used to generate
 | |
| a 6-bit value for up to 30 bits and then a 2-bit value to complete a 32-bit result.
 | |
| The nul terminator means that the remaining digits are 0.  An empty input string or 
 | |
| NULL string results in 0L.  An invalid string results in undefined behavior.
 | |
| If the size of a long is > 32 bits, the result is sign-extended.
 | |
|  
 | |
| RETURNS
 | |
| <<l64a>> returns a nul-terminated string of 0 to 6 characters.
 | |
| <<a64l>> returns the 32-bit translated value from the input character string.
 | |
| 
 | |
| PORTABILITY
 | |
| <<l64a>> and <<a64l>> are non-ANSI and are defined by the Single Unix Specification.
 | |
| 
 | |
| Supporting OS subroutines required: None.
 | |
| */
 | |
| 
 | |
| #include <_ansi.h>
 | |
| #include <stdlib.h>
 | |
| #include <limits.h>
 | |
| 
 | |
| long
 | |
| _DEFUN (a64l, (input),
 | |
| 	const char *input)
 | |
| {
 | |
|   char *ptr;
 | |
|   char ch;
 | |
|   int i, digit;
 | |
|   unsigned long result = 0;
 | |
| 
 | |
|   if (input == NULL)
 | |
|     return 0;
 | |
| 
 | |
|   ptr = input;
 | |
| 
 | |
|   /* it easiest to go from most significant digit to least so find end of input or up
 | |
|      to 6 characters worth */
 | |
|   for (i = 0; i < 6; ++i)
 | |
|     {
 | |
|       if (*ptr)
 | |
| 	++ptr;
 | |
|     }
 | |
| 
 | |
|   while (ptr > input)
 | |
|     {
 | |
|       ch = *(--ptr);
 | |
| 
 | |
| #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
 | |
|       if (ch >= 'a')
 | |
| 	digit = (ch - 'a') + 38;
 | |
|       else if (ch >= 'A')
 | |
| 	digit = (ch - 'A') + 12;
 | |
|       else if (ch >= '0')
 | |
| 	digit = (ch - '0') + 2;
 | |
|       else if (ch == '/')
 | |
| 	digit = 1;
 | |
|       else
 | |
| 	digit = 0;
 | |
| #else /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */
 | |
|       switch (ch)
 | |
| 	{
 | |
| 	case '/':
 | |
| 	  digit = 1;
 | |
| 	  break;
 | |
| 	case '0':
 | |
| 	case '1':
 | |
| 	case '2':
 | |
| 	case '3':
 | |
| 	case '4':
 | |
| 	case '5':
 | |
| 	case '6':
 | |
| 	case '7':
 | |
| 	case '8':
 | |
| 	case '9':
 | |
| 	  digit = (ch - '0') + 2;
 | |
| 	  break;
 | |
| 	case 'A':
 | |
| 	case 'B':
 | |
| 	case 'C':
 | |
| 	case 'D':
 | |
| 	case 'E':
 | |
| 	case 'F':
 | |
| 	case 'G':
 | |
| 	case 'H':
 | |
| 	case 'I':
 | |
| 	case 'J':
 | |
| 	case 'K':
 | |
| 	case 'L':
 | |
| 	case 'M':
 | |
| 	case 'N':
 | |
| 	case 'O':
 | |
| 	case 'P':
 | |
| 	case 'Q':
 | |
| 	case 'R':
 | |
| 	case 'S':
 | |
| 	case 'T':
 | |
| 	case 'U':
 | |
| 	case 'V':
 | |
| 	case 'W':
 | |
| 	case 'X':
 | |
| 	case 'Y':
 | |
| 	case 'Z':
 | |
| 	  digit = (ch - 'A') + 12;
 | |
| 	  break;
 | |
| 	case 'a':
 | |
| 	case 'b':
 | |
| 	case 'c':
 | |
| 	case 'd':
 | |
| 	case 'e':
 | |
| 	case 'f':
 | |
| 	case 'g':
 | |
| 	case 'h':
 | |
| 	case 'i':
 | |
| 	case 'j':
 | |
| 	case 'k':
 | |
| 	case 'l':
 | |
| 	case 'm':
 | |
| 	case 'n':
 | |
| 	case 'o':
 | |
| 	case 'p':
 | |
| 	case 'q':
 | |
| 	case 'r':
 | |
| 	case 's':
 | |
| 	case 't':
 | |
| 	case 'u':
 | |
| 	case 'v':
 | |
| 	case 'w':
 | |
| 	case 'x':
 | |
| 	case 'y':
 | |
| 	case 'z':
 | |
| 	  digit = (ch - 'A') + 38;
 | |
| 	  break;
 | |
| 	default:
 | |
| 	  digit = 0;
 | |
| 	  break;
 | |
| 	}
 | |
| #endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */ 
 | |
|       
 | |
|       result = (result << 6) + digit;
 | |
|     }
 | |
| 
 | |
| #if LONG_MAX > 2147483647
 | |
|   /* for implementations where long is > 32 bits, the result must be sign-extended */
 | |
|   if (result & 0x80000000)
 | |
|       return (((long)-1 >> 32) << 32) + result;
 | |
| #endif
 | |
| 
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |