libarmutils  1.4
 All Data Structures Files Functions Variables Typedefs Enumerations Macros Groups
string_utils.c
Go to the documentation of this file.
1 /*******************************************************************************
2 *
3 * COPYRIGHT (C) 2010 Battelle Memorial Institute. All Rights Reserved.
4 *
5 ********************************************************************************
6 *
7 * Author:
8 * name: Brian Ermold
9 * phone: (509) 375-2277
10 * email: brian.ermold@pnl.gov
11 *
12 ********************************************************************************
13 *
14 * REPOSITORY INFORMATION:
15 * $Revision: 16166 $
16 * $Author: ermold $
17 * $Date: 2012-12-07 22:39:18 +0000 (Fri, 07 Dec 2012) $
18 *
19 ********************************************************************************
20 *
21 * NOTE: DOXYGEN is used to generate documentation for this file.
22 *
23 *******************************************************************************/
24 
25 /** @file string_utils.c
26  * String Functions.
27  */
28 
29 #include "armutils.h"
30 
31 /*******************************************************************************
32  * Private Functions
33  */
34 /** @privatesection */
35 
36 /*******************************************************************************
37  * Public Functions
38  */
39 /** @publicsection */
40 
41 /**
42  * Extract the major, minor, and micro values from a version string.
43  *
44  * This function will look for the first occurrence of "%d.%d" in the specified
45  * version string. These values will be returned as the major and minor version
46  * numbers respectively. It will then check for an optional ".%d" or "-%d"
47  * following the version number. If found, this value will be returned as the
48  * micro version number.
49  *
50  * @param string pointer to the version string
51  * @param major output: major version number
52  * @param minor output: minor version number
53  * @param micro output: micro version number
54  *
55  * @return
56  * - 3 if major, minor, and micro version numbers were found
57  * - 2 if major and minor version numbers were found
58  * - 0 if a valid version number was not found
59  */
61  const char *string,
62  int *major,
63  int *minor,
64  int *micro)
65 {
66  const char *strp = string;
67  int nfound = 0;
68  int version[3];
69 
70  if (major) *major = 0;
71  if (minor) *minor = 0;
72  if (micro) *micro = 0;
73 
74  for (; *strp != '\0'; ++strp) {
75 
76  while ((*strp != '\0') && !isdigit(*strp)) ++strp;
77 
78  if (*strp == '\0') break;
79 
80  nfound = sscanf(strp, "%d.%d.%d",
81  &version[0], &version[1], &version[2]);
82 
83  if (nfound == 2) {
84  nfound = sscanf(strp, "%d.%d-%d",
85  &version[0], &version[1], &version[2]);
86  }
87 
88  if (nfound >= 2) break;
89  }
90 
91  if (nfound < 2) {
92  return(0);
93  }
94 
95  if (major && (nfound >= 1)) *major = version[0];
96  if (minor && (nfound >= 2)) *minor = version[1];
97  if (micro && (nfound >= 3)) *micro = version[2];
98 
99  return(nfound);
100 }
101 
102 /**
103  * Qsort numeric string compare function.
104  *
105  * This function can be used by qsort to sort an array of string
106  * pointers by using the numeric values found within the strings.
107  * The first numbers found in the strings will be compared, if those
108  * are equal the next numbers found will be used, and so on and so
109  * fourth, until no more numbers are found in the strings. If all
110  * numeric values are equal, the strcmp result will be returned.
111  *
112  * @param str1 - pointer to pointer to string 1
113  * @param str2 - pointer to pointer to string 2
114  */
115 int qsort_numeric_strcmp(const void *str1, const void *str2)
116 {
117  const char *s1 = *(const char **)str1;
118  const char *s2 = *(const char **)str2;
119  long n1, n2;
120 
121  while (1) {
122 
123  while (*s1 && !isdigit(*s1)) s1++;
124  while (*s2 && !isdigit(*s2)) s2++;
125 
126  if (*s1 && *s2) {
127 
128  n1 = strtol(s1, (char **)&s1, 10);
129  n2 = strtol(s2, (char **)&s2, 10);
130 
131  if (n1 > n2) return(1);
132  else if (n1 < n2) return(-1);
133  }
134  else if (*s1) return(1);
135  else if (*s2) return(-1);
136  else {
137  return(strcmp(*(const char **)str1, *(const char **)str2));
138  }
139  }
140 }
141 
142 /**
143  * Qsort string compare function.
144  *
145  * This function can be used by qsort to sort an array of string pointers.
146  *
147  * @param str1 - pointer to pointer to string 1
148  * @param str2 - pointer to pointer to string 2
149  */
150 int qsort_strcmp(const void *str1, const void *str2)
151 {
152  return(strcmp(*(const char **)str1, *(const char **)str2));
153 }
154 
155 /**
156  * Copy a string.
157  *
158  * The returned string is dynamically allocated and must be freed by
159  * the calling process.
160  *
161  * Error messages from this function are sent to the message handler
162  * (see msngr_init_log() and msngr_init_mail()).
163  *
164  * @param string - the string to copy
165  *
166  * @return
167  * - pointer to the copy of the string
168  * - NULL if a memory allocation error occurred
169  */
170 char *string_copy(const char *string)
171 {
172  char *copy = strdup(string);
173 
174  if (!copy) {
175 
177  "Could not copy string: '%s'\n"
178  " -> memory allocation error\n", string);
179  }
180 
181  return(copy);
182 }
183 
184 /**
185  * Create a new string.
186  *
187  * This functions creates a new string under the control of the format
188  * argument. The returned string is dynamically allocated and must be
189  * freed by the calling process.
190  *
191  * Error messages from this function are sent to the message handler
192  * (see msngr_init_log() and msngr_init_mail()).
193  *
194  * @param format - format string (see printf)
195  * @param ... - arguments for the format string
196  *
197  * @return
198  * - pointer to the new string
199  * - NULL if a memory allocation error occurred
200  */
201 char *string_create(const char *format, ...)
202 {
203  va_list args;
204  char *string;
205 
206  va_start(args, format);
207  string = msngr_format_va_list(format, args);
208  va_end(args);
209 
210  if (!string) {
211 
213  "Could not create string for format string: '%s'\n"
214  " -> memory allocation error\n", format);
215  }
216 
217  return(string);
218 }
219 
220 /**
221  * Create a new string.
222  *
223  * This functions creates a new string under the control of the format
224  * argument. The returned string is dynamically allocated and must be
225  * freed by the calling process.
226  *
227  * Error messages from this function are sent to the message handler
228  * (see msngr_init_log() and msngr_init_mail()).
229  *
230  * @param format - format string (see printf)
231  * @param args - arguments for the format string
232  *
233  * @return
234  * - pointer to the new string
235  * - NULL if a memory allocation error occurred
236  */
237 char *string_create_va_list(const char *format, va_list args)
238 {
239  char *string = msngr_format_va_list(format, args);
240 
241  if (!string) {
242 
244  "Could not create string for format string: '%s'\n"
245  " -> memory allocation error\n", format);
246  }
247 
248  return(string);
249 }
250 
251 /**
252  * Read numeric values from a string.
253  *
254  * This function will read all the numerical values from a string
255  * and store them in the specified buffer. All strings of * characters
256  * will also be extracted as -9999.
257  *
258  * @param string - pointer to the string
259  * @param buflen - the maximum number of values the buffer can hold
260  * @param buffer - output buffer
261  *
262  * @return
263  * The number of values read from the string or the number of
264  * values that would have been read from the string if the
265  * buffer had been large enough.
266  */
267 int string_to_doubles(char *string, int buflen, double *buffer)
268 {
269  int nvals = 0;
270  char *endp = (char *)NULL;
271  char *strp;
272  double value;
273 
274  for (strp = string; *strp != '\0'; ++strp) {
275 
276  while(*strp == ' ') ++strp;
277  if (*strp == '\0') break;
278 
279  if (*strp == '*') {
280  endp = strp;
281  while(*endp == '*') ++endp;
282  value = -9999.0;
283  }
284  else {
285  value = strtod(strp, &endp);
286  }
287 
288  if (endp != strp) {
289 
290  if (nvals < buflen)
291  buffer[nvals] = value;
292 
293  nvals++;
294  strp = endp;
295  if (*strp == '\0') break;
296  }
297  }
298 
299  return(nvals);
300 }
301 
302 /**
303  * Read numeric values from a string.
304  *
305  * This function will read all the numerical values from a string
306  * and store them in the specified buffer. All strings of * characters
307  * will also be extracted as -9999.
308  *
309  * @param string - pointer to the string
310  * @param buflen - the maximum number of values the buffer can hold
311  * @param buffer - output buffer
312  *
313  * @return
314  * The number of values read from the string or the number of
315  * values that would have been read from the string if the
316  * buffer had been large enough.
317  */
318 int string_to_floats(char *string, int buflen, float *buffer)
319 {
320  int nvals = 0;
321  char *endp = (char *)NULL;
322  char *strp;
323  double value;
324 
325  for (strp = string; *strp != '\0'; ++strp) {
326 
327  while(*strp == ' ') ++strp;
328  if (*strp == '\0') break;
329 
330  if (*strp == '*') {
331  endp = strp;
332  while(*endp == '*') ++endp;
333  value = -9999.0;
334  }
335  else {
336  value = strtod(strp, &endp);
337  }
338 
339  if (endp != strp) {
340 
341  if (nvals < buflen)
342  buffer[nvals] = (float)value;
343 
344  nvals++;
345  strp = endp;
346  if (*strp == '\0') break;
347  }
348  }
349 
350  return(nvals);
351 }
352 
353 /**
354  * Read numeric values from a string.
355  *
356  * This function will read all the numerical values from a string
357  * and store them in the specified buffer. All strings of * characters
358  * will also be extracted as -9999.
359  *
360  * @param string - pointer to the string
361  * @param buflen - the maximum number of values the buffer can hold
362  * @param buffer - output buffer
363  *
364  * @return
365  * The number of values read from the string or the number of
366  * values that would have been read from the string if the
367  * buffer had been large enough.
368  */
369 int string_to_ints(char *string, int buflen, int *buffer)
370 {
371  int nvals = 0;
372  char *endp = (char *)NULL;
373  char *strp;
374  long value;
375 
376  for (strp = string; *strp != '\0'; ++strp) {
377 
378  while(*strp == ' ') ++strp;
379  if (*strp == '\0') break;
380 
381  if (*strp == '*') {
382  endp = strp;
383  while(*endp == '*') ++endp;
384  value = -9999;
385  }
386  else {
387  value = strtol(strp, &endp, 0);
388  }
389 
390  if (endp != strp) {
391 
392  if (nvals < buflen)
393  buffer[nvals] = (int)value;
394 
395  nvals++;
396  strp = endp;
397  if (*strp == '\0') break;
398  }
399  }
400 
401  return(nvals);
402 }
403 
404 /**
405  * Read numeric values from a string.
406  *
407  * This function will read all the numerical values from a string
408  * and store them in the specified buffer. All strings of * characters
409  * will also be extracted as -9999.
410  *
411  * @param string - pointer to the string
412  * @param buflen - the maximum number of values the buffer can hold
413  * @param buffer - output buffer
414  *
415  * @return
416  * The number of values read from the string or the number of
417  * values that would have been read from the string if the
418  * buffer had been large enough.
419  */
420 int string_to_longs(char *string, int buflen, long *buffer)
421 {
422  int nvals = 0;
423  char *endp = (char *)NULL;
424  char *strp;
425  long value;
426 
427  for (strp = string; *strp != '\0'; ++strp) {
428 
429  while(*strp == ' ') ++strp;
430  if (*strp == '\0') break;
431 
432  if (*strp == '*') {
433  endp = strp;
434  while(*endp == '*') ++endp;
435  value = -9999;
436  }
437  else {
438  value = strtol(strp, &endp, 0);
439  }
440 
441  if (endp != strp) {
442 
443  if (nvals < buflen)
444  buffer[nvals] = value;
445 
446  nvals++;
447  strp = endp;
448  if (*strp == '\0') break;
449  }
450  }
451 
452  return(nvals);
453 }
454 
455 /**
456  * Trim the tag from a repository string.
457  *
458  * This function will extract the repository value by trimming the
459  * leading tag and trailing $ from it.
460  *
461  * @param string - repository string
462  * @param buflen - length of the output buffer
463  * @param buffer - pointer to the output buffer
464  *
465  * @return pointer to the output buffer
466  */
468  const char *string,
469  int buflen,
470  char *buffer)
471 {
472  char *cp;
473 
474  buffer[0] = '\0';
475 
476  cp = (char *)strchr(string, ':');
477  if (cp) {
478  for (cp++; (*cp == ' ') && (*cp != '\0'); cp++);
479 
480  strncpy(buffer, cp, buflen);
481  buffer[buflen-1] = '\0';
482 
483  cp = (char *)strrchr(buffer, '$');
484  if (cp) {
485  for (cp--; (*cp == ' ') && (cp != buffer); cp--);
486 
487  if (cp == buffer)
488  *cp = '\0';
489  else
490  *++cp = '\0';
491  }
492  }
493 
494  return(buffer);
495 }
496 
497 /**
498  * Trim all space characters from the end of a string.
499  *
500  * This function replaces all isspace() characters at the
501  * end of a string with the terminating null character.
502  *
503  * @param string - the string to trim
504  *
505  * @return pointer to the modified input string
506  */
507 char *trim_trailing_spaces(char *string)
508 {
509  char *chrp;
510 
511  if (string) {
512  chrp = &string[strlen(string)-1];
513  while (isspace(*chrp) && chrp != string) *chrp-- = '\0';
514  }
515 
516  return(string);
517 }