comment out menu entry not existing in claws
[claws.git] / src / utils.c
index 0e65bbc55df67903237eb1231e2d54dd356a55ef..9c5333f48d39c715b0d502157737deb4c7168c23 100644 (file)
@@ -81,6 +81,17 @@ void hash_free_strings(GHashTable *table)
        g_hash_table_foreach(table, hash_free_strings_func, NULL);
 }
 
+static void hash_free_value_mem_func(gpointer key, gpointer value,
+                                    gpointer data)
+{
+       g_free(value);
+}
+
+void hash_free_value_mem(GHashTable *table)
+{
+       g_hash_table_foreach(table, hash_free_value_mem_func, NULL);
+}
+
 void ptr_array_free_strings(GPtrArray *array)
 {
        gint i;
@@ -106,17 +117,15 @@ gint to_number(const gchar *nstr)
        return atoi(nstr);
 }
 
-/* convert integer into string
-   nstr must be a 11 characters table
-*/
-gchar *itos_buf(gchar nstr[], gint n)
+/* convert integer into string,
+   nstr must be not lower than 11 characters length */
+gchar *itos_buf(gchar *nstr, gint n)
 {
        g_snprintf(nstr, 11, "%d", n);
        return nstr;
 }
 
-/* convert integer into string
-   use an internal static buffer */
+/* convert integer into string */
 gchar *itos(gint n)
 {
        static gchar nstr[11];
@@ -126,7 +135,7 @@ gchar *itos(gint n)
 
 gchar *to_human_readable(off_t size)
 {
-       static gchar str[9];
+       static gchar str[10];
        gint count;
        guint32 div = 1;
 
@@ -141,10 +150,10 @@ gchar *to_human_readable(off_t size)
        case 0: g_snprintf(str, sizeof(str), "%dB",    (gint)size);   break;
        case 1: g_snprintf(str, sizeof(str), "%.1fKB", (gfloat)size / div);
                break;
-       case 2: g_snprintf(str, sizeof(str), "%.1fMB", (gfloat)size / div);
+       case 2: g_snprintf(str, sizeof(str), "%.2fMB", (gfloat)size / div);
                break;
        default:
-               g_snprintf(str, sizeof(str), "%.1fGB", (gfloat)size / div);
+               g_snprintf(str, sizeof(str), "%.2fGB", (gfloat)size / div);
                break;
        }
 
@@ -159,7 +168,17 @@ gint strcmp2(const gchar *s1, const gchar *s2)
        else
                return strcmp(s1, s2);
 }
-
+/* strstr with NULL-checking */
+gint strstr2(const gchar *s1, const gchar *s2)
+{
+       if (s1 == NULL || s2 == NULL)
+               return -1;
+       else
+               if( strstr(s1, s2) !=NULL) 
+                return 0;
+                else 
+                return -1;
+}
 /* compare paths */
 gint path_cmp(const gchar *s1, const gchar *s2)
 {
@@ -192,6 +211,21 @@ gchar *strretchomp(gchar *str)
        return str;
 }
 
+/* remove trailing character */
+gchar *strtailchomp(gchar *str, gchar tail_char)
+{
+       register gchar *s;
+
+       if (!*str) return str;
+       if (tail_char == '\0') return str;
+
+       for (s = str + strlen(str) - 1; s >= str && *s == tail_char; s--)
+               *s = '\0';
+
+       return str;
+}
+
+
 /* Similar to `strstr' but this function ignores the case of both strings.  */
 gchar *strcasestr(const gchar *haystack, const gchar *needle)
 {
@@ -486,11 +520,12 @@ gint subject_compare(const gchar *s1, const gchar *s2)
        if (!*str1 || !*str2) return -1;
 
        retval = strcmp(str1, str2);
-       //if (retval == 0)
-       //      g_print("\ns1 = %s\ns2 = %s\n"
-       //              "str1 = %s\nstr2 = %s\nmatched.\n",
-       //              s1, s2, str1, str2);
-
+       /*
+       if (retval == 0)
+               g_print("\ns1 = %s\ns2 = %s\n"
+                       "str1 = %s\nstr2 = %s\nmatched.\n",
+                       s1, s2, str1, str2);
+       */
        return retval;
 }
 
@@ -560,6 +595,35 @@ void extract_parenthesis(gchar *str, gchar op, gchar cl)
        *destp = '\0';
 }
 
+void extract_one_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
+                                            gchar op, gchar cl)
+{
+       register gchar *srcp, *destp;
+       gint in_brace;
+       gboolean in_quote = FALSE;
+
+       srcp = destp = str;
+
+       if ((srcp = strchr_with_skip_quote(destp, quote_chr, op))) {
+               memmove(destp, srcp + 1, strlen(srcp));
+               in_brace = 1;
+               while(*destp) {
+                       if (*destp == op && !in_quote)
+                               in_brace++;
+                       else if (*destp == cl && !in_quote)
+                               in_brace--;
+                       else if (*destp == quote_chr)
+                               in_quote ^= TRUE;
+
+                       if (in_brace == 0)
+                               break;
+
+                       destp++;
+               }
+       }
+       *destp = '\0';
+}
+
 void extract_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
                                         gchar op, gchar cl)
 {
@@ -569,7 +633,7 @@ void extract_parenthesis_with_skip_quote(gchar *str, gchar quote_chr,
 
        srcp = destp = str;
 
-       while ((srcp = strchr_with_skip_quote(destp, '"', op))) {
+       while ((srcp = strchr_with_skip_quote(destp, quote_chr, op))) {
                if (destp > str)
                        *destp++ = ' ';
                memmove(destp, srcp + 1, strlen(srcp));
@@ -883,55 +947,45 @@ gboolean is_ascii_str(const guchar *str)
 
 gint get_quote_level(const gchar *str)
 {
-       size_t firstquotepos;
-       size_t lastquotepos = -1;
+       const gchar *first_pos;
+       const gchar *last_pos;
        const gchar *p = str;
-       const gchar *pos;
-       gint quotelevel = -1;
-       gint i = 0;
+       gint quote_level = -1;
 
        /* speed up line processing by only searching to the last '>' */
-       if ((pos = strchr(str, '>')) != NULL) {
-               firstquotepos = pos - str;
-               lastquotepos = strrchr(str, '>') - str + 1;
-
+       if ((first_pos = strchr(str, '>')) != NULL) {
                /* skip a line if it contains a '<' before the initial '>' */
-               if (memchr(str, '<', pos - str) != NULL)
+               if (memchr(str, '<', first_pos - str) != NULL)
                        return -1;
+               last_pos = strrchr(first_pos, '>');
        } else
                return -1;
 
-       while (i < lastquotepos) {
-               while (i < lastquotepos) {
-                       if (isspace(*p) || (*p == '\t')) {
+       while (p <= last_pos) {
+               while (p < last_pos) {
+                       if (isspace(*p))
                                p++;
-                               i++;
-                       } else
+                       else
                                break;
                }
-               if (i >= lastquotepos)
-                       break;
 
                if (*p == '>')
-                       quotelevel++;
-               else if ((*p != '-') && !isspace(*p) && (i < lastquotepos)) {
+                       quote_level++;
+               else if (*p != '-' && !isspace(*p) && p <= last_pos) {
                        /* any characters are allowed except '-' and space */
-                       while ((*p != '-') && (*p != '>') && !isspace(*p) &&
-                              (i < lastquotepos)) {
+                       while (*p != '-' && *p != '>' && !isspace(*p) &&
+                              p < last_pos)
                                p++;
-                               i++;
-                       }
                        if (*p == '>')
-                               quotelevel++;
-                       else if ((i >= lastquotepos) || isspace(*p))
+                               quote_level++;
+                       else
                                break;
                }
 
                p++;
-               i++;
        }
 
-       return quotelevel;
+       return quote_level;
 }
 
 GList *uri_list_extract_filenames(const gchar *uri_list)
@@ -1119,6 +1173,17 @@ gchar *get_imap_cache_dir(void)
        return imap_cache_dir;
 }
 
+gchar *get_mbox_cache_dir(void)
+{
+       static gchar *mbox_cache_dir = NULL;
+
+       if (!mbox_cache_dir)
+               mbox_cache_dir = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                            MBOX_CACHE_DIR, NULL);
+
+       return mbox_cache_dir;
+}
+
 gchar *get_mime_tmp_dir(void)
 {
        static gchar *mime_tmp_dir = NULL;
@@ -1171,6 +1236,33 @@ off_t get_file_size(const gchar *file)
        return s.st_size;
 }
 
+off_t get_left_file_size(FILE *fp)
+{
+       glong pos;
+       glong end;
+       off_t size;
+
+       if ((pos = ftell(fp)) < 0) {
+               perror("ftell");
+               return -1;
+       }
+       if (fseek(fp, 0L, SEEK_END) < 0) {
+               perror("fseek");
+               return -1;
+       }
+       if ((end = ftell(fp)) < 0) {
+               perror("fseek");
+               return -1;
+       }
+       size = end - pos;
+       if (fseek(fp, pos, SEEK_SET) < 0) {
+               perror("fseek");
+               return -1;
+       }
+
+       return size;
+}
+
 gboolean file_exist(const gchar *file, gboolean allow_fifo)
 {
        struct stat s;
@@ -1297,6 +1389,51 @@ gint remove_all_files(const gchar *dir)
        return 0;
 }
 
+gint remove_numbered_files(const gchar *dir, guint first, guint last)
+{
+       DIR *dp;
+       struct dirent *d;
+       gchar *prev_dir;
+       gint fileno;
+
+       prev_dir = g_get_current_dir();
+
+       if (chdir(dir) < 0) {
+               FILE_OP_ERROR(dir, "chdir");
+               return -1;
+       }
+
+       if ((dp = opendir(".")) == NULL) {
+               FILE_OP_ERROR(dir, "opendir");
+               return -1;
+       }
+
+       while ((d = readdir(dp)) != NULL) {
+               fileno = to_number(d->d_name);
+               if (fileno >= 0 && first <= fileno && fileno <= last) {
+                       if (unlink(d->d_name) < 0)
+                               FILE_OP_ERROR(d->d_name, "unlink");
+               }
+       }
+
+       closedir(dp);
+
+       if (chdir(prev_dir) < 0) {
+               FILE_OP_ERROR(prev_dir, "chdir");
+               g_free(prev_dir);
+               return -1;
+       }
+
+       g_free(prev_dir);
+
+       return 0;
+}
+
+gint remove_all_numbered_files(const gchar *dir)
+{
+       return remove_numbered_files(dir, 0, UINT_MAX);
+}
+
 gint remove_dir_recursive(const gchar *dir)
 {
        struct stat s;
@@ -1304,7 +1441,7 @@ gint remove_dir_recursive(const gchar *dir)
        struct dirent *d;
        gchar *prev_dir;
 
-       //g_print("dir = %s\n", dir);
+       /*g_print("dir = %s\n", dir);*/
 
        if (stat(dir, &s) < 0) {
                FILE_OP_ERROR(dir, "stat");
@@ -1322,7 +1459,7 @@ gint remove_dir_recursive(const gchar *dir)
        }
 
        prev_dir = g_get_current_dir();
-       //g_print("prev_dir = %s\n", prev_dir);
+       /*g_print("prev_dir = %s\n", prev_dir);*/
 
        if (!path_cmp(prev_dir, dir)) {
                g_free(prev_dir);
@@ -1357,7 +1494,7 @@ gint remove_dir_recursive(const gchar *dir)
                        continue;
                }
 
-               //g_print("removing %s\n", d->d_name);
+               /*g_print("removing %s\n", d->d_name);*/
 
                if (S_ISDIR(s.st_mode)) {
                        if (remove_dir_recursive(d->d_name) < 0) {
@@ -1546,6 +1683,27 @@ gint copy_file(const gchar *src, const gchar *dest)
        return 0;
 }
 
+gint move_file(const gchar *src, const gchar *dest)
+{
+       if (is_file_exist(dest)) {
+               g_warning(_("move_file(): file %s already exists."), dest);
+               return -1;
+       }
+
+       if (rename(src, dest) == 0) return 0;
+
+       if (EXDEV != errno) {
+               FILE_OP_ERROR(src, "rename");
+               return -1;
+       }
+
+       if (copy_file(src, dest) < 0) return -1;
+
+       unlink(src);
+
+       return 0;
+}
+
 gint change_file_mode_rw(FILE *fp, const gchar *file)
 {
 #if HAVE_FCHMOD
@@ -1627,7 +1785,28 @@ gint execute_async(gchar *const argv[])
        return 0;
 }
 
-gint execute_command_line(const gchar *cmdline)
+gint execute_sync(gchar *const argv[])
+{
+       pid_t pid;
+
+       if ((pid = fork()) < 0) {
+               perror("fork");
+               return -1;
+       }
+
+       if (pid == 0) {         /* child process */
+               execvp(argv[0], argv);
+
+               perror("execvp");
+               _exit(1);
+       }
+
+       waitpid(pid, NULL, 0);
+
+       return 0;
+}
+
+gint execute_command_line(const gchar *cmdline, gboolean async)
 {
        gchar **argv;
        gint i;
@@ -1649,7 +1828,10 @@ gint execute_command_line(const gchar *cmdline)
                }
        }
 
-       ret = execute_async(argv);
+       if (async)
+               ret = execute_async(argv);
+       else
+               ret = execute_sync(argv);
        g_strfreev(argv);
 
        return ret;
@@ -1674,7 +1856,7 @@ gint open_uri(const gchar *uri, const gchar *cmdline)
                g_snprintf(buf, sizeof(buf), default_cmdline, uri);
        }
 
-       execute_command_line(buf);
+       execute_command_line(buf, TRUE);
 
        return 0;
 }
@@ -1823,13 +2005,43 @@ void get_rfc822_date(gchar *buf, gint len)
                   day, dd, mon, yyyy, hh, mm, ss, tzoffset(&t));
 }
 
-void debug_print(const gchar *format, ...)
+static FILE *log_fp = NULL;
+
+void set_log_file(const gchar *filename)
+{
+       if (log_fp) return;
+       log_fp = fopen(filename, "w");
+       if (!log_fp)
+               FILE_OP_ERROR(filename, "fopen");
+}
+
+void close_log_file(void)
+{
+       if (log_fp) {
+               fclose(log_fp);
+               log_fp = NULL;
+       }
+}
+
+static guint log_verbosity_count = 0;
+
+void log_verbosity_set(gboolean verbose)
+{
+       if (verbose)
+               log_verbosity_count++;
+       else if (log_verbosity_count > 0)
+               log_verbosity_count--;
+}
+
+void debug_print_real(const gchar *file, const guint line, const gchar *format, ...)
 {
        va_list args;
        gchar buf[BUFFSIZE];
 
        if (!debug_mode) return;
 
+       printf("%s:%d:", file, line);
+
        va_start(args, format);
        g_vsnprintf(buf, sizeof(buf), format, args);
        va_end(args);
@@ -1841,14 +2053,27 @@ void log_print(const gchar *format, ...)
 {
        va_list args;
        gchar buf[BUFFSIZE];
+       gchar *logbuf;
+       gchar timestr[6];
+       time_t t;
 
        va_start(args, format);
        g_vsnprintf(buf, sizeof(buf), format, args);
        va_end(args);
+       
+       time(&t);
+       strftime(timestr, 6, "%H:%M", localtime(&t));
+       logbuf = g_strdup_printf("[%s] %s", timestr, buf);
 
-       if (debug_mode) fputs(buf, stdout);
-       log_window_append(buf, LOG_NORMAL);
-       statusbar_puts_all(buf);
+       if (debug_mode) fputs(logbuf, stdout);
+       log_window_append(logbuf, LOG_NORMAL);
+       if (log_fp) {
+               fputs(logbuf, log_fp);
+               fflush(log_fp);
+       }
+       if (log_verbosity_count)
+               statusbar_puts_all(buf);
+       g_free(logbuf);
 }
 
 void log_message(const gchar *format, ...)
@@ -1862,6 +2087,12 @@ void log_message(const gchar *format, ...)
 
        if (debug_mode) g_message("%s", buf);
        log_window_append(buf, LOG_MSG);
+       if (log_fp) {
+               fputs("message: ", log_fp);
+               fputs(buf, log_fp);
+               fflush(log_fp);
+       }
+       statusbar_puts_all(buf);
 }
 
 void log_warning(const gchar *format, ...)
@@ -1875,6 +2106,11 @@ void log_warning(const gchar *format, ...)
 
        g_warning("%s", buf);
        log_window_append(buf, LOG_WARN);
+       if (log_fp) {
+               fputs("*** warning: ", log_fp);
+               fputs(buf, log_fp);
+               fflush(log_fp);
+       }
 }
 
 void log_error(const gchar *format, ...)
@@ -1888,4 +2124,9 @@ void log_error(const gchar *format, ...)
 
        g_warning("%s", buf);
        log_window_append(buf, LOG_ERROR);
+       if (log_fp) {
+               fputs("*** error: ", log_fp);
+               fputs(buf, log_fp);
+               fflush(log_fp);
+       }
 }