"Fossies" - the Fresh Open Source Software Archive

Member "navit-0.5.6/navit/util.c" (6 Mar 2021, 39294 Bytes) of package /linux/privat/navit-0.5.6.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "util.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 0.5.5_vs_0.5.6.

    1 /**
    2  * Navit, a modular navigation system.
    3  * Copyright (C) 2005-2008 Navit Team
    4  *
    5  * This program is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU General Public License
    7  * version 2 as published by the Free Software Foundation.
    8  *
    9  * This program is distributed in the hope that it will be useful,
   10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12  * GNU General Public License for more details.
   13  *
   14  * You should have received a copy of the GNU General Public License
   15  * along with this program; if not, write to the
   16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   17  * Boston, MA  02110-1301, USA.
   18  */
   19 
   20 #include <stdlib.h>
   21 #include <glib.h>
   22 #include <ctype.h>
   23 #include <stdarg.h>
   24 #include <time.h>
   25 #include <limits.h>
   26 #include <string.h>
   27 #include <stdio.h>
   28 
   29 #ifdef _POSIX_C_SOURCE
   30 #include <unistd.h>
   31 #include <sys/types.h>
   32 #include <sys/wait.h>
   33 #endif
   34 #ifdef _MSC_VER
   35 typedef int ssize_t ;
   36 #endif
   37 #include "util.h"
   38 #include "debug.h"
   39 #include "config.h"
   40 
   41 void strtoupper(char *dest, const char *src) {
   42     while (*src)
   43         *dest++=toupper(*src++);
   44     *dest='\0';
   45 }
   46 
   47 void strtolower(char *dest, const char *src) {
   48     while (*src)
   49         *dest++=tolower(*src++);
   50     *dest='\0';
   51 }
   52 
   53 /**
   54  * @brief Fast compute of square root for unsigned ints
   55  *
   56  * @param n The input number
   57  * @return sqrt(n)
   58  */
   59 unsigned int uint_sqrt(unsigned int n) {
   60     unsigned int h, p= 0, q= 1, r= n;
   61 
   62     /* avoid q rollover */
   63     if(n >= (1<<(sizeof(n)*8-2))) {
   64         q = 1<<(sizeof(n)*8-2);
   65     } else {
   66         while ( q <= n ) {
   67             q <<= 2;
   68         }
   69         q >>= 2;
   70     }
   71 
   72     while ( q != 0 ) {
   73         h = p + q;
   74         p >>= 1;
   75         if ( r >= h ) {
   76             p += q;
   77             r -= h;
   78         }
   79         q >>= 2;
   80     }
   81     return p;
   82 }
   83 
   84 int navit_utf8_strcasecmp(const char *s1, const char *s2) {
   85     char *s1_folded,*s2_folded;
   86     int cmpres;
   87     s1_folded=g_utf8_casefold(s1,-1);
   88     s2_folded=g_utf8_casefold(s2,-1);
   89     cmpres=strcmp(s1_folded,s2_folded);
   90     dbg(lvl_debug,"Compared %s with %s, got %d",s1_folded,s2_folded,cmpres);
   91     g_free(s1_folded);
   92     g_free(s2_folded);
   93     return cmpres;
   94 }
   95 
   96 /**
   97  * @brief Trims all leading and trailing whitespace characters from a string.
   98  *
   99  * Whitespace characters are all up to and including 0x20.
  100  *
  101  * This function operates in-place, i.e. `s` will be modified.
  102  *
  103  * @param s The string to trim
  104  */
  105 static void strtrim(char *s) {
  106     char *tmp = g_strdup(s);
  107     char *in = tmp;
  108     while (strlen(in) && (in[0] <= 0x20))
  109         in++;
  110     while (strlen(in) && (in[strlen(in) - 1] <= 0x20))
  111         in[strlen(in) - 1] = 0;
  112     strcpy(s, in);
  113     g_free(tmp);
  114 }
  115 
  116 /**
  117  * @brief Escape special characters from a string
  118  *
  119  * @param mode The escape mode that needs to be enabled (see enum escape_mode)
  120  * @param in The string to escape
  121  *
  122  * @return The escaped string
  123  *
  124  * @note In html escape mode (escape_mode_html), we will only process HTML escape sequence, and string quoting, but we won't escape backslashes or double quotes
  125  * @warning The returned string has been allocated and g_free() must thus be called on this string
  126  */
  127 char *str_escape(enum escape_mode mode, const char *in) {
  128     int len=mode & escape_mode_string ? 2:0;    /* Add 2 characters to the length of the buffer if quoting is enabled */
  129     char *dst,*out;
  130     const char *src=in;
  131     static const char *quot="&quot;";
  132     static const char *apos="&apos;";
  133     static const char *amp="&amp;";
  134     static const char *lt="&lt;";
  135     static const char *gt="&gt;";
  136 
  137     dbg(lvl_debug, "Will escape string=\"%s\", escape mode %d", in, mode);
  138     while (*src) {
  139         if ((*src == '"' || *src == '\\') && (mode & (escape_mode_string | escape_mode_quote)))
  140             len++;
  141         if (*src == '"' && mode == escape_mode_html_quote)
  142             len+=strlen(quot);
  143         else if (*src == '\'' && mode == escape_mode_html_apos)
  144             len+=strlen(apos);
  145         else if (*src == '&' && mode == escape_mode_html_amp)
  146             len+=strlen(amp);
  147         else if (*src == '<' && mode == escape_mode_html_lt)
  148             len+=strlen(lt);
  149         else if (*src == '>' && mode == escape_mode_html_gt)
  150             len+=strlen(gt);
  151         else
  152             len++;
  153         src++;
  154     }
  155     src=in;
  156     out=dst=g_malloc(len+1); /* +1 character for NUL termination */
  157 
  158     /* In string quoting mode (escape_mode_string), prepend the whole string with a double quote */
  159     if (mode & escape_mode_string)
  160         *dst++='"';
  161 
  162     while (*src) {
  163         if (mode & escape_mode_html) {  /* In html escape mode, only process HTML escape sequence, not backslashes or quotes */
  164             if (*src == '"' && (mode & escape_mode_html_quote)) {
  165                 strcpy(dst,quot);
  166                 src++;
  167                 dst+=strlen(quot);
  168             } else if (*src == '\'' && (mode & escape_mode_html_apos)) {
  169                 strcpy(dst,apos);
  170                 src++;
  171                 dst+=strlen(apos);
  172             } else if (*src == '&' && (mode & escape_mode_html_amp)) {
  173                 strcpy(dst,amp);
  174                 src++;
  175                 dst+=strlen(amp);
  176             } else if (*src == '<' && (mode & escape_mode_html_lt)) {
  177                 strcpy(dst,lt);
  178                 src++;
  179                 dst+=strlen(lt);
  180             } else if (*src == '>' && (mode & escape_mode_html_gt)) {
  181                 strcpy(dst,gt);
  182                 src++;
  183                 dst+=strlen(gt);
  184             } else
  185                 *dst++=*src++;
  186         } else {
  187             if ((*src == '"' || *src == '\\') && (mode & (escape_mode_string | escape_mode_quote))) {
  188                 *dst++='\\';
  189             }
  190             *dst++=*src++;
  191         }
  192     }
  193 
  194     /* In string quoting mode (escape_mode_string), append a double quote to the whole string */
  195     if (mode & escape_mode_string)
  196         *dst++='"';
  197 
  198     *dst++='\0';
  199     dbg(lvl_debug, "Result of escaped string=\"%s\"", out);
  200     return out;
  201 }
  202 
  203 /**
  204  * @brief Copy a string from @p src to @p dest, unescaping characters
  205  *
  206  * @note Escaped characters are "\\\\" (double backslash) resulting in '\\' (single backslash)
  207  *       and "\\\"" (backslash followed by double quote), resulting in '"' (double quote)
  208  *       but we will escape any other character, for example "\\ " will result in ' ' (space)
  209  *       This is the reverse of function str_escape, except that we assume (and only support) unescaping mode escape_mode_quote here
  210  *
  211  * @param[out] dest The location where to store the unescaped string
  212  * @param[in] src The source string to copy (and to unescape)
  213  * @param n The maximum amount of bytes copied into dest. Warning: If there is no null byte among the n bytes written to dest, the string placed in dest will not be null-terminated.
  214  *
  215  * @return A pointer to the destination string @p dest
  216  */
  217 char *strncpy_unescape(char *dest, const char *src, size_t n) {
  218     char *dest_ptr; /* A pointer to the currently parsed character inside string dest */
  219 
  220     for (dest_ptr=dest; (dest_ptr-dest) < n && (*src != '\0'); src++, dest_ptr++) {
  221         if (*src == '\\') {
  222             src++;
  223         }
  224         *dest_ptr = *src;
  225         if (*dest_ptr == '\0') {
  226             /* This is only possible if we just parsed an escaped sequence '\\' followed by a NUL termination, which is not really sane, but we will silently accept this case */
  227             return dest;
  228         }
  229     }
  230     if ((dest_ptr-dest) < n)
  231         *dest_ptr='\0'; /* Add a trailing '\0' if any room is remaining */
  232     else {
  233         // strncpy_unescape will return a non NUL-terminated string. Trouble ahead if this is not handled properly
  234     }
  235 
  236     return dest;
  237 }
  238 
  239 /**
  240  * @brief Parser states for `parse_for_systematic_comparison()`.
  241  */
  242 enum parse_state {
  243     parse_state_whitespace,
  244     parse_state_numeric,
  245     parse_state_alpha,
  246 };
  247 
  248 /**
  249  * @brief Parses a string for systematic comparison.
  250  *
  251  * This is a helper function for `compare_name_systematic()`.
  252  *
  253  * The string is broken down into numeric and non-numeric parts. Whitespace characters are discarded
  254  * unless they are surrounded by string characters, in which case the whole unit is treated as one
  255  * string part. All strings are converted to lowercase and leading zeroes stripped from numbers.
  256  *
  257  * @param s The string to parse
  258  *
  259  * @return A buffer containing the parsed string, parts delimited by a null character, the last part
  260  * followed by a double null character.
  261  */
  262 static char * parse_for_systematic_comparison(const char *s) {
  263     char *ret = g_malloc0(strlen(s) * 2 + 1);
  264     const char *in = s;
  265     char *out = ret;
  266     char *part;
  267     enum parse_state state = parse_state_whitespace;
  268     int i = 0;
  269     char c;
  270 
  271     dbg(lvl_debug, "enter\n");
  272 
  273     while (i < strlen(in)) {
  274         c = in[i];
  275         if ((c <= 0x20) || (c == ',') || (c == '-') || (c == '.') || (c == '/')) {
  276             /* whitespace */
  277             if (state == parse_state_numeric) {
  278                 part = g_malloc0(i + 1);
  279                 strncpy(part, in, i);
  280                 sprintf(part, "%d", atoi(part));
  281                 strcpy(out, part);
  282                 out += strlen(part) + 1;
  283                 dbg(lvl_debug, "part='%s'\n", part);
  284                 g_free(part);
  285                 in += i;
  286                 i = 1;
  287                 state = parse_state_whitespace;
  288             } else
  289                 i++;
  290         } else if ((c >= '0') && (c <= '9')) {
  291             /* numeric */
  292             if (state == parse_state_alpha) {
  293                 part = g_malloc0(i + 1);
  294                 strncpy(part, in, i);
  295                 strtrim(part);
  296                 strcpy(out, part);
  297                 out += strlen(part) + 1;
  298                 dbg(lvl_debug, "part='%s'\n", part);
  299                 g_free(part);
  300                 in += i;
  301                 i = 1;
  302             } else
  303                 i++;
  304             state = parse_state_numeric;
  305         } else {
  306             /* alpha */
  307             if (state == parse_state_numeric) {
  308                 part = g_malloc0(i + 1);
  309                 strncpy(part, in, i);
  310                 sprintf(part, "%d", atoi(part));
  311                 strcpy(out, part);
  312                 out += strlen(part) + 1;
  313                 dbg(lvl_debug, "part='%s'\n", part);
  314                 g_free(part);
  315                 in += i;
  316                 i = 1;
  317             } else
  318                 i++;
  319             state = parse_state_alpha;
  320         }
  321     }
  322 
  323     if (strlen(in) > 0) {
  324         if (state == parse_state_numeric) {
  325             part = g_malloc0(strlen(in) + 1);
  326             strcpy(part, in);
  327             sprintf(part, "%d", atoi(part));
  328             strcpy(out, part);
  329             dbg(lvl_debug, "part='%s'\n", part);
  330             g_free(part);
  331         } else if (state == parse_state_alpha) {
  332             part = g_malloc0(strlen(in) + 1);
  333             strcpy(part, in);
  334             strtrim(part);
  335             strcpy(out, part);
  336             dbg(lvl_debug, "part='%s'\n", part);
  337             g_free(part);
  338         }
  339     }
  340 
  341     return ret;
  342 }
  343 
  344 /**
  345  * @brief Compares two name_systematic strings.
  346  *
  347  * A name_systematic string is typically used for road reference numbers (A 4, I-51, SP526). This
  348  * function performs a fuzzy comparison: Each string is broken down into numeric and non-numeric parts.
  349  * Then both strings are compared part by part. The following rules apply:
  350  *
  351  * \li Semicolons denote sequences of strings, and the best match between any pair of strings from `s1` and `s2` is
  352  * returned.
  353  * \li Whitespace bordering on a number is discarded.
  354  * \li Whitespace surrounded by string characters is treated as one string with the surrounding characters.
  355  * \li If one string has more parts than the other, the shorter string is padded with null parts.
  356  * \li null equals null.
  357  * \li null does not equal non-null.
  358  * \li Numeric parts are compared as integers, hence `'042'` equals `'42'`.
  359  * \li Comparison of string parts is case-insensitive.
  360  *
  361  * Partial matches are currently determined by determining each part of one string with each part of the other. Each
  362  * part of one string that is matched by at least one part of the other increases the score. Order is currently not
  363  * taken into account, i.e. `'42A'` and `'A-42A'` are both considered full (not partial) matches for `'A42'`. Future
  364  * versions may change this.
  365  *
  366  * @param s1 The first string
  367  * @param s2 The second string
  368  *
  369  * @return 0 if both strings match, nonzero if they do not. `MAX_MISMATCH` indicates a complete mismatch; values in
  370  * between indicate partial matches (lower values correspond to better matches).
  371  */
  372 int compare_name_systematic(const char *s1, const char *s2) {
  373     int ret = MAX_MISMATCH;
  374     int tmp;
  375     int elements = 0, matches = 0;
  376     char *l = NULL, *r = NULL, *l0, *r0;
  377 
  378     if (!s1 || !s1[0]) {
  379         if (!s2 || !s2[0])
  380             return 0;
  381         else
  382             return MAX_MISMATCH;
  383     } else if (!s2 || !s2[0])
  384         return MAX_MISMATCH;
  385 
  386     /* break up strings at semicolons and parse each separately, return 0 if any two match */
  387     if (strchr(s1, ';')) {
  388         l = g_strdup(s1);
  389         for (l0 = strtok(l, ";"); l0; l0 = strtok(NULL, ";")) {
  390             tmp = compare_name_systematic(l0, s2);
  391             if (tmp < ret)
  392                 ret = tmp;
  393             if (!ret)
  394                 break;
  395         }
  396         g_free(l);
  397         return ret;
  398     } else if (strchr(s2, ';')) {
  399         r = g_strdup(s2);
  400         for (r0 = strtok(r, ";"); r0; r0 = strtok(NULL, ";")) {
  401             tmp = compare_name_systematic(s1, r0);
  402             if (tmp < ret)
  403                 ret = tmp;
  404             if (!ret)
  405                 break;
  406         }
  407         g_free(r);
  408         return ret;
  409     }
  410 
  411     /* s1 and s2 are single strings (no semicolons) */
  412     l0 = parse_for_systematic_comparison(s1);
  413     r0 = parse_for_systematic_comparison(s2);
  414 
  415     /* count left-hand elements and all left-hand elements matched by a right-hand element */
  416     for (l = l0; l[0]; l += strlen(l) + 1) {
  417         elements++;
  418         for (r = r0; r[0]; r += strlen(r) + 1) {
  419             if (atoi(l) || (l[0] == '0')) {
  420                 if ((atoi(r) || (r[0] == '0')) && (atoi(l) == atoi(r))) {
  421                     matches++;
  422                     break;
  423                 }
  424             } else if (!strcasecmp(l, r)) {
  425                 matches++;
  426                 break;
  427             }
  428         }
  429     }
  430 
  431     /* same in the opposite direction */
  432     for (r = r0; r[0]; r += strlen(r) + 1) {
  433         elements++;
  434         for (l = l0; l[0]; l += strlen(l) + 1) {
  435             if (atoi(l) || (l[0] == '0')) {
  436                 if ((atoi(r) || (r[0] == '0')) && (atoi(l) == atoi(r))) {
  437                     matches++;
  438                     break;
  439                 }
  440             } else if (!strcasecmp(l, r)) {
  441                 matches++;
  442                 break;
  443             }
  444         }
  445     }
  446 
  447     g_free(l0);
  448     g_free(r0);
  449 
  450     ret = ((elements - matches) * MAX_MISMATCH) / elements;
  451 
  452     dbg(lvl_debug, "'%s' %s '%s', ret=%d",
  453         s1, ret ? (ret == MAX_MISMATCH ? "does NOT match" : "PARTIALLY matches") : "matches", s2, ret);
  454 
  455     return ret;
  456 }
  457 
  458 static void hash_callback(gpointer key, gpointer value, gpointer user_data) {
  459     GList **l=user_data;
  460     *l=g_list_prepend(*l, value);
  461 }
  462 
  463 GList *g_hash_to_list(GHashTable *h) {
  464     GList *ret=NULL;
  465     g_hash_table_foreach(h, hash_callback, &ret);
  466 
  467     return ret;
  468 }
  469 
  470 static void hash_callback_key(gpointer key, gpointer value, gpointer user_data) {
  471     GList **l=user_data;
  472     *l=g_list_prepend(*l, key);
  473 }
  474 
  475 GList *g_hash_to_list_keys(GHashTable *h) {
  476     GList *ret=NULL;
  477     g_hash_table_foreach(h, hash_callback_key, &ret);
  478 
  479     return ret;
  480 }
  481 
  482 /**
  483  * @brief Appends a formatted string and appends it to an existing one.
  484  *
  485  * Usage is similar to the familiar C functions that take a format string and a variable argument list.
  486  *
  487  * Return value is a concatenation of `buffer` (unless it is NULL) and `fmt`, with the remaining arguments
  488  * inserted into `fmt`.
  489  *
  490  * @param buffer An existing string, can be null and will be freed by this function
  491  * @param fmt A format string (will not be altered)
  492  *
  493  * @return A newly allocated string, see description. The caller is responsible for freeing the returned string.
  494  */
  495 gchar *g_strconcat_printf(gchar *buffer, gchar *fmt, ...) {
  496     gchar *str,*ret;
  497     va_list ap;
  498 
  499     va_start(ap, fmt);
  500     str=g_strdup_vprintf(fmt, ap);
  501     va_end(ap);
  502     if (! buffer)
  503         return str;
  504     ret=g_strconcat(buffer, str, NULL);
  505     g_free(buffer);
  506     g_free(str);
  507     return ret;
  508 }
  509 
  510 #ifndef HAVE_GLIB
  511 int g_utf8_strlen_force_link(gchar *buffer, int max);
  512 int g_utf8_strlen_force_link(gchar *buffer, int max) {
  513     return g_utf8_strlen(buffer, max);
  514 }
  515 #endif
  516 
  517 #if defined(_WIN32) || defined(__CEGCC__)
  518 #include <windows.h>
  519 #include <sys/types.h>
  520 #endif
  521 
  522 #if defined(_WIN32) || defined(__CEGCC__) || defined (__APPLE__) || defined(HAVE_API_ANDROID)
  523 char *stristr(const char *String, const char *Pattern) {
  524     char *pptr, *sptr, *start;
  525 
  526     for (start = (char *)String; *start != (int)NULL; start++) {
  527         /* find start of pattern in string */
  528         for ( ; ((*start!=(int)NULL) && (toupper(*start) != toupper(*Pattern))); start++)
  529             ;
  530         if ((int)NULL == *start)
  531             return NULL;
  532 
  533         pptr = (char *)Pattern;
  534         sptr = (char *)start;
  535 
  536         while (toupper(*sptr) == toupper(*pptr)) {
  537             sptr++;
  538             pptr++;
  539 
  540             /* if end of pattern then pattern was found */
  541 
  542             if ((int)NULL == *pptr)
  543                 return (start);
  544         }
  545     }
  546     return NULL;
  547 }
  548 
  549 #ifndef SIZE_MAX
  550 # define SIZE_MAX ((size_t) -1)
  551 #endif
  552 #ifndef SSIZE_MAX
  553 # define SSIZE_MAX ((ssize_t) (SIZE_MAX / 2))
  554 #endif
  555 #if !HAVE_FLOCKFILE
  556 # undef flockfile
  557 # define flockfile(x) ((void) 0)
  558 #endif
  559 #if !HAVE_FUNLOCKFILE
  560 # undef funlockfile
  561 # define funlockfile(x) ((void) 0)
  562 #endif
  563 
  564 /* Some systems, like OSF/1 4.0 and Woe32, don't have EOVERFLOW.  */
  565 #ifndef EOVERFLOW
  566 # define EOVERFLOW E2BIG
  567 #endif
  568 
  569 
  570 #ifndef HAVE_GETDELIM
  571 /**
  572  * @brief Reads the part of a file up to a delimiter to a string.
  573  * <p>
  574  * Read up to (and including) a DELIMITER from FP into *LINEPTR (and NUL-terminate it).
  575  *
  576  * @param lineptr Pointer to a pointer returned from malloc (or NULL), pointing to a buffer. It is
  577  * realloc'ed as necessary and will receive the data read.
  578  * @param n Size of the buffer.
  579  *
  580  * @return Number of characters read (not including the null terminator), or -1 on error or EOF.
  581 */
  582 ssize_t getdelim (char **lineptr, size_t *n, int delimiter, FILE *fp) {
  583     int result;
  584     size_t cur_len = 0;
  585 
  586     if (lineptr == NULL || n == NULL || fp == NULL) {
  587         return -1;
  588     }
  589 
  590     flockfile (fp);
  591 
  592     if (*lineptr == NULL || *n == 0) {
  593         *n = 120;
  594         *lineptr = (char *) realloc (*lineptr, *n);
  595         if (*lineptr == NULL) {
  596             result = -1;
  597             goto unlock_return;
  598         }
  599     }
  600 
  601     for (;;) {
  602         int i;
  603 
  604         i = getc (fp);
  605         if (i == EOF) {
  606             result = -1;
  607             break;
  608         }
  609 
  610         /* Make enough space for len+1 (for final NUL) bytes.  */
  611         if (cur_len + 1 >= *n) {
  612             size_t needed_max=SIZE_MAX;
  613             size_t needed = 2 * *n + 1;   /* Be generous. */
  614             char *new_lineptr;
  615             if (needed_max < needed)
  616                 needed = needed_max;
  617             if (cur_len + 1 >= needed) {
  618                 result = -1;
  619                 goto unlock_return;
  620             }
  621 
  622             new_lineptr = (char *) realloc (*lineptr, needed);
  623             if (new_lineptr == NULL) {
  624                 result = -1;
  625                 goto unlock_return;
  626             }
  627 
  628             *lineptr = new_lineptr;
  629             *n = needed;
  630         }
  631 
  632         (*lineptr)[cur_len] = i;
  633         cur_len++;
  634 
  635         if (i == delimiter)
  636             break;
  637     }
  638     (*lineptr)[cur_len] = '\0';
  639     result = cur_len ? cur_len : result;
  640 
  641 unlock_return:
  642     funlockfile (fp); /* doesn't set errno */
  643 
  644     return result;
  645 }
  646 #endif
  647 
  648 #ifndef HAVE_GETLINE
  649 ssize_t getline (char **lineptr, size_t *n, FILE *stream) {
  650     return getdelim (lineptr, n, '\n', stream);
  651 }
  652 #endif
  653 
  654 #if defined(_UNICODE)
  655 wchar_t* newSysString(const char *toconvert) {
  656     int newstrlen = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, 0, 0);
  657     wchar_t *newstring = g_new(wchar_t,newstrlen);
  658     MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, toconvert, -1, newstring, newstrlen) ;
  659     return newstring;
  660 }
  661 #else
  662 char * newSysString(const char *toconvert) {
  663     return g_strdup(toconvert);
  664 }
  665 #endif
  666 #endif
  667 
  668 /**
  669  * @brief Optimizes the format of a string, adding carriage returns so that when displayed, the result text zone is roughly as wide as high
  670  *
  671  * @param[in,out] s The string to proces (will be modified by this function, but length will be unchanged)
  672  */
  673 void square_shape_str(char *s) {
  674     char *c;
  675     char *last_break;
  676     unsigned int max_cols = 0;
  677     unsigned int cur_cols = 0;
  678     unsigned int max_rows = 0;
  679     unsigned int surface;
  680     unsigned int target_cols;
  681 
  682     if (!s)
  683         return;
  684     for (c=s; *c!='\0'; c++) {
  685         if (*c==' ') {
  686             if (max_cols < cur_cols)
  687                 max_cols = cur_cols;
  688             cur_cols = 0;
  689             max_rows++;
  690         } else
  691             cur_cols++;
  692     }
  693     if (max_cols < cur_cols)
  694         max_cols = cur_cols;
  695     if (cur_cols)   /* If last line does not end with CR, add it to line numbers anyway */
  696         max_rows++;
  697     /* Give twice more room for rows (hence the factor 2 below)
  698      * This will render as a rectangular shape, taking more horizontal space than vertical */
  699     surface = max_rows * 2 * max_cols;
  700     target_cols = uint_sqrt(surface);
  701 
  702     if (target_cols < max_cols)
  703         target_cols = max_cols;
  704 
  705     target_cols = target_cols + target_cols/10; /* Allow 10% extra on columns */
  706     dbg(lvl_debug, "square_shape_str(): analyzing input text=\"%s\". max_rows=%u, max_cols=%u, surface=%u, target_cols=%u",
  707         s, max_rows, max_cols, max_rows * 2 * max_cols, target_cols);
  708 
  709     cur_cols = 0;
  710     last_break = NULL;
  711     for (c=s; *c!='\0'; c++) {
  712         if (*c==' ') {
  713             if (cur_cols>=target_cols) {    /* This line is too long, break at the previous non alnum character */
  714                 if (last_break) {
  715                     *last_break =
  716                         '\n';   /* Replace the previous non alnum character with a line break, this creates a new line and prevents the previous line from being too long */
  717                     cur_cols = c-last_break;
  718                 }
  719             }
  720             last_break = c; /* Record this position as a candidate to insert a line break */
  721         }
  722         cur_cols++;
  723     }
  724     if (cur_cols>=target_cols && last_break) {
  725         *last_break =
  726             '\n';   /* Replace the previous non alnum character with a line break, this creates a new line and prevents the previous line from being too long */
  727     }
  728 
  729     dbg(lvl_debug, "square_shape_str(): output text=\"%s\"", s);
  730 }
  731 
  732 #if defined(_MSC_VER) || (!defined(HAVE_GETTIMEOFDAY) && defined(HAVE_API_WIN32_BASE))
  733 /**
  734  * Impements a simple incomplete version of gettimeofday. Only usefull for messuring
  735  * time spans, not the real time of day.
  736  */
  737 int gettimeofday(struct timeval *time, void *local) {
  738     int milliseconds = GetTickCount();
  739 
  740     time->tv_sec = milliseconds/1000;
  741     time->tv_usec = (milliseconds - (time->tv_sec * 1000)) * 1000;
  742 
  743     return 0;
  744 }
  745 #endif
  746 /**
  747  * @brief Converts an ISO 8601-style time string into epoch time.
  748  *
  749  * @param iso8601 Time in ISO 8601 format.
  750  *
  751  * @return The number of seconds elapsed since January 1, 1970, 00:00:00 UTC.
  752  */
  753 unsigned int iso8601_to_secs(char *iso8601) {
  754     int a,b,d,val[6],i=0;
  755     char *start=iso8601,*pos=iso8601;
  756     while (*pos && i < 6) {
  757         if (*pos < '0' || *pos > '9') {
  758             val[i++]=atoi(start);
  759             pos++;
  760             start=pos;
  761         }
  762         if(*pos)
  763             pos++;
  764     }
  765 
  766     a=val[0]/100;
  767     b=2-a+a/4;
  768 
  769     if (val[1] < 2) {
  770         val[0]--;
  771         val[1]+=12;
  772     }
  773 
  774     d=1461*(val[0]+4716)/4+306001*(val[1]+1)/10000+val[2]+b-2442112;
  775 
  776     return ((d*24+val[3])*60+val[4])*60+val[5];
  777 }
  778 
  779 /**
  780  * @brief Converts a `tm` structure to `time_t`
  781  *
  782  * Returns the value of type `time_t` that represents the UTC time described by the `tm` structure
  783  * pointed to by `pt` (which may be modified).
  784  *
  785  * This function performs the reverse translation that `gmtime()` does. As this functionality is absent
  786  * in the standard library, it is emulated by calling `mktime()`, converting its output into both GMT
  787  * and local time, comparing the results and calling `mktime()` again with an input adjusted for the
  788  * offset in the opposite direction. This ensures maximum portability.
  789  *
  790  * The values of the `tm_wday` and `tm_yday` members of `pt` are ignored, and the values of the other
  791  * members are interpreted even if out of their valid ranges (see `struct tm`). For example, `tm_mday`
  792  * may contain values above 31, which are interpreted accordingly as the days that follow the last day
  793  * of the selected month.
  794  *
  795  * A call to this function automatically adjusts the values of the members of `pt` if they are off-range
  796  * or—in the case of `tm_wday` and `tm_yday`—if their values are inconsistent with the other members.
  797  *
  798  */
  799 time_t mkgmtime(struct tm * pt) {
  800     time_t ret;
  801 
  802     /* Input, GMT and local time */
  803     struct tm * pti, * pgt, * plt;
  804 
  805     pti = g_memdup(pt, sizeof(struct tm));
  806 
  807     ret = mktime(pti);
  808 
  809     pgt = g_memdup(gmtime(&ret), sizeof(struct tm));
  810     plt = g_memdup(localtime(&ret), sizeof(struct tm));
  811 
  812     pti->tm_year = pt->tm_year - pgt->tm_year + plt->tm_year;
  813     pti->tm_mon = pt->tm_mon - pgt->tm_mon + plt->tm_mon;
  814     pti->tm_mday = pt->tm_mday - pgt->tm_mday + plt->tm_mday;
  815     pti->tm_hour = pt->tm_hour - pgt->tm_hour + plt->tm_hour;
  816     pti->tm_min = pt->tm_min - pgt->tm_min + plt->tm_min;
  817     pti->tm_sec = pt->tm_sec - pgt->tm_sec + plt->tm_sec;
  818 
  819     ret = mktime(pti);
  820 
  821     dbg(lvl_debug, "time %ld (%02d-%02d-%02d %02d:%02d:%02d)\n", ret, pti->tm_year, pti->tm_mon, pti->tm_mday,
  822         pti->tm_hour, pti->tm_min, pti->tm_sec);
  823 
  824     g_free(pti);
  825     g_free(pgt);
  826     g_free(plt);
  827 
  828     return ret;
  829 }
  830 
  831 /**
  832  * @brief Converts an ISO 8601-style time string into `time_t`.
  833  */
  834 time_t iso8601_to_time(char * iso8601) {
  835     /* Date/time fields (YYYY-MM-DD-hh-mm-ss) */
  836     int val[8];
  837 
  838     int i = 0;
  839 
  840     /* Start of next integer portion and current position */
  841     char *start = iso8601, *pos = iso8601;
  842 
  843     /* Time struct */
  844     struct tm tm;
  845 
  846     memset(&tm, 0, sizeof(struct tm));
  847 
  848     while (*pos && i < 6) {
  849         if (*pos < '0' || *pos > '9') {
  850             val[i++] = atoi(start);
  851             if (i == 6)
  852                 break;
  853             pos++;
  854             start = pos;
  855         }
  856         if (*pos)
  857             pos++;
  858     }
  859     val[6] = 0;
  860     val[7] = 0;
  861     if (*pos && i == 6) {
  862         if (pos[1] && pos[2] && (!pos[3] || pos[3] == ':')) {
  863             val[6] = atoi(pos);
  864             if (pos[3] == ':') {
  865                 pos += 3;
  866                 val[7] = (val[6] < 0) ? -atoi(pos) : atoi(pos);
  867             }
  868         } else if (pos[1] && pos[2] && pos[3] && pos[4]) {
  869             val[6] = atoi(pos) / 100;
  870             val[7] = atoi(pos) % 100;
  871         }
  872     }
  873 
  874     tm.tm_year = val[0] - 1900;
  875     tm.tm_mon = val[1] - 1;
  876     tm.tm_mday = val[2];
  877     tm.tm_hour = val[3] - val[6];
  878     tm.tm_min = val[4] - val[7];
  879     tm.tm_sec = val[5];
  880 
  881     dbg(lvl_debug, "time %s (%02d-%02d-%02d %02d:%02d:%02d)\n", iso8601, tm.tm_year, tm.tm_mon, tm.tm_mday,
  882         tm.tm_hour, tm.tm_min, tm.tm_sec);
  883 
  884     return mkgmtime(&tm);
  885 }
  886 
  887 /**
  888  * @brief Converts time to ISO8601 format.
  889  *
  890  * The caller is responsible for freeing the return value of this function when it is no longer needed.
  891  *
  892  * @param time The time, as returned by `time()` and related functions
  893  *
  894  * @return Time in ISO8601 format
  895  */
  896 char * time_to_iso8601(time_t time) {
  897     char *timep=NULL;
  898     char buffer[32];
  899     struct tm *tm;
  900 
  901     tm = gmtime(&time);
  902     if (tm) {
  903         strftime(buffer, sizeof(buffer), "%Y-%m-%dT%TZ", tm);
  904         timep=g_strdup(buffer);
  905     }
  906     return timep;
  907 }
  908 
  909 /**
  910  * @brief Outputs local system time in ISO 8601 format.
  911  *
  912  * @return Time in ISO 8601 format
  913  */
  914 char *current_to_iso8601(void) {
  915 #ifdef HAVE_API_WIN32_BASE
  916     char *timep=NULL;
  917     SYSTEMTIME ST;
  918     GetSystemTime(&ST);
  919     timep=g_strdup_printf("%d-%02d-%02dT%02d:%02d:%02dZ",ST.wYear,ST.wMonth,ST.wDay,ST.wHour,ST.wMinute,ST.wSecond);
  920     return timep;
  921 #else
  922     time_t tnow;
  923     tnow = time(0);
  924     return time_to_iso8601(tnow);
  925 #endif
  926 }
  927 
  928 
  929 struct spawn_process_info {
  930 #ifdef HAVE_API_WIN32_BASE
  931     PROCESS_INFORMATION pr;
  932 #else
  933     pid_t pid; // = -1 if non-blocking spawn isn't supported
  934     int status; // exit status if non-blocking spawn isn't supported
  935 #endif
  936 };
  937 
  938 
  939 /**
  940  * Escape and quote string for shell
  941  *
  942  * @param in arg string to escape
  943  * @returns escaped string
  944  */
  945 char *shell_escape(char *arg) {
  946     char *r;
  947     int arglen=strlen(arg);
  948     int i,j,rlen;
  949 #ifdef HAVE_API_WIN32_BASE
  950     {
  951         int bscount=0;
  952         rlen=arglen+3;
  953         r=g_new(char,rlen);
  954         r[0]='"';
  955         for(i=0,j=1; i<arglen; i++) {
  956             if(arg[i]=='\\') {
  957                 bscount++;
  958                 if(i==(arglen-1)) {
  959                     // Most special case - last char is
  960                     // backslash. We can't escape it inside
  961                     // quoted string due to Win unescaping
  962                     // rules so quote should be closed
  963                     // before backslashes and these
  964                     // backslashes shouldn't be doubled
  965                     rlen+=bscount;
  966                     r=g_realloc(r,rlen);
  967                     r[j++]='"';
  968                     memset(r+j,'\\',bscount);
  969                     j+=bscount;
  970                 }
  971             } else {
  972                 //Any preceeding backslashes will be doubled.
  973                 bscount*=2;
  974                 // Double quote needs to be preceeded by
  975                 // at least one backslash
  976                 if(arg[i]=='"')
  977                     bscount++;
  978                 if(bscount>0) {
  979                     rlen+=bscount;
  980                     r=g_realloc(r,rlen);
  981                     memset(r+j,'\\',bscount);
  982                     j+=bscount;
  983                     bscount=0;
  984                 }
  985                 r[j++]=arg[i];
  986                 if(i==(arglen-1)) {
  987                     r[j++]='"';
  988                 }
  989             }
  990         }
  991         r[j++]=0;
  992     }
  993 #else
  994     {
  995         // Will use hard quoting for the whole string
  996         // and replace each singular quote found with a '\'' sequence.
  997         rlen=arglen+3;
  998         r=g_new(char,rlen);
  999         r[0]='\'';
 1000         for(i=0,j=1; i<arglen; i++) {
 1001             if(arg[i]=='\'') {
 1002                 rlen+=3;
 1003                 r=g_realloc(r,rlen);
 1004                 g_strlcpy(r+j,"'\\''",rlen-j);
 1005             } else {
 1006                 r[j++]=arg[i];
 1007             }
 1008         }
 1009         r[j++]='\'';
 1010         r[j++]=0;
 1011     }
 1012 #endif
 1013     return r;
 1014 }
 1015 
 1016 #ifndef _POSIX_C_SOURCE
 1017 static char* spawn_process_compose_cmdline(char **argv) {
 1018     int i,j;
 1019     char *cmdline=shell_escape(argv[0]);
 1020     for(i=1,j=strlen(cmdline); argv[i]; i++) {
 1021         char *arg=shell_escape(argv[i]);
 1022         int arglen=strlen(arg);
 1023         cmdline[j]=' ';
 1024         cmdline=g_realloc(cmdline,j+1+arglen+1);
 1025         memcpy(cmdline+j+1,arg,arglen+1);
 1026         g_free(arg);
 1027         j=j+1+arglen;
 1028     }
 1029     return cmdline;
 1030 }
 1031 #endif
 1032 
 1033 #ifdef _POSIX_C_SOURCE
 1034 
 1035 #if 0 /* def _POSIX_THREADS */
 1036 #define spawn_process_sigmask(how,set,old) pthread_sigmask(how,set,old)
 1037 #else
 1038 #define spawn_process_sigmask(how,set,old) sigprocmask(how,set,old)
 1039 #endif
 1040 
 1041 GList *spawn_process_children=NULL;
 1042 
 1043 #endif
 1044 
 1045 
 1046 /**
 1047  * Call external program
 1048  *
 1049  * @param in argv NULL terminated list of parameters,
 1050  *    zeroeth argument is program name
 1051  * @returns 0 - success, >0 - return code, -1 - error
 1052  */
 1053 struct spawn_process_info*
 1054 spawn_process(char **argv) {
 1055     struct spawn_process_info*r=g_new(struct spawn_process_info,1);
 1056 #ifdef _POSIX_C_SOURCE
 1057     {
 1058         pid_t pid;
 1059 
 1060         sigset_t set, old;
 1061         dbg(lvl_debug,"spawning process for '%s'", argv[0]);
 1062         sigemptyset(&set);
 1063         sigaddset(&set,SIGCHLD);
 1064         spawn_process_sigmask(SIG_BLOCK,&set,&old);
 1065         pid=fork();
 1066         if(pid==0) {
 1067             execvp(argv[0], argv);
 1068             /*Shouldn't reach here*/
 1069             exit(1);
 1070         } else if(pid>0) {
 1071             r->status=-1;
 1072             r->pid=pid;
 1073             spawn_process_children=g_list_prepend(spawn_process_children,r);
 1074         } else {
 1075             dbg(lvl_error,"fork() returned error.");
 1076             g_free(r);
 1077             r=NULL;
 1078         }
 1079         spawn_process_sigmask(SIG_SETMASK,&old,NULL);
 1080         return r;
 1081     }
 1082 #else
 1083 #ifdef HAVE_API_WIN32_BASE
 1084     {
 1085         char *cmdline;
 1086         DWORD dwRet;
 1087 
 1088         // For [desktop] Windows it's adviceable not to use
 1089         // first CreateProcess parameter because PATH is not used
 1090         // if it is defined.
 1091         //
 1092         // On WinCE 6.0 I was unable to launch anything
 1093         // without first CreateProcess parameter, also it seems that
 1094         // no WinCE program has support for quoted strings in arguments.
 1095         // So...
 1096 #ifdef HAVE_API_WIN32_CE
 1097         LPWSTR cmd,args;
 1098         cmdline=g_strjoinv(" ",argv+1);
 1099         args=newSysString(cmdline);
 1100         cmd = newSysString(argv[0]);
 1101         dwRet=CreateProcess(cmd, args, NULL, NULL, 0, 0, NULL, NULL, NULL, &(r->pr));
 1102         dbg(lvl_debug, "CreateProcess(%s,%s), PID=%i",argv[0],cmdline,r->pr.dwProcessId);
 1103         g_free(cmd);
 1104 #else
 1105         TCHAR* args;
 1106         STARTUPINFO startupInfo;
 1107         memset(&startupInfo, 0, sizeof(startupInfo));
 1108         startupInfo.cb = sizeof(startupInfo);
 1109         cmdline=spawn_process_compose_cmdline(argv);
 1110         args=newSysString(cmdline);
 1111         dwRet=CreateProcess(NULL, args, NULL, NULL, 0, 0, NULL, NULL, &startupInfo, &(r->pr));
 1112         dbg(lvl_debug, "CreateProcess(%s), PID=%i",cmdline,r->pr.dwProcessId);
 1113 #endif
 1114         g_free(cmdline);
 1115         g_free(args);
 1116         return r;
 1117     }
 1118 #else
 1119     {
 1120         char *cmdline=spawn_process_compose_cmdline(argv);
 1121         int status;
 1122         dbg(lvl_error,"Unblocked spawn_process isn't availiable on this platform.");
 1123         status=system(cmdline);
 1124         g_free(cmdline);
 1125         r->status=status;
 1126         r->pid=0;
 1127         return r;
 1128     }
 1129 #endif
 1130 #endif
 1131 }
 1132 
 1133 /**
 1134  * Check external program status
 1135  *
 1136  * @param in *pi pointer to spawn_process_info structure
 1137  * @param in block =0 do not block =1 block until child terminated
 1138  * @returns -1 - still running, >=0 program exited,
 1139  *     =255 trminated abnormally or wasn't run at all.
 1140  *
 1141  */
 1142 int spawn_process_check_status(struct spawn_process_info *pi, int block) {
 1143     if(pi==NULL) {
 1144         dbg(lvl_error,"Trying to get process status of NULL, assuming process is terminated.");
 1145         return 255;
 1146     }
 1147 #ifdef HAVE_API_WIN32_BASE
 1148     {
 1149         int failcount=0;
 1150         while(1) {
 1151             DWORD dw;
 1152             if(GetExitCodeProcess(pi->pr.hProcess,&dw)) {
 1153                 if(dw!=STILL_ACTIVE) {
 1154                     return dw;
 1155                     break;
 1156                 }
 1157             } else {
 1158                 dbg(lvl_error,"GetExitCodeProcess failed. Assuming the process is terminated.");
 1159                 return 255;
 1160             }
 1161             if(!block)
 1162                 return -1;
 1163 
 1164             dw=WaitForSingleObject(pi->pr.hProcess,INFINITE);
 1165             if(dw==WAIT_FAILED && failcount++==1) {
 1166                 dbg(lvl_error,"WaitForSingleObject failed twice. Assuming the process is terminated.");
 1167                 return 0;
 1168                 break;
 1169             }
 1170         }
 1171     }
 1172 #else
 1173 #ifdef _POSIX_C_SOURCE
 1174     if(pi->status!=-1) {
 1175         return pi->status;
 1176     }
 1177     while(1) {
 1178         int status;
 1179         pid_t w=waitpid(pi->pid,&status,block?0:WNOHANG);
 1180         if(w>0) {
 1181             if(WIFEXITED(status))
 1182                 pi->status=WEXITSTATUS(status);
 1183             return pi->status;
 1184             if(WIFSTOPPED(status)) {
 1185                 dbg(lvl_debug,"child is stopped by %i signal",WSTOPSIG(status));
 1186             } else if (WIFSIGNALED(status)) {
 1187                 dbg(lvl_debug,"child terminated by signal %i",WEXITSTATUS(status));
 1188                 pi->status=255;
 1189                 return 255;
 1190             }
 1191             if(!block)
 1192                 return -1;
 1193         } else if(w==0) {
 1194             if(!block)
 1195                 return -1;
 1196         } else {
 1197             if(pi->status!=-1) // Signal handler has changed pi->status while in this function
 1198                 return pi->status;
 1199             dbg(lvl_error,"waitpid() indicated error, reporting process termination.");
 1200             return 255;
 1201         }
 1202     }
 1203 #else
 1204     dbg(lvl_error, "Non-blocking spawn_process isn't availiable for this platform, repoting process exit status.");
 1205     return pi->status;
 1206 #endif
 1207 #endif
 1208 }
 1209 
 1210 void spawn_process_info_free(struct spawn_process_info *pi) {
 1211     if(pi==NULL)
 1212         return;
 1213 #ifdef HAVE_API_WIN32_BASE
 1214     CloseHandle(pi->pr.hProcess);
 1215     CloseHandle(pi->pr.hThread);
 1216 #endif
 1217 #ifdef _POSIX_C_SOURCE
 1218     {
 1219         sigset_t set, old;
 1220         sigemptyset(&set);
 1221         sigaddset(&set,SIGCHLD);
 1222         spawn_process_sigmask(SIG_BLOCK,&set,&old);
 1223         spawn_process_children=g_list_remove(spawn_process_children,pi);
 1224         spawn_process_sigmask(SIG_SETMASK,&old,NULL);
 1225     }
 1226 #endif
 1227     g_free(pi);
 1228 }
 1229 
 1230 #ifdef _POSIX_C_SOURCE
 1231 static void spawn_process_sigchld(int sig) {
 1232     int status;
 1233     pid_t pid;
 1234     while ((pid=waitpid(-1, &status, WNOHANG)) > 0) {
 1235         GList *el=g_list_first(spawn_process_children);
 1236         while(el) {
 1237             struct spawn_process_info *p=el->data;
 1238             if(p->pid==pid) {
 1239                 p->status=status;
 1240             }
 1241             el=g_list_next(el);
 1242         }
 1243     }
 1244 }
 1245 #endif
 1246 
 1247 void spawn_process_init() {
 1248 #ifdef _POSIX_C_SOURCE
 1249     struct sigaction act;
 1250     act.sa_handler=spawn_process_sigchld;
 1251     act.sa_flags=0;
 1252     sigemptyset(&act.sa_mask);
 1253     sigaction(SIGCHLD, &act, NULL);
 1254 #endif
 1255     return;
 1256 }
 1257 
 1258 /**
 1259  * @brief Get printable compass direction from an angle.
 1260  *
 1261  * This function supports three different modes:
 1262  *
 1263  * In mode 0, the angle in degrees is output as a string.
 1264  *
 1265  * In mode 1, the angle is output as a cardinal direction (N, SE etc.).
 1266  *
 1267  * In mode 2, the angle is output in analog clock notation (6 o'clock).
 1268  *
 1269  * @param buffer Buffer to hold the result string (up to 5 characters, including the terminating null
 1270  * character, may be required)
 1271  * @param angle The angle to convert
 1272  * @param mode The conversion mode, see description
 1273  */
 1274 void get_compass_direction(char *buffer, int angle, int mode) {
 1275     angle=angle%360;
 1276     switch (mode) {
 1277     case 0:
 1278         sprintf(buffer,"%d",angle);
 1279         break;
 1280     case 1:
 1281         if (angle < 69 || angle > 291)
 1282             *buffer++='N';
 1283         if (angle > 111 && angle < 249)
 1284             *buffer++='S';
 1285         if (angle > 22 && angle < 158)
 1286             *buffer++='E';
 1287         if (angle > 202 && angle < 338)
 1288             *buffer++='W';
 1289         *buffer++='\0';
 1290         break;
 1291     case 2:
 1292         angle=(angle+15)/30;
 1293         if (! angle)
 1294             angle=12;
 1295         sprintf(buffer,"%d H", angle);
 1296         break;
 1297     }
 1298 }