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.
43 void mutt_nocurses_error (const char *fmt, ...)
48 vfprintf (stderr, fmt, ap);
53 void *safe_calloc (size_t nmemb, size_t size)
60 if (((size_t) -1) / nmemb <= size)
62 mutt_error _("Integer overflow -- can't allocate memory!");
67 if (!(p = calloc (nmemb, size)))
69 mutt_error _("Out of memory!");
76 void *safe_malloc (size_t siz)
82 if ((p = (void *) malloc (siz)) == 0) /* __MEM_CHECKED__ */
84 mutt_error _("Out of memory!");
91 void safe_realloc (void *ptr, size_t siz)
94 void **p = (void **)ptr;
100 free (*p); /* __MEM_CHECKED__ */
107 r = (void *) realloc (*p, siz); /* __MEM_CHECKED__ */
110 /* realloc(NULL, nbytes) doesn't seem to work under SunOS 4.1.x --- __MEM_CHECKED__ */
111 r = (void *) malloc (siz); /* __MEM_CHECKED__ */
116 mutt_error _("Out of memory!");
124 void safe_free (void *ptr)
126 void **p = (void **)ptr;
129 free (*p); /* __MEM_CHECKED__ */
134 int safe_fclose (FILE **f)
145 char *safe_strdup (const char *s)
153 p = (char *)safe_malloc (l);
158 void mutt_str_replace (char **p, const char *s)
161 *p = safe_strdup (s);
164 void mutt_str_adjust (char **p)
166 if (!p || !*p) return;
167 safe_realloc (p, strlen (*p) + 1);
170 /* convert all characters in the string to lowercase */
171 char *mutt_strlower (char *s)
177 *p = tolower ((unsigned char) *p);
184 void mutt_unlink (const char *s)
190 if (stat (s, &sb) == 0)
192 if ((f = fopen (s, "r+")))
195 memset (buf, 0, sizeof (buf));
196 while (sb.st_size > 0)
198 fwrite (buf, 1, MIN (sizeof (buf), sb.st_size), f);
199 sb.st_size -= MIN (sizeof (buf), sb.st_size);
206 int mutt_copy_bytes (FILE *in, FILE *out, size_t size)
213 chunk = (size > sizeof (buf)) ? sizeof (buf) : size;
214 if ((chunk = fread (buf, 1, chunk, in)) < 1)
216 if (fwrite (buf, 1, chunk, out) != chunk)
218 /* dprint (1, (debugfile, "mutt_copy_bytes(): fwrite() returned short byte count\n")); */
227 int mutt_copy_stream (FILE *fin, FILE *fout)
230 char buf[LONG_STRING];
232 while ((l = fread (buf, 1, sizeof (buf), fin)) > 0)
234 if (fwrite (buf, 1, l, fout) != l)
242 compare_stat (struct stat *osb, struct stat *nsb)
244 if (osb->st_dev != nsb->st_dev || osb->st_ino != nsb->st_ino ||
245 osb->st_rdev != nsb->st_rdev)
253 int safe_symlink(const char *oldpath, const char *newpath)
255 struct stat osb, nsb;
257 if(!oldpath || !newpath)
260 if(unlink(newpath) == -1 && errno != ENOENT)
263 if (oldpath[0] == '/')
265 if (symlink (oldpath, newpath) == -1)
270 char abs_oldpath[_POSIX_PATH_MAX];
272 if ((getcwd (abs_oldpath, sizeof abs_oldpath) == NULL) ||
273 (strlen (abs_oldpath) + 1 + strlen (oldpath) + 1 > sizeof abs_oldpath))
276 strcat (abs_oldpath, "/"); /* __STRCAT_CHECKED__ */
277 strcat (abs_oldpath, oldpath); /* __STRCAT_CHECKED__ */
278 if (symlink (abs_oldpath, newpath) == -1)
282 if(stat(oldpath, &osb) == -1 || stat(newpath, &nsb) == -1
283 || compare_stat(&osb, &nsb) == -1)
293 * This function is supposed to do nfs-safe renaming of files.
295 * Warning: We don't check whether src and target are equal.
298 int safe_rename (const char *src, const char *target)
300 struct stat ssb, tsb;
305 if (link (src, target) != 0)
309 * Coda does not allow cross-directory links, but tells
310 * us it's a cross-filesystem linking attempt.
312 * However, the Coda rename call is allegedly safe to use.
314 * With other file systems, rename should just fail when
315 * the files reside on different file systems, so it's safe
321 return rename (src, target);
327 * Stat both links and check if they are equal.
330 if (stat (src, &ssb) == -1)
335 if (stat (target, &tsb) == -1)
341 * pretend that the link failed because the target file
345 if (compare_stat (&ssb, &tsb) == -1)
352 * Unlink the original link. Should we really ignore the return
361 int safe_open (const char *path, int flags)
363 struct stat osb, nsb;
366 if ((fd = open (path, flags, 0600)) < 0)
369 /* make sure the file is not symlink */
370 if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 ||
371 compare_stat(&osb, &nsb) == -1)
373 /* dprint (1, (debugfile, "safe_open(): %s is a symlink!\n", path)); */
381 /* when opening files for writing, make sure the file doesn't already exist
382 * to avoid race conditions.
384 FILE *safe_fopen (const char *path, const char *mode)
386 /* first set the current umask */
391 int flags = O_CREAT | O_EXCL;
402 if ((fd = safe_open (path, flags)) < 0)
405 return (fdopen (fd, mode));
408 return (fopen (path, mode));
411 static char safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
413 void mutt_sanitize_filename (char *f, short slash)
419 if ((slash && *f == '/') || !strchr (safe_chars, *f))
424 /* these characters must be escaped in regular expressions */
426 static char rx_special_chars[] = "^.[$()|*+?{\\";
428 int mutt_rx_sanitize_string (char *dest, size_t destlen, const char *src)
430 while (*src && --destlen > 2)
432 if (strchr (rx_special_chars, *src))
448 /* Read a line from ``fp'' into the dynamically allocated ``s'',
449 * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed.
450 * If a line ends with "\", this char and the linefeed is removed,
451 * and the next line is read too.
453 char *mutt_read_line (char *s, size_t *size, FILE *fp, int *line)
460 s = safe_malloc (STRING);
466 if (fgets (s + offset, *size - offset, fp) == NULL)
471 if ((ch = strchr (s + offset, '\n')) != NULL)
475 if (ch > s && *(ch - 1) == '\r')
477 if (ch == s || *(ch - 1) != '\\')
484 c = getc (fp); /* This is kind of a hack. We want to know if the
485 char at the current point in the input stream is EOF.
486 feof() will only tell us if we've already hit EOF, not
487 if the next character is EOF. So, we need to read in
488 the next character and manually check if it is EOF. */
491 /* The last line of fp isn't \n terminated */
497 ungetc (c, fp); /* undo our dammage */
498 /* There wasn't room for the line -- increase ``s'' */
499 offset = *size - 1; /* overwrite the terminating 0 */
501 safe_realloc (&s, *size);
508 mutt_substrcpy (char *dest, const char *beg, const char *end, size_t destlen)
513 if (len > destlen - 1)
515 memcpy (dest, beg, len);
520 char *mutt_substrdup (const char *begin, const char *end)
528 len = strlen (begin);
530 p = safe_malloc (len + 1);
531 memcpy (p, begin, len);
536 /* prepare a file name to survive the shell's quoting rules.
537 * From the Unix programming FAQ by way of Liviu.
540 size_t mutt_quote_filename (char *d, size_t l, const char *f)
550 /* leave some space for the trailing characters. */
555 for(i = 0; j < l && f[i]; i++)
557 if(f[i] == '\'' || f[i] == '`')
574 /* NULL-pointer aware string comparison functions */
576 int mutt_strcmp(const char *a, const char *b)
578 return strcmp(NONULL(a), NONULL(b));
581 int mutt_strcasecmp(const char *a, const char *b)
583 return strcasecmp(NONULL(a), NONULL(b));
586 int mutt_strncmp(const char *a, const char *b, size_t l)
588 return strncmp(NONULL(a), NONULL(b), l);
591 int mutt_strncasecmp(const char *a, const char *b, size_t l)
593 return strncasecmp(NONULL(a), NONULL(b), l);
596 size_t mutt_strlen(const char *a)
598 return a ? strlen (a) : 0;
601 int mutt_strcoll(const char *a, const char *b)
603 return strcoll(NONULL(a), NONULL(b));
606 const char *mutt_stristr (const char *haystack, const char *needle)
615 while (*(p = haystack))
619 tolower ((unsigned char) *p) == tolower ((unsigned char) *q);
629 char *mutt_skip_whitespace (char *p)
635 void mutt_remove_trailing_ws (char *s)
639 for (p = s + mutt_strlen (s) - 1 ; p >= s && ISSPACE (*p) ; p--)
643 char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l)
645 const char *fmt = "%s/%s";
647 if (!*fname || (*dir && dir[strlen(dir)-1] == '/'))
650 snprintf (d, l, fmt, dir, fname);
654 const char *mutt_basename (const char *f)
656 const char *p = strrchr (f, '/');