1/*---------------------------------------------------------------------------*
2 *  LCHAR.c  *
3 *                                                                           *
4 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
5 *                                                                           *
6 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
7 *  you may not use this file except in compliance with the License.         *
8 *                                                                           *
9 *  You may obtain a copy of the License at                                  *
10 *      http://www.apache.org/licenses/LICENSE-2.0                           *
11 *                                                                           *
12 *  Unless required by applicable law or agreed to in writing, software      *
13 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
15 *  See the License for the specific language governing permissions and      *
16 *  limitations under the License.                                           *
17 *                                                                           *
18 *---------------------------------------------------------------------------*/
19
20#include "LCHAR.h"
21#include "plog.h"
22#include "pmemory.h"
23
24#define MTAG NULL
25
26ESR_ReturnCode lstrtrim(LCHAR* text)
27{
28  size_t beginning, ending, len;
29
30  len = LSTRLEN(text);
31
32  /* locating first non-whitespace character from beginning */
33  for (beginning = 0; beginning < len && LISSPACE(text[beginning]); ++beginning);
34  /* locating first non-whitespace character from end */
35  for (ending = len - 1; ending > beginning && LISSPACE(text[ending]); --ending);
36
37  if (beginning > 0 && beginning <= ending)
38    LMEMMOVE(text, text + beginning, ending - beginning + 1);
39  text[ending-beginning+1] = '\0';
40  return ESR_SUCCESS;
41}
42
43ESR_ReturnCode lstrinsert(const LCHAR* source, LCHAR* target, size_t offset, size_t* len)
44{
45  ESR_ReturnCode rc;
46
47  if (source == NULL || target == NULL || len == NULL)
48  {
49    rc = ESR_INVALID_ARGUMENT;
50    PLogError(ESR_rc2str(rc));
51    goto CLEANUP;
52  }
53  if (LSTRLEN(source) + LSTRLEN(target) + 1 > *len)
54  {
55    *len = LSTRLEN(source) + LSTRLEN(target) + 1;
56    rc = ESR_BUFFER_OVERFLOW;
57    PLOG_DBG_TRACE((ESR_rc2str(rc)));
58    goto CLEANUP;
59  }
60  memmove(target + offset + LSTRLEN(source), target + offset, LSTRLEN(target + offset) + 1);
61  LSTRNCPY(target + offset, source, LSTRLEN(source));
62  return ESR_SUCCESS;
63CLEANUP:
64  return rc;
65}
66
67ESR_ReturnCode lstrreplace(LCHAR* text, const LCHAR source, const LCHAR target)
68{
69  LCHAR* index;
70
71  while (ESR_TRUE)
72  {
73    index = LSTRCHR(text, source);
74    if (index == NULL)
75      break;
76    *index = target;
77  }
78  return ESR_SUCCESS;
79}
80
81ESR_ReturnCode lstrtoi(const LCHAR* text, int* result, int base)
82{
83  LCHAR* endPtr;
84
85  if (result == NULL)
86    return ESR_INVALID_ARGUMENT;
87  *result = LSTRTOL(text, &endPtr, base);
88  if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
89    return ESR_INVALID_ARGUMENT;
90  return ESR_SUCCESS;
91}
92
93ESR_ReturnCode lstrtoui(const LCHAR* text, unsigned int* result, int base)
94{
95  LCHAR* endPtr;
96
97  if (result == NULL)
98    return ESR_INVALID_ARGUMENT;
99  *result = LSTRTOUL(text, &endPtr, base);
100  if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
101    return ESR_INVALID_ARGUMENT;
102  return ESR_SUCCESS;
103}
104
105ESR_ReturnCode lstrtof(const LCHAR* text, float* result)
106{
107  LCHAR* endPtr;
108
109  if (result == NULL)
110    return ESR_INVALID_ARGUMENT;
111  *result = (float) LSTRTOD(text, &endPtr);
112  if (endPtr == text || (!LISSPACE(*endPtr) && *endPtr != L('\0')))
113    return ESR_INVALID_ARGUMENT;
114  return ESR_SUCCESS;
115}
116
117ESR_ReturnCode lstrtob(const LCHAR* text, ESR_BOOL* result)
118{
119  ESR_ReturnCode rc = ESR_SUCCESS;
120  int compare;
121  unsigned int temp;
122
123  if (result == NULL)
124    return ESR_INVALID_ARGUMENT;
125  CHKLOG(rc, lstrcasecmp(text, L("true"), &compare));
126  if (compare == 0)
127  {
128    *result = ESR_TRUE;
129    return ESR_SUCCESS;
130  }
131  CHKLOG(rc, lstrcasecmp(text, L("yes"), &compare));
132  if (compare == 0)
133  {
134    *result = ESR_TRUE;
135    return ESR_SUCCESS;
136  }
137  CHKLOG(rc, lstrcasecmp(text, L("false"), &compare));
138  if (compare == 0)
139  {
140    *result = ESR_FALSE;
141    return ESR_SUCCESS;
142  }
143  CHKLOG(rc, lstrcasecmp(text, L("no"), &compare));
144  if (compare == 0)
145  {
146    *result = ESR_FALSE;
147    return ESR_SUCCESS;
148  }
149
150  /* Check for boolean expressed as an integer value */
151  CHK(rc, lstrtoui(text, &temp, 10));
152  *result = (temp != 0);
153  return ESR_SUCCESS;
154CLEANUP:
155  return rc;
156}
157
158ESR_ReturnCode LCHARGetInt( LCHAR* text, int* value, LCHAR** finalPosition)
159{
160  LCHAR *beg, *end;
161  LCHAR temp;
162  ESR_ReturnCode rc;
163
164  /* Skip whitespace */
165  for (beg = text; *beg != L('\0') && LISSPACE(*beg); ++beg);
166  if (beg == NULL)
167    return ESR_INVALID_ARGUMENT; /* invalid command syntax */
168  /* Find next whitespace */
169  for (end = beg; *end != L('\0') && !LISSPACE(*end); ++end);
170  if (end == NULL)
171    return ESR_INVALID_ARGUMENT; /* invalid command syntax */
172
173  temp = *end;
174  *end = L('\0');
175  rc = lstrtoi(beg, value, 10);
176  if (rc != ESR_SUCCESS)
177  {
178    *end = temp;
179    PLogError(ESR_rc2str(rc));
180    goto CLEANUP;
181  }
182  *end = temp;
183  if (finalPosition != NULL)
184    *finalPosition = end;
185  return ESR_SUCCESS;
186CLEANUP:
187  return rc;
188}
189
190ESR_ReturnCode lstrlwr(LCHAR* string)
191{
192  if (string)
193  {
194    while (*string)
195    {
196      if (LISALPHA(*string))
197        *string = (LCHAR) LTOLOWER(*string);
198      ++string;
199    }
200  }
201  else
202    return ESR_INVALID_ARGUMENT;
203
204  return ESR_SUCCESS;
205}
206
207ESR_ReturnCode lstrupr(LCHAR* string)
208{
209  if (string)
210  {
211    while (*string)
212    {
213      if (LISALPHA(*string))
214        *string = (LCHAR) LTOUPPER(*string);
215      ++string;
216    }
217  }
218  else
219    return ESR_INVALID_ARGUMENT;
220
221  return ESR_SUCCESS;
222}
223
224/* strcasecmp is not POSIX.4 API */
225ESR_ReturnCode lstrcasecmp(const LCHAR *string1, const LCHAR *string2, int *result)
226{
227
228  if (!string1 || !string2)
229    return ESR_INVALID_ARGUMENT;
230
231  while (LTOUPPER(*string1) == LTOUPPER(*string2++))
232  {
233    if (!*string1++)
234    {
235      *result = 0;
236      return ESR_SUCCESS;
237    }
238  }
239
240  *result = LTOUPPER(*string1) - LTOUPPER(*--string2);
241  return ESR_SUCCESS;
242}
243
244/**
245 * This code is from MS SDK: C:\PROGRAM FILES\MICROSOFT SDK\src\crt\xtoa.c
246 * Buffer overflow checking is left up to the caller.
247 *
248 * @param value Number to be converted
249 * @param string String result
250 * @param radix Base of value; must be in the range 2 - 36
251 */
252static void pxtoa(unsigned long val, LCHAR *buf, unsigned radix, int is_neg)
253{
254  LCHAR *p;                /* pointer to traverse string */
255  LCHAR *firstdig;         /* pointer to first digit */
256  LCHAR temp;              /* temp char */
257  unsigned digval;        /* value of digit */
258
259  p = buf;
260
261  if (is_neg)
262  {
263    /* negative, so output '-' and negate */
264    *p++ = '-';
265    val = (unsigned long)(-(long)val);
266  }
267
268  firstdig = p;           /* save pointer to first digit */
269
270  do
271  {
272    digval = (unsigned)(val % radix);
273    val /= radix;       /* get next digit */
274
275    /* convert to ascii and store */
276    if (digval > 9)
277      *p++ = (LCHAR)(digval - 10 + 'a');  /* a letter */
278    else
279      *p++ = (LCHAR)(digval + '0');       /* a digit */
280  }
281  while (val > 0);
282
283  /* We now have the digit of the number in the buffer, but in reverse
284     order.  Thus we reverse them now. */
285
286  *p-- = '\0';            /* terminate string; p points to last digit */
287
288  do
289  {
290    temp = *p;
291    *p = *firstdig;
292    *firstdig = temp;   /* swap *p and *firstdig */
293    --p;
294    ++firstdig;         /* advance to next two digits */
295  }
296  while (firstdig < p); /* repeat until halfway */
297}
298
299/*
300 * Convert an integer to a string.
301 */
302ESR_ReturnCode litostr(int value, LCHAR *string, size_t *len, int radix)
303{
304  size_t size;
305  /* pxtoa() is guaranteed not to overflow past 33 characters */
306  LCHAR buffer[33];
307
308  if (!string)
309    return ESR_INVALID_ARGUMENT;
310
311  if (radix == 10 && value < 0)
312    pxtoa((unsigned long) value, buffer, radix, 1);
313  else
314    pxtoa((unsigned long) value, buffer, radix, 0);
315
316  size = LSTRLEN(buffer);
317
318  if (size >= *len)   /* + null-terminated character */
319  {
320    *len = size;
321    return ESR_BUFFER_OVERFLOW;
322  }
323  else
324    LSTRCPY(string, buffer);
325
326  return ESR_SUCCESS;
327}
328
329
330/* Convert an unsigned long integer to a string. */
331ESR_ReturnCode lultostr(unsigned long  value, LCHAR *string, size_t *len, int radix)
332{
333  size_t size;
334  LCHAR buffer[33];
335
336  if (!string)
337    return ESR_INVALID_ARGUMENT;
338
339  pxtoa(value, buffer, radix, 0);
340
341  size = LSTRLEN(buffer);
342
343  if (size >= *len)   /* + null-terminated character */
344  {
345    *len = size;
346    return ESR_BUFFER_OVERFLOW;
347  }
348  else
349  {
350    *len = size;
351    LSTRCPY(string, buffer);
352  }
353
354  return ESR_SUCCESS;
355}
356