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;
367 if ((fd = open (path, flags, 0666)) < 0)
370 /* make sure the file is not symlink */
371 if (lstat (path, &osb) < 0 || fstat (fd, &nsb) < 0 ||
372 compare_stat(&osb, &nsb) == -1)
374 /* dprint (1, (debugfile, "safe_open(): %s is a symlink!\n", path)); */
382 /* when opening files for writing, make sure the file doesn't already exist
383 * to avoid race conditions.
385 FILE *safe_fopen (const char *path, const char *mode)
387 /* first set the current umask */
392 int flags = O_CREAT | O_EXCL;
403 if ((fd = safe_open (path, flags)) < 0)
406 return (fdopen (fd, mode));
409 return (fopen (path, mode));
412 static char safe_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+@{}._-:%/";
414 void mutt_sanitize_filename (char *f, short slash)
420 if ((slash && *f == '/') || !strchr (safe_chars, *f))
425 /* these characters must be escaped in regular expressions */
427 static char rx_special_chars[] = "^.[$()|*+?{\\";
429 int mutt_rx_sanitize_string (char *dest, size_t destlen, const char *src)
431 while (*src && --destlen > 2)
433 if (strchr (rx_special_chars, *src))
449 /* Read a line from ``fp'' into the dynamically allocated ``s'',
450 * increasing ``s'' if necessary. The ending "\n" or "\r\n" is removed.
451 * If a line ends with "\", this char and the linefeed is removed,
452 * and the next line is read too.
454 char *mutt_read_line (char *s, size_t *size, FILE *fp, int *line)
461 s = safe_malloc (STRING);
467 if (fgets (s + offset, *size - offset, fp) == NULL)
472 if ((ch = strchr (s + offset, '\n')) != NULL)
476 if (ch > s && *(ch - 1) == '\r')
478 if (ch == s || *(ch - 1) != '\\')
485 c = getc (fp); /* This is kind of a hack. We want to know if the
486 char at the current point in the input stream is EOF.
487 feof() will only tell us if we've already hit EOF, not
488 if the next character is EOF. So, we need to read in
489 the next character and manually check if it is EOF. */
492 /* The last line of fp isn't \n terminated */
498 ungetc (c, fp); /* undo our dammage */
499 /* There wasn't room for the line -- increase ``s'' */
500 offset = *size - 1; /* overwrite the terminating 0 */
502 safe_realloc (&s, *size);
509 mutt_substrcpy (char *dest, const char *beg, const char *end, size_t destlen)
514 if (len > destlen - 1)
516 memcpy (dest, beg, len);
521 char *mutt_substrdup (const char *begin, const char *end)
529 len = strlen (begin);
531 p = safe_malloc (len + 1);
532 memcpy (p, begin, len);
537 /* prepare a file name to survive the shell's quoting rules.
538 * From the Unix programming FAQ by way of Liviu.
541 size_t mutt_quote_filename (char *d, size_t l, const char *f)
551 /* leave some space for the trailing characters. */
556 for(i = 0; j < l && f[i]; i++)
558 if(f[i] == '\'' || f[i] == '`')
575 /* NULL-pointer aware string comparison functions */
577 int mutt_strcmp(const char *a, const char *b)
579 return strcmp(NONULL(a), NONULL(b));
582 int mutt_strcasecmp(const char *a, const char *b)
584 return strcasecmp(NONULL(a), NONULL(b));
587 int mutt_strncmp(const char *a, const char *b, size_t l)
589 return strncmp(NONULL(a), NONULL(b), l);
592 int mutt_strncasecmp(const char *a, const char *b, size_t l)
594 return strncasecmp(NONULL(a), NONULL(b), l);
597 size_t mutt_strlen(const char *a)
599 return a ? strlen (a) : 0;
602 int mutt_strcoll(const char *a, const char *b)
604 return strcoll(NONULL(a), NONULL(b));
607 const char *mutt_stristr (const char *haystack, const char *needle)
616 while (*(p = haystack))
620 tolower ((unsigned char) *p) == tolower ((unsigned char) *q);
630 char *mutt_skip_whitespace (char *p)
636 void mutt_remove_trailing_ws (char *s)
640 for (p = s + mutt_strlen (s) - 1 ; p >= s && ISSPACE (*p) ; p--)
644 char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l)
646 const char *fmt = "%s/%s";
648 if (!*fname || (*dir && dir[strlen(dir)-1] == '/'))
651 snprintf (d, l, fmt, dir, fname);
655 const char *mutt_basename (const char *f)
657 const char *p = strrchr (f, '/');