+int getStringArrayLength(char **s_array)
+{
+ int num_strings = 0;
+
+ if (s_array == NULL)
+ return 0;
+
+ while (s_array[num_strings] != NULL)
+ num_strings++;
+
+ return num_strings;
+}
+
+void freeStringArray(char **s_array)
+{
+ int i;
+
+ if (s_array == NULL)
+ return;
+
+ for (i = 0; s_array[i] != NULL; i++)
+ checked_free(s_array[i]);
+
+ checked_free(s_array);
+}
+
+char *getEscapedString(const char *s)
+{
+ const unsigned char *s_ptr = (unsigned char *)s;
+ char *s_escaped;
+ char *s_escaped_ptr;
+
+ if (s == NULL)
+ return NULL;
+
+ /* Each source byte needs maximally four target chars (\777) */
+ s_escaped = checked_malloc(strlen(s) * 4 + 1);
+ s_escaped_ptr = s_escaped;
+
+ while (*s_ptr != '\0')
+ {
+ switch (*s_ptr)
+ {
+ case '\b':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 'b';
+ break;
+
+ case '\f':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 'f';
+ break;
+
+ case '\n':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 'n';
+ break;
+
+ case '\r':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 'r';
+ break;
+
+ case '\t':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 't';
+ break;
+
+ case '\v':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = 'v';
+ break;
+
+ case '\\':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = '\\';
+ break;
+
+ case '"':
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = '"';
+ break;
+
+ default:
+ if ((*s_ptr < ' ') || (*s_ptr >= 0177))
+ {
+ *s_escaped_ptr++ = '\\';
+ *s_escaped_ptr++ = '0' + (((*s_ptr) >> 6) & 07);
+ *s_escaped_ptr++ = '0' + (((*s_ptr) >> 3) & 07);
+ *s_escaped_ptr++ = '0' + ( (*s_ptr) & 07);
+ }
+ else
+ {
+ *s_escaped_ptr++ = *s_ptr;
+ }
+ break;
+ }
+
+ s_ptr++;
+ }
+
+ *s_escaped_ptr = '\0';
+
+ return s_escaped;
+}
+
+char *getUnescapedString(const char *s)
+{
+ const char *s_ptr = s;
+ const char *octal_ptr;
+ char *s_unescaped;
+ char *s_unescaped_ptr;
+
+ if (s == NULL)
+ return NULL;
+
+ s_unescaped = checked_malloc(strlen(s) + 1);
+ s_unescaped_ptr = s_unescaped;
+
+ while (*s_ptr != '\0')
+ {
+ if (*s_ptr == '\\')
+ {
+ s_ptr++;
+
+ switch (*s_ptr)
+ {
+ case '\0':
+ Warn("getUnescapedString: trailing \\");
+ goto out;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ *s_unescaped_ptr = 0;
+ octal_ptr = s_ptr;
+
+ while (s_ptr < octal_ptr + 3 && *s_ptr >= '0' && *s_ptr <= '7')
+ {
+ *s_unescaped_ptr = (*s_unescaped_ptr * 8) + (*s_ptr - '0');
+ s_ptr++;
+ }
+
+ s_unescaped_ptr++;
+ s_ptr--;
+ break;
+
+ case 'b':
+ *s_unescaped_ptr++ = '\b';
+ break;
+
+ case 'f':
+ *s_unescaped_ptr++ = '\f';
+ break;
+
+ case 'n':
+ *s_unescaped_ptr++ = '\n';
+ break;
+
+ case 'r':
+ *s_unescaped_ptr++ = '\r';
+ break;
+
+ case 't':
+ *s_unescaped_ptr++ = '\t';
+ break;
+
+ case 'v':
+ *s_unescaped_ptr++ = '\v';
+ break;
+
+ default:
+ /* also handles \" and \\ */
+ *s_unescaped_ptr++ = *s_ptr;
+ break;
+ }
+ }
+ else
+ {
+ *s_unescaped_ptr++ = *s_ptr;
+ }
+
+ s_ptr++;
+ }
+
+ out:
+ *s_unescaped_ptr = '\0';
+
+ return s_unescaped;
+}
+
+char *chugString(char *s)
+{
+ if (s == NULL)
+ return NULL;
+
+ char *start;
+
+ for (start = (char *)s; *start && isspace(*start); start++)
+ ;
+
+ memmove(s, start, strlen(start) + 1);
+
+ return s;
+}
+
+char *chompString(char *s)
+{
+ if (s == NULL)
+ return NULL;
+
+ int len = strlen(s);
+
+ while (len--)
+ {
+ if (isspace(s[len]))
+ s[len] = '\0';
+ else
+ break;
+ }
+
+ return s;
+}
+
+char *stripString(char *s)
+{
+ return chugString(chompString(s));
+}
+