Back to index

tetex-bin  3.0
Defines | Enumerations | Functions
string-utils.h File Reference
#include "xdvi-config.h"
#include "kpathsea/c-vararg.h"
#include "my-vsnprintf.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Defines

#define XDVI_GET_STRING_ARGP(buf, fmt)

Enumerations

enum  expandPathTypeT { USE_DVI_PATH, USE_CWD_PATH }

Functions

Boolean str_is_prefix (const char *, const char *, Boolean case_sensitive)
Boolean str_is_suffix (const char *, const char *, Boolean case_sensitive)
Boolean is_spaces_only (const char *)
char * my_stristr (const char *haystack, const char *needle)
char * filename_append_dvi (const char *fname)
char * expand_filename (const char *fname, expandPathTypeT type)
char * expand_filename_append_dvi (const char *fname, expandPathTypeT type, Boolean must_exist)
char * canonicalize_path (const char *path)
char * format_arg (const char *fmt, const char *arg, int *match)
char * escape_format_arg (const char *arg)
char * unquote_arg (const char *fmt, const char *arg, int *match, int *len)
char * get_dir_component (const char *path)
char ** get_separated_list (const char *source, const char *sep, Boolean do_unquote)
const char * find_format_str (const char *input, const char *fmt)
Boolean src_compare (const char *src, int src_len, const char *target, const char *path, size_t path_len)
char * shell_escape_string (const char *str)
void replace_extension (const char *fname, const char *extension, char *buf, size_t name_len)
int length_of_int (int n)
char * get_string_va (const char *fmt,...)
double my_atof (const char *str)

Define Documentation

#define XDVI_GET_STRING_ARGP (   buf,
  fmt 
)
Value:
do {                                                                         \
        va_list argp;                                                                      \
       int CHUNK_LEN = 128;                                                         \
       int curr_len = CHUNK_LEN, need_len;                                                 \
                                                                                    \
       buf = NULL;                                                                  \
                                                                                    \
       for (;;) {                                                                   \
            /* see man page for vsnprintf: for glibc 2.0, <need_len> is */                 \
            /* -1 if <buf> had been trucated to <curr_len>; for glibc 2.1, */                     \
            /* it's the total length of <fmt>; so the following works */                   \
            /* with both versions: */                                                      \
           buf = xrealloc(buf, curr_len);                                           \
                                                                                    \
           va_start(argp, fmt);                                                     \
           need_len = VSNPRINTF(buf, curr_len, fmt, argp);                                 \
            va_end(argp);                                                           \
												\
	    if (need_len > -1 && need_len < curr_len) { /* <curr_len> was large enough */  \
              break;                                                                \
           }                                                                        \
           if (need_len > -1) {    /* now need_len + 1 is the exact space needed */ \
              curr_len = need_len + 1;                                              \
           }                                                                        \
           else {    /* try again with larger <len> */                              \
              curr_len += CHUNK_LEN;                                                       \
           }                                                                        \
       }                                                                            \
    } while (0)                                                                            \

Definition at line 50 of file string-utils.h.


Enumeration Type Documentation

Enumerator:
USE_DVI_PATH 
USE_CWD_PATH 

Definition at line 14 of file string-utils.h.


Function Documentation

char* canonicalize_path ( const char *  path)

Definition at line 580 of file string-utils.c.

{
    char *p, *q, *start;
    char c;
    size_t len = strlen(path);

    assert(path != NULL);
    assert(*path == '/');

    start = q = p = xstrdup(path);

    /* len is the length of string */
    while (p < start + len) {
       if ((c = p[1]) == '/') {
           /* remove multiple '/' in pathname */
           memmove(p + 1, p + 2, len - (p + 2 - start) + 1);
           len--;
           continue;
       }
       else if (c == '.') {
           if ((c = p[2]) == '/') {
              /* p = '/.' in pathname */
              memmove(p + 1, p + 3, len - (p + 3 - start) + 1);
              len -= 2;
              continue;
           }
           else if (c == '.' && ((c = p[3]) == '/' || c == '\0')) {
              /* p == "/.." */
              memmove(q, p + 3, len - (p + 3 - start) + 1);
              len -= (p - q) + 3;
              p = q;
              /* check if the new dirname at p is "//" or './' or '../' */
              if ((c = p[1]) == '/')
                  continue;
              else if (c == '.') {
                  if ((c = p[2]) == '/')
                     continue;
                  else if (c == '.' && ((c = p[3]) == '/' || c == '\0')) {
                     while (--q >= start && *q != '/');
                     if (q < start)
                         q = start;
                     continue;
                  }
              }
           }
       }

       /* search next '/' */
       q = p;
       while (++p <= start + len && *p != '/');
    }

    return start;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* escape_format_arg ( const char *  arg)

Definition at line 272 of file string-utils.c.

{
    char *ret, *ptr;
    ASSERT(arg != NULL, "");
    ret = xmalloc(strlen(arg) * 2 + 1); /* more than enuff */
    
    ptr = ret;
    while (*arg != '\0') {
       /* need to escape? */
       if (*arg == '%' && (ptr == ret
                         || (ptr > ret && *(arg - 1) != '%'))) {
           *ptr++ = '%';
       }
       *ptr++ = *arg++;
    }
    *ptr = '\0';

    /* trim return buffer */
    return xrealloc(ret, strlen(ret) + 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* expand_filename ( const char *  fname,
expandPathTypeT  type 
)

Definition at line 136 of file string-utils.c.

{
    char *path_name = NULL;

    if (*filename == '/') /* already an absolute path */
       return xstrdup(filename);
    
    if (type == USE_CWD_PATH) {
       size_t path_name_len = 512;
       size_t len = strlen(filename) + 1;

       /* append to cwd if it's not already a full path */
       if (filename[0] != '/') {
           for (;;) {
              char *tmp;
              path_name = xrealloc(path_name, path_name_len);
              if ((tmp = getcwd(path_name, path_name_len)) == NULL && errno == ERANGE) {
                  path_name_len *= 2;
              }
              else {
                  path_name = tmp;
                  break;
              }
           }
           len += strlen(path_name) + 1;  /* 1 for '/' */
           path_name = xrealloc(path_name, len);
           strcat(path_name, "/");
           strcat(path_name, filename);
       }
       
       TRACE_HTEX((stderr,
                  "Expanding filename |%s| with CWD gives |%s|",
                  filename, path_name == NULL ? "<NULL>" : path_name));
       return path_name ? path_name : xstrdup(filename);
    }
    else {
       ASSERT(globals.dvi_file.dirname != NULL, "globals.dvi_file.dirname should have been initialized before");
       path_name = xstrdup(globals.dvi_file.dirname);
       path_name = xstrcat(path_name, filename);
       TRACE_HTEX((stderr,
                  "Expanding filename |%s| with globals.dvi_file.dirname |%s| gives |%s|",
                  filename, globals.dvi_file.dirname, path_name));
       return path_name;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* expand_filename_append_dvi ( const char *  fname,
expandPathTypeT  type,
Boolean  must_exist 
)

Definition at line 239 of file string-utils.c.

{
    char canonical_path[MAXPATHLEN + 1];
    char *normalized_fname = filename_append_dvi(filename);
    char *expanded_fname = expand_filename(normalized_fname, type);
    if (must_exist) {
       char *canonical_name = REALPATH(expanded_fname, canonical_path);
       free(normalized_fname);
       free(expanded_fname);
       return xstrdup(canonical_name);
    }
    else {
       free(normalized_fname);
       return expanded_fname;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* filename_append_dvi ( const char *  fname)

Definition at line 186 of file string-utils.c.

{
    char *expanded_filename = NULL;
    const char *orig_filename = filename;
    size_t len;
    char *p;
    
    /* skip over `file:' prefix if present */
    if (str_is_prefix("file:", filename, True)) {
       filename += strlen("file:");
       if (str_is_prefix("//", filename + strlen("file:"), True)) { /* is there a hostname following? */
           char *tmp = strchr(filename+2, '/'); /* skip over host name */
           if (tmp == NULL) {
              XDVI_WARNING((stderr, "Malformed hostname part in filename `%s'; not expanding file name",
                           orig_filename));
           }
           else {
              /* deal with multiple `//' after "file://localhost";
                 while the RFC seems to suggest that file://localhost/foo/bar defines a path
                 `foo/bar', most browsers (and actually, also libwww) will treat this path as absolute:
                 `/foo/bar'. So we treat
                 file://localhost//foo/bar
                 and
                 file://localhost/foo/bar
                 as equivalent.
              */
              while (*(tmp+1) == '/') 
                  tmp++;
              filename = tmp;
           }
       }
    }

    len = strlen(filename) + 5; /* 5 in case we need to add `.dvi\0' */

    expanded_filename = xmalloc(len);

    strcpy(expanded_filename, filename);

    /* Append ".dvi" extension if no extension is present.
       Only look at the filename part when trying to find a `.'.
     */
    if ((p = strrchr(expanded_filename, '/')) == NULL) {
       p = expanded_filename;
    }
    if ((p = strrchr(p, '.')) == NULL) {
       TRACE_HTEX((stderr, "appending .dvi extension to filename |%s|", expanded_filename));
       strcat(expanded_filename, ".dvi");
    }
    return expanded_filename;
}

Here is the call graph for this function:

Here is the caller graph for this function:

const char* find_format_str ( const char *  input,
const char *  fmt 
)

Definition at line 395 of file string-utils.c.

{
    const char *ptr = input;
    while ((ptr = strstr(ptr, fmt)) != NULL) {
       if (ptr > input && *(ptr - 1) == '\\') {
           ptr++;
           continue;
       }
       else
           return ptr;
    }
    return NULL;
}

Here is the caller graph for this function:

char* format_arg ( const char *  fmt,
const char *  arg,
int match 
)

Definition at line 257 of file string-utils.c.

{
    char *tmp = xmalloc(strlen(fmt) + strlen(arg) + 1);
    if (strchr(fmt, '%') != NULL) {
       sprintf(tmp, fmt, arg);
       *match = 1;
    }
    else {
       strcpy(tmp, fmt);
    }
    return tmp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* get_dir_component ( const char *  path)

Definition at line 411 of file string-utils.c.

{
    char *ret = NULL;
    char *p;
    
    if ((p = strrchr(path, '/')) != NULL) {
       /* copy, chop off filename (but not the '/') */
       ret = xstrdup(path);
       *(ret + (p - path) + 1) = '\0';
       TRACE_CLIENT((stderr, "get_dir_component of |%s| is |%s|\n", path, ret));
    }
    return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char** get_separated_list ( const char *  source,
const char *  sep,
Boolean  do_unquote 
)

Definition at line 326 of file string-utils.c.

{
    /* allocate at least list of size 1, for NULL termination below */
    char **chunks = xmalloc(sizeof *chunks);
    const char *b_ptr, *e_ptr;
    size_t i = 0;
    
    b_ptr = source;

    while (*b_ptr != '\0' && strchr(sep, *b_ptr) != NULL)
       b_ptr++;
    
    for (i = 0; *b_ptr != '\0'; i++) {
       char *quote;
       char quotechar = 0;
       size_t len, chunk_len, alloc_len = 0;
       
       if ((len = strcspn(b_ptr, sep)) == 0) /* at end */
           break;

       /* check for quoted chunk, in which case we don't want to treat
          spaces as chunk separators */
       if (do_unquote && (quote = strchr("'\"", *b_ptr)) != NULL) {
           const char *curr = b_ptr + 1;
           quotechar = *quote;

           for (;;) { /* find end of quote */
              char *maybe_end = strchr(curr, quotechar);
              if (maybe_end != NULL) {
                  if (maybe_end - curr > 0 &&
                     *(maybe_end - 1) == '\\') { /* escaped quote */
                     curr = ++maybe_end;
                  }
                  else { /* found */
                     b_ptr++;
                     len = maybe_end - b_ptr;
                     break;
                  }
              }
              else { /* not found end - warn, and forget about this quote */
                  XDVI_WARNING((stderr, "Unmatched quote character in string `%s'", b_ptr));
                  break;
              }
           }
       }
       
       e_ptr = b_ptr + len;
       chunk_len = e_ptr - b_ptr;
       while (i + 1 >= alloc_len) {
           alloc_len++;
       }
       chunks = xrealloc(chunks, alloc_len * sizeof *chunks);
       chunks[i] = xmalloc(chunk_len + 1);
       memcpy(chunks[i], b_ptr, chunk_len);
       chunks[i][chunk_len] = '\0';

       /* skip trailing quotechar and spaces */
       b_ptr = e_ptr;
       if (do_unquote && quotechar != 0 && *b_ptr == quotechar)
           b_ptr++;
       while (*b_ptr != '\0' && strchr(sep, *b_ptr) != NULL)
           b_ptr++;
    }
    /* terminate list with NULL element */
    chunks[i] = NULL;
    return chunks;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* get_string_va ( const char *  fmt,
  ... 
)

Definition at line 694 of file string-utils.c.

{
    char *buf = NULL;
    XDVI_GET_STRING_ARGP(buf, fmt);
    return buf;
}

Here is the caller graph for this function:

Definition at line 736 of file string-utils.c.

{
    for (; *ptr; ptr++) {
       if (!isspace((int)*ptr))
           return False;
    }
    return True;
}

Definition at line 719 of file string-utils.c.

{
    int ret = 1;

    if (n < 0) {
       ret++;
       n *= -1;
    }
    while (n >= 10) {
       n /= 10;
       ret++;
    }

    return ret;
}

Here is the caller graph for this function:

double my_atof ( const char *  str)

Definition at line 705 of file string-utils.c.

{
    char *ptr;
    double f;
    
    f = strtod(str, (char **)&ptr);
    if (*ptr != '\0') {
       XDVI_WARNING((stderr, "strtod: incomplete conversion of %s to %f", str, f));
    }
    return f;
}

Here is the caller graph for this function:

char* my_stristr ( const char *  haystack,
const char *  needle 
)

Definition at line 105 of file string-utils.c.

{
  const char *curr;

  for (curr = haystack; *curr != '\0'; curr++) {
      const char *ptr1, *ptr2;
      /* search for first character */
      for (; ((*curr != '\0') && (tolower((int)*curr) != *needle)); curr++) { ; }

      if (*curr == '\0') /* not found */
       return NULL;

      /* now compare other characters */
      ptr1 = needle;
      ptr2 = curr;
      while (tolower((int)*ptr2) == *ptr1) {
         ptr2++;
         ptr1++;
         /* success if at end of needle */
         if (*ptr1 == '\0')
             return (char *)curr;
      }
  }
  return NULL;
}
void replace_extension ( const char *  fname,
const char *  extension,
char *  buf,
size_t  name_len 
)

Definition at line 667 of file string-utils.c.

{
    char *sep;
    if ((sep = strrchr(fname, '.')) != NULL) {
       size_t len = strlen(extension);
       if (len + (sep - fname) > buf_len)
           return;
       strncpy(buf, fname, sep - fname);
       strcpy(buf + (sep - fname), extension);
    }
    return;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* shell_escape_string ( const char *  str)

Definition at line 641 of file string-utils.c.

{
    size_t len = strlen(str);
    char *new_str = xmalloc(len * 2 + 1); /* safe amount, since each char will be doubled at most */
    
    const char *src_ptr = str;
    char *target_ptr = new_str;
    while (*src_ptr != '\0') {
       if (*src_ptr == '\\'
           || *src_ptr == '`'
           || *src_ptr == '('
           || *src_ptr == ')'
           || *src_ptr == ';') {
#if 0
           /* only if not yet escaped? */
           && (src_ptr == str || (src_ptr > str && *(src_ptr - 1) != '\\'))) {
#endif
           *target_ptr++ = '\\';
       }
       *target_ptr++ = *src_ptr++;
    }
    *target_ptr = '\0'; /* terminate */
    return new_str;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean src_compare ( const char *  src,
int  src_len,
const char *  target,
const char *  path,
size_t  path_len 
)

Definition at line 435 of file string-utils.c.

{
    int i, j;
    Boolean matched = True;

    /* This macro sets the `src' pointer to `dvi_path' after having
       dropped off the beginning of src, or returns False if dvi_path
       is NULL (which either means that `src' was an absolute path, or
       that the dvi_path has been used up already).
    */
#define CHK_USE_DIR(i)                                                       \
       if (i == -1) {                                                        \
           if (dvi_path == NULL) /* already done */                          \
              return False;                                           \
           src = dvi_path;                                            \
           dvi_path = NULL;                                           \
           i = dvi_path_len - 1;                                      \
           MYTRACE((stderr, "swapped, now using: |%s| of len %d", src, i));  \
       }

    /* ignore path in both filenames if one of them does not contain a path */
    {
       char *src_p = strrchr(src, '/');
       char *target_p = strrchr(target, '/');

       if (src_p == NULL) {
           dvi_path = NULL;
           if (target_p != NULL)
              target = target_p + 1;
       }

       if (target_p == NULL) {
           dvi_path = NULL;
           if (src_p != NULL)
              src = src_p + 1;
       }
    }

    /* don't prepend dvi_path if src is absolute */
    if (*src == '/') { 
       dvi_path = NULL;
    }
    
    /* skip `.tex' suffix in strings if present */
    i = src_len;
    MYTRACE((stderr, "len of |%s| %d", src, i));
    if (i >= 4 && strcmp(src + (i - 4), ".tex") == 0) {
       MYTRACE((stderr, "src |%s| has .tex suffix!", src));
       i -= 4;
    }

    j = strlen(target);
    MYTRACE((stderr, "len of |%s| %d", target, j));
    if (j >= 4 && strcmp(target + (j - 4), ".tex") == 0) {
       MYTRACE((stderr, "target |%s| has .tex suffix!", target));
       j -= 4;
    }

    /* start with index of last char */
    i--;
    j--;

    while (i >= 0 && j >= 0) {
       int skip_dirs = 0;
/*     fprintf(stderr, "check: %d[%c]\n", i, src[i]); */
       while (src[i] == '.' && src[i + 1] == '/') { /* normalize `../' and `./' */
           MYTRACE((stderr, "check2: %d[%c]", i, src[i]));

           if (i >= 2 && src[i - 1] == '.' && src[i - 2] == '/') {
              MYTRACE((stderr, "case /.."));
              i -= 3;
              skip_dirs++;
           }
           else if (i == 1) { /* `../' or `/./' at start of src */
              if (src[0] == '.') { /* `../' */
                  MYTRACE((stderr, "../ at start"));
                  i -= 2;
                  skip_dirs++;
              }
              else if (src[0] == '/') { /* `/./' */
                  MYTRACE((stderr, "/./ at start"));
                  i -= 1;
              }
              else /* something else */
                  break;
           }
           else if (i == 0 || (i > 1 && src[i - 1] == '/')) { /* ./ at start, or /./ somewhere */
              i -= 1;
           }
           else /* might be `abc./' or `abc../' (strange but legal) */
              break;

           CHK_USE_DIR(i);
           while (i >= 0 && src[i] == '/') i--;
           CHK_USE_DIR(i);
           
           while (src[i] != '.' && skip_dirs-- > 0) { /* unless there are subsequent `../' */
              /* skip directories backwards */
              while (i >= 0 && src[i] != '/') {
                  MYTRACE((stderr, "non-slash: %d,%c", i, src[i]));
                  i--;
              }
              CHK_USE_DIR(i);
              while (i >= 0 && src[i] == '/') {
                  MYTRACE((stderr, "slash: %d,%c", i, src[i]));
                  i--;
              }
              CHK_USE_DIR(i);
              MYTRACE((stderr, "skipped backwards: %d,%c", i, src[i]));
           }
       }

       /* skip multiple '/'. No need to fall off the beginning of src and use
          CHK_USE_DIR() here, since with (multiple) '/' at the beginning, src
          must be an absolute path. */
       while (i > 0 && src[i] == '/' && src[i - 1] == '/') {
           i--;
       }
       
       MYTRACE((stderr, "comparing: %d[%c] - %d[%c]", i, src[i], j, target[j]));
       if (src[i] != target[j]) {
           matched = False;
           break;
       }
       if (i == 0 && j == 0) /* at start of both strings */
           break;
       i--;
       j--;
       CHK_USE_DIR(i);
    }

    if (i != 0 || j != 0) /* not at start of both strings, no match */
       return False;
    else
       return matched;
#undef CHK_USE_DIR
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean str_is_prefix ( const char *  ,
const char *  ,
Boolean  case_sensitive 
)

Definition at line 48 of file string-utils.c.

{
    int i;

    for (i = 0; *str1 != '\0' && *str2 != '\0'; i++) {
       if ((case_sensitive && *str1 != *str2) ||
           (!case_sensitive && *str1 != tolower((int)*str2)))
           return False;
       str1++;
       str2++;
    }
    return *str1 == '\0';
}

Here is the caller graph for this function:

Boolean str_is_suffix ( const char *  ,
const char *  ,
Boolean  case_sensitive 
)

Definition at line 77 of file string-utils.c.

{
    int len1 = strlen(str1);
    int len2 = strlen(str2);

    while (len2 > len1) {
       str2++;
       len2--;
    }
    if (case_sensitive)
       return strcmp(str1, str2) == 0;
    else
       /* also compare terminating 0; second string
          is assumed to be all-lowercase! */
       return memicmp(str2, str1, len1 + 1) == 0;
}

Here is the call graph for this function:

char* unquote_arg ( const char *  fmt,
const char *  arg,
int match,
int len 
)

Definition at line 294 of file string-utils.c.

{
    char *ptr;
    char c;
    
    c = fmt[0];
    fmt++;
    if ((ptr = strchr(fmt, c)) != NULL) {
       *ptr++ = '\0';
       while (*ptr == ' ' || *ptr == '\t') {
           ptr++;
       }
       *len = ptr - fmt;
       return format_arg(fmt, arg, match);
    }
    else {
       *len = strlen(fmt);
       XDVI_WARNING((stderr, "Ignoring lonesome quote in string %s", fmt - 1));
       return format_arg(fmt, arg, match);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function: