2 * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
3 * Copyright (C) 1999-2000 Thomas Roessler <roessler@does-not-exist.org>
5 * This program is free software; you can redistribute it
6 * and/or modify it under the terms of the GNU General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later
11 * This program is distributed in the hope that it will be
12 * useful, but WITHOUT ANY WARRANTY; without even the implied
13 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111, USA.
24 * This file used to contain some more functions, namely those
25 * which are now in muttlib.c. They have been removed, so we have
26 * some of our "standard" functions in external programs, too.
41 void mutt_nocurses_error (const char *fmt, ...)
46 vfprintf (stderr, fmt, ap);
51 void *safe_calloc (size_t nmemb, size_t size)
58 if (((size_t) -1) / nmemb <= size)
60 mutt_error _("Integer overflow -- can't allocate memory!");
65 if (!(p = calloc (nmemb, size)))
67 mutt_error _("Out of memory!");
74 void *safe_malloc (size_t siz)
80 if ((p = (void *) malloc (siz)) == 0) /* __MEM_CHECKED__ */
82 mutt_error _("Out of memory!");
89 void safe_realloc (void *ptr, size_t siz)
92 void **p = (void **)ptr;
98 free (*p); /* __MEM_CHECKED__ */
105 r = (void *) realloc (*p, siz); /* __MEM_CHECKED__ */
108 /* realloc(NULL, nbytes) doesn't seem to work under SunOS 4.1.x --- __MEM_CHECKED__ */
109 r = (void *) malloc (siz); /* __MEM_CHECKED__ */
114 mutt_error _("Out of memory!");
122 void safe_free (void *ptr)
124 void **p = (void **)ptr;
127 free (*p); /* __MEM_CHECKED__ */
132 int safe_fclose (FILE **f)
143 char *safe_strdup (const char *s)
151 p = (char *)safe_malloc (l);
156 void mutt_str_replace (char **p, const char *s)
159 *p = safe_strdup (s);
162 void mutt_str_adjust (char **p)
164 if (!p || !*p) return;
165 safe_realloc (p, strlen (*p) + 1);
168 /* convert all characters in the string to lowercase */
169 char *mutt_strlower (char *s)
175 *p = tolower ((unsigned char) *p);
182 void mutt_unlink (const char *s)
188 if (stat (s, &sb) == 0)
190 if ((f = fopen (s, "r+")))
193 memset (buf, 0, sizeof (buf));
194 while (sb.st_size > 0)
196 fwrite (buf, 1, MIN (sizeof (buf), sb.st_size), f);
197 sb.st_size -= MIN (sizeof (buf), sb.st_size);
204 int mutt_copy_bytes (FILE *in, FILE *out, size_t size)
211 chunk = (size > sizeof (buf)) ? sizeof (buf) : size;
212 if ((chunk = fread (buf, 1, chunk, in)) < 1)
214 if (fwrite (buf, 1, chunk, out) != chunk)
216 /* dprint (1, (debugfile, "mutt_copy_bytes(): fwrite() returned short byte count\n")); */
225 int mutt_copy_stream (FILE *fin, FILE *fout)
228 char buf[LONG_STRING];
230 while ((l = fread (buf, 1, sizeof (buf), fin)) > 0)
232 if (fwrite (buf, 1, l, fout) != l)
240 compare_stat (struct stat *osb, struct stat *nsb)
242 if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino ||
243 osb->st_rdev != nsb->st_rdev)
251 int safe_symlink(const char *oldpath, const char *newpath)
253 struct stat osb, nsb;
255 if(!oldpath || !newpath)
258 if(unlink(newpath) == -1 && errno != ENOENT)
261 if (oldpath[0] == '/')
263 if (symlink (oldpath, newpath) == -1)
268 char abs_oldpath[_POSIX_PATH_MAX];
270 if ((getcwd (abs_oldpath, sizeof abs_oldpath) == NULL) ||
271 (strlen (abs_oldpath) + 1 + strlen (oldpath) + 1 > sizeof abs_oldpath))
274 strcat (abs_oldpath, "/"); /* __STRCAT_CHECKED__ */
275 strcat (abs_oldpath, oldpath); /* __STRCAT_CHECKED__ */
276 if (symlink (abs_oldpath, newpath) == -1)
280 if(stat(oldpath, &osb) == -1 || stat(newpath, &nsb) == -1
281 || compare_stat(&osb, &nsb) == -1)
291 * This function is supposed to do nfs-safe renaming of files.
293 * Warning: We don't check whether src and target are equal.
296 int safe_rename (const char *src, const char *target)
298 struct stat ssb, tsb;
303 if (link (src, target) != 0)
307 * Coda does not allow cross-directory links, but tells
308 * us it's a cross-filesystem linking attempt.
310 * However, the Coda rename call is allegedly safe to use.
312 * With other file systems, rename should just fail when
313 * the files reside on different file systems, so it's safe
319 return rename (src, target);
325 * Stat both links and check if they are equal.
328 if (stat (src, &ssb) == -1)
333 if (stat (target, &tsb) == -1)
339 * pretend that the link failed because the target file
343 if (compare_stat (&ssb, &tsb) == -1)
350 * Unlink the original link. Should we really ignore the return
359 int safe_open (const char *path, int flags)
361 struct stat osb, nsb;
364 if ((fd = open (path, flags, 0600)) < 0)
367 /* make sure the file is not symlink */
368 if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 ||
369 compare_stat(&osb, &nsb) == -1)
371 /* dprint (1, (debugfile, "safe_open(): %s is a symlink!\n", path)); */
379 /* when opening files for writing, make sure the file doesn't already exist
380 * to avoid race conditions.
382 FILE *safe_fopen (const char *path, const char *mode)
387 int flags = O_CREAT | O_EXCL;
398 if ((fd = safe_open (path, flags)) < 0)
401 return (fdopen (fd, mode));
404 return (fopen (path, mode));
407 static char safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
409 void mutt_sanitize_filename (char *f, short slash)
415 if ((slash && *f == '/') || !strchr (safe_chars, *f))
420 /* these characters must be escaped in regular expressions */
422 static char rx_special_chars[] = "^.[$()|*+?{\\";
424 int mutt_rx_sanitize_string (char *dest, size_t destlen, const char *src)
426 while (*src && --destlen > 2)
428 if (strchr (rx_special_chars, *src))
444 /* Read a line from ``fp'' into the dynamically allocated ``s'',
445 * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed.
446 * If a line ends with "\", this char and the linefeed is removed,
447 * and the next line is read too.
449 char *mutt_read_line (char *s, size_t *size, FILE *fp, int *line)
456 s = safe_malloc (STRING);
462 if (fgets (s + offset, *size - offset, fp) == NULL)
467 if ((ch = strchr (s + offset, '\n')) != NULL)
471 if (ch > s && *(ch - 1) == '\r')
473 if (ch == s || *(ch - 1) != '\\')
480 c = getc (fp); /* This is kind of a hack. We want to know if the
481 char at the current point in the input stream is EOF.
482 feof() will only tell us if we've already hit EOF, not
483 if the next character is EOF. So, we need to read in
484 the next character and manually check if it is EOF. */
487 /* The last line of fp isn't \n terminated */
493 ungetc (c, fp); /* undo our dammage */
494 /* There wasn't room for the line -- increase ``s'' */
495 offset = *size - 1; /* overwrite the terminating 0 */
497 safe_realloc (&s, *size);
504 mutt_substrcpy (char *dest, const char *beg, const char *end, size_t destlen)
509 if (len > destlen - 1)
511 memcpy (dest, beg, len);
516 char *mutt_substrdup (const char *begin, const char *end)
524 len = strlen (begin);
526 p = safe_malloc (len + 1);
527 memcpy (p, begin, len);
532 /* prepare a file name to survive the shell's quoting rules.
533 * From the Unix programming FAQ by way of Liviu.
536 size_t mutt_quote_filename (char *d, size_t l, const char *f)
546 /* leave some space for the trailing characters. */
551 for(i = 0; j < l && f[i]; i++)
553 if(f[i] == '\'' || f[i] == '`')
570 /* NULL-pointer aware string comparison functions */
572 int mutt_strcmp(const char *a, const char *b)
574 return strcmp(NONULL(a), NONULL(b));
577 int mutt_strcasecmp(const char *a, const char *b)
579 return strcasecmp(NONULL(a), NONULL(b));
582 int mutt_strncmp(const char *a, const char *b, size_t l)
584 return strncmp(NONULL(a), NONULL(b), l);
587 int mutt_strncasecmp(const char *a, const char *b, size_t l)
589 return strncasecmp(NONULL(a), NONULL(b), l);
592 size_t mutt_strlen(const char *a)
594 return a ? strlen (a) : 0;
597 int mutt_strcoll(const char *a, const char *b)
599 return strcoll(NONULL(a), NONULL(b));
602 const char *mutt_stristr (const char *haystack, const char *needle)
611 while (*(p = haystack))
615 tolower ((unsigned char) *p) == tolower ((unsigned char) *q);
625 char *mutt_skip_whitespace (char *p)
631 void mutt_remove_trailing_ws (char *s)
635 for (p = s + mutt_strlen (s) - 1 ; p >= s && ISSPACE (*p) ; p--)
639 char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l)
641 const char *fmt = "%s/%s";
643 if (!*fname || (*dir && dir[strlen(dir)-1] == '/'))
646 snprintf (d, l, fmt, dir, fname);
650 const char *mutt_basename (const char *f)
652 const char *p = strrchr (f, '/');