Cygwin: mmap: allow remapping part of an existing anonymous mapping
[newlib-cygwin.git] / newlib / libc / stdlib / a64l.c
blobdcac2e050d5952da57f62fe1fd535ba4e23eac50
1 /*
2 FUNCTION
3 <<a64l>>, <<l64a>>---convert between radix-64 ASCII string and long
5 INDEX
6 a64l
7 INDEX
8 l64a
10 SYNOPSIS
11 #include <stdlib.h>
12 long a64l(const char *<[input]>);
13 char *l64a(long <[input]>);
15 DESCRIPTION
16 Conversion is performed between long and radix-64 characters. The
17 <<l64a>> routine transforms up to 32 bits of input value starting from
18 least significant bits to the most significant bits. The input value
19 is split up into a maximum of 5 groups of 6 bits and possibly one
20 group of 2 bits (bits 31 and 30).
22 Each group of 6 bits forms a value from 0--63 which is translated into
23 a character as follows:
26 o 0 = '.'
27 o 1 = '/'
28 o 2--11 = '0' to '9'
29 o 12--37 = 'A' to 'Z'
30 o 38--63 = 'a' to 'z'
33 When the remaining bits are zero or all bits have been translated, a
34 null terminator is appended to the string. An input value of 0
35 results in the empty string.
37 The <<a64l>> function performs the reverse translation. Each
38 character is used to generate a 6-bit value for up to 30 bits and then
39 a 2-bit value to complete a 32-bit result. The null terminator means
40 that the remaining digits are 0. An empty input string or NULL string
41 results in 0L. An invalid string results in undefined behavior. If
42 the size of a long is greater than 32 bits, the result is sign-extended.
44 RETURNS
45 <<l64a>> returns a null-terminated string of 0 to 6 characters.
46 <<a64l>> returns the 32-bit translated value from the input character string.
48 PORTABILITY
49 <<l64a>> and <<a64l>> are non-ANSI and are defined by the Single Unix Specification.
51 Supporting OS subroutines required: None.
54 #include <_ansi.h>
55 #include <stdlib.h>
56 #include <limits.h>
58 long
59 a64l (const char *input)
61 const char *ptr;
62 char ch;
63 int i, digit;
64 unsigned long result = 0;
66 if (input == NULL)
67 return 0;
69 ptr = input;
71 /* it easiest to go from most significant digit to least so find end of input or up
72 to 6 characters worth */
73 for (i = 0; i < 6; ++i)
75 if (*ptr)
76 ++ptr;
79 while (ptr > input)
81 ch = *(--ptr);
83 #if defined(PREFER_SIZE_OVER_SPEED) || defined(__OPTIMIZE_SIZE__)
84 if (ch >= 'a')
85 digit = (ch - 'a') + 38;
86 else if (ch >= 'A')
87 digit = (ch - 'A') + 12;
88 else if (ch >= '0')
89 digit = (ch - '0') + 2;
90 else if (ch == '/')
91 digit = 1;
92 else
93 digit = 0;
94 #else /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */
95 switch (ch)
97 case '/':
98 digit = 1;
99 break;
100 case '0':
101 case '1':
102 case '2':
103 case '3':
104 case '4':
105 case '5':
106 case '6':
107 case '7':
108 case '8':
109 case '9':
110 digit = (ch - '0') + 2;
111 break;
112 case 'A':
113 case 'B':
114 case 'C':
115 case 'D':
116 case 'E':
117 case 'F':
118 case 'G':
119 case 'H':
120 case 'I':
121 case 'J':
122 case 'K':
123 case 'L':
124 case 'M':
125 case 'N':
126 case 'O':
127 case 'P':
128 case 'Q':
129 case 'R':
130 case 'S':
131 case 'T':
132 case 'U':
133 case 'V':
134 case 'W':
135 case 'X':
136 case 'Y':
137 case 'Z':
138 digit = (ch - 'A') + 12;
139 break;
140 case 'a':
141 case 'b':
142 case 'c':
143 case 'd':
144 case 'e':
145 case 'f':
146 case 'g':
147 case 'h':
148 case 'i':
149 case 'j':
150 case 'k':
151 case 'l':
152 case 'm':
153 case 'n':
154 case 'o':
155 case 'p':
156 case 'q':
157 case 'r':
158 case 's':
159 case 't':
160 case 'u':
161 case 'v':
162 case 'w':
163 case 'x':
164 case 'y':
165 case 'z':
166 digit = (ch - 'a') + 38;
167 break;
168 default:
169 digit = 0;
170 break;
172 #endif /* !defined(PREFER_SIZE_OVER_SPEED) && !defined(__OPTIMIZE_SIZE__) */
174 result = (result << 6) + digit;
177 #if LONG_MAX > 2147483647
178 /* for implementations where long is > 32 bits, the result must be sign-extended */
179 if (result & 0x80000000)
180 return (((long)-1 >> 32) << 32) + result;
181 #endif
183 return result;