1 /* PSPP - computes sample statistics.
2 Copyright (C) 1997-9, 2000 Free Software Foundation, Inc.
3 Written by Ben Pfaff <blp@gnu.org>.
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of the
8 License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 /* AIX requires this to be the first thing in the file. */
23 #define alloca __builtin_alloca
31 #ifndef alloca /* predefined by HP cc +Olibcalls */
50 /*#define DEBUGGING 1 */
51 #include "debug-print.h"
53 /* PORTME: Everything in this file is system dependent. */
67 #include <win32/windows.h>
76 const char *config_path;
81 config_path = fn_getenv_default ("STAT_CONFIG_PATH", default_config_path);
84 /* Functions for performing operations on filenames. */
86 /* Substitutes $variables as defined by GETENV into INPUT and returns
87 a copy of the resultant string. Supports $var and ${var} syntaxes;
88 $$ substitutes as $. */
90 fn_interp_vars (const char *input, const char *(*getenv) (const char *))
94 if (NULL == strchr (input, '$'))
95 return xstrdup (input);
97 ds_init (NULL, &output, strlen (input));
103 return ds_value (&output);
110 ds_putchar (&output, '$');
119 start = ds_length (&output);
126 else if (*input == '{')
134 while (*input && *input != stop
135 && (stop || isalpha ((unsigned char) *input)))
136 ds_putchar (&output, *input++);
138 value = getenv (ds_value (&output) + start);
139 ds_truncate (&output, start);
140 ds_concat (&output, value);
142 if (stop && *input == stop)
147 ds_putchar (&output, *input++);
152 /* Expands csh tilde notation from the path INPUT into a malloc()'d
155 fn_tilde_expand (const char *input)
158 struct string output;
160 if (NULL == strchr (input, '~'))
161 return xstrdup (input);
162 ds_init (NULL, &output, strlen (input));
166 for (ip = input; *ip; )
167 if (*ip != '~' || (ip != input && ip[-1] != PATH_DELIMITER))
168 ds_putchar (&output, *ip++);
171 static const char stop_set[3] = {DIR_SEPARATOR, PATH_DELIMITER, 0};
176 cp = ip + strcspn (ip, stop_set);
183 strncpy (username, ip, cp - ip + 1);
185 pwd = getpwnam (username);
187 if (!pwd || !pwd->pw_dir)
188 ds_putchar (&output, *ip++);
190 ds_concat (&output, pwd->pw_dir);
194 const char *home = fn_getenv ("HOME");
196 ds_putchar (&output, *ip++);
198 ds_concat (&output, home);
204 return ds_value (&output);
208 fn_tilde_expand (char *input)
210 return xstrdup (input);
214 /* Searches for a configuration file with name NAME in the path given
215 by PATH, which is tilde- and environment-interpolated. Directories
216 in PATH are delimited by PATH_DELIMITER, defined in <pref.h>.
217 Returns the malloc'd full name of the first file found, or NULL if
220 If PREPEND is non-NULL, then it is prepended to each filename;
221 i.e., it looks like PREPEND/PATH_COMPONENT/NAME. This is not done
222 with absolute directories in the path. */
223 #if unix || __MSDOS__ || __WIN32__
225 fn_search_path (const char *basename, const char *path, const char *prepend)
228 struct string filename;
231 if (fn_absolute_p (basename))
232 return fn_tilde_expand (basename);
235 char *temp = fn_interp_vars (path, fn_getenv);
236 bp = subst_path = fn_tilde_expand (temp);
240 msg (VM (4), _("Searching for `%s'..."), basename);
241 ds_init (NULL, &filename, 64);
248 msg (VM (4), _("Search unsuccessful!"));
249 ds_destroy (&filename);
254 for (ep = bp; *ep && *ep != PATH_DELIMITER; ep++)
257 /* Paste together PREPEND/PATH/BASENAME. */
258 ds_clear (&filename);
259 if (prepend && !fn_absolute_p (bp))
261 ds_concat (&filename, prepend);
262 ds_putchar (&filename, DIR_SEPARATOR);
264 ds_concat_buffer (&filename, bp, ep - bp);
266 && ds_value (&filename)[ds_length (&filename) - 1] != DIR_SEPARATOR)
267 ds_putchar (&filename, DIR_SEPARATOR);
268 ds_concat (&filename, basename);
270 msg (VM (5), " - %s", ds_value (&filename));
271 if (fn_exists_p (ds_value (&filename)))
273 msg (VM (4), _("Found `%s'."), ds_value (&filename));
275 return ds_value (&filename);
280 msg (VM (4), _("Search unsuccessful!"));
282 ds_destroy (&filename);
288 #else /* not unix, msdog, lose32 */
290 fn_search_path (const char *basename, const char *path, const char *prepend)
292 size_t size = strlen (path) + 1 + strlen (basename) + 1;
297 size += strlen (prepend) + 1;
298 string = xmalloc (size);
303 cp = stpcpy (cp, prepend);
304 *cp++ = DIR_SEPARATOR;
306 cp = stpcpy (cp, path);
307 *cp++ = DIR_SEPARATOR;
308 strcpy (cp, basename);
312 #endif /* not unix, msdog, lose32 */
314 /* Prepends directory DIR to filename FILE and returns a malloc()'d
317 fn_prepend_dir (const char *file, const char *dir)
322 if (fn_absolute_p (file))
323 return xstrdup (file);
325 temp = xmalloc (strlen (file) + 1 + strlen (dir) + 1);
326 cp = stpcpy (temp, dir);
327 if (cp != temp && cp[-1] != DIR_SEPARATOR)
328 *cp++ = DIR_SEPARATOR;
329 cp = stpcpy (cp, file);
334 /* fn_normalize(): This very OS-dependent routine canonicalizes
335 filename FN1. The filename should not need to be the name of an
336 existing file. Returns a malloc()'d copy of the canonical name.
337 This function must always succeed; if it needs to bail out then it
338 should return xstrdup(FN1). */
341 fn_normalize (const char *filename)
344 char *fn1, *fn2, *dest;
347 if (fn_special_p (filename))
348 return xstrdup (filename);
350 fn1 = fn_tilde_expand (filename);
352 /* Follow symbolic links. */
356 fn1 = fn_readlink (fn1);
365 maxlen = strlen (fn1) * 2;
368 dest = fn2 = xmalloc (maxlen + 1);
371 if (*src == DIR_SEPARATOR)
377 memset (dest, 0, maxlen);
379 while (getcwd (dest, maxlen - (dest - fn2)) == NULL && errno == ERANGE)
382 dest = fn2 = xrealloc (fn2, maxlen + 1);
384 memset (dest, 0, maxlen);
394 dest = strchr (fn2, '\0');
395 if (dest - fn2 >= maxlen)
397 int ofs = dest - fn2;
399 fn2 = xrealloc (fn2, maxlen + 1);
402 if (dest[-1] != DIR_SEPARATOR)
403 *dest++ = DIR_SEPARATOR;
413 if (c == DIR_SEPARATOR || c == 0)
415 /* remove `./', `../' from directory */
416 if (dest[-1] == '.' && dest[-2] == DIR_SEPARATOR)
418 else if (dest[-1] == '.' && dest[-2] == '.' && dest[-3] == DIR_SEPARATOR)
423 while (dest[-1] != DIR_SEPARATOR)
426 else if (dest[-1] != DIR_SEPARATOR) /* remove extra slashes */
431 if (dest[-1] == DIR_SEPARATOR && dest > fn2 + 1)
436 return xrealloc (fn2, strlen (fn2) + 1);
444 if (dest - fn2 >= maxlen)
446 int ofs = dest - fn2;
448 fn2 = xrealloc (fn2, maxlen + 1);
457 fn_normalize (const char *fn1)
463 /* Don't change special filenames. */
464 if (is_special_filename (filename))
465 return xstrdup (filename);
467 /* First find the required buffer length. */
468 len = GetFullPathName (fn1, 0, NULL, NULL);
475 /* Then make a buffer that big. */
477 success = GetFullPathName (fn1, len, fn2, NULL);
478 if (success >= len || success == 0)
488 fn_normalize (const char *fn1)
490 char *fn2 = _fullpath (NULL, fn1, 0);
494 for (cp = fn2; *cp; cp++)
495 *cp = toupper ((unsigned char) (*cp));
498 return xstrdup (fn1);
502 fn_normalize (const char *fn1)
504 char *fn2 = xmalloc (1024);
506 fn2 = xrealloc (fn2, strlen (fn2) + 1);
509 #else /* not Lose32, Unix, or DJGPP */
511 fn_normalize (const char *fn)
515 #endif /* not Lose32, Unix, or DJGPP */
517 /* Returns the directory part of FILENAME, as a malloc()'d
520 fn_dirname (const char *filename)
526 len = strlen (filename);
527 if (len == 1 && filename[0] == '/')
529 else if (len && filename[len - 1] == DIR_SEPARATOR)
530 p = mm_find_reverse (filename, len - 1, filename + len - 1, 1);
532 p = strrchr (filename, DIR_SEPARATOR);
536 s = xmalloc (p - filename + 1);
537 memcpy (s, filename, p - filename);
543 /* Returns the basename part of FILENAME as a malloc()'d string. */
546 fn_basename (const char *filename)
548 /* Not used, not implemented. */
553 /* Returns the current working directory, as a malloc()'d string.
559 char *buffer = xmalloc (size);
563 char *value = getcwd (buffer, size);
569 buffer = xmalloc (size);
573 /* Find out information about files. */
575 /* Returns nonzero iff NAME specifies an absolute filename. */
577 fn_absolute_p (const char *name)
581 || !strncmp (name, "./", 2)
582 || !strncmp (name, "../", 3)
587 || !strncmp (name, ".\\", 2)
588 || !strncmp (name, "..\\", 3)
589 || (name[0] && name[1] == ':'))
596 /* Returns 1 if the filename specified is a virtual file that doesn't
597 really exist on disk, 0 if it's a real filename. */
599 fn_special_p (const char *filename)
601 if (!strcmp (filename, "-") || !strcmp (filename, "stdin")
602 || !strcmp (filename, "stdout") || !strcmp (filename, "stderr")
604 || filename[0] == '|'
605 || (*filename && filename[strlen (filename) - 1] == '|')
613 /* Returns nonzero if file with name NAME exists. */
615 fn_exists_p (const char *name)
620 return stat (name, &temp) == 0;
622 FILE *f = fopen (name, "r");
631 /* Stolen from libc.info but heavily modified, this is a wrapper
632 around readlink() that allows for arbitrary filename length. */
634 fn_readlink (const char *filename)
640 char *buffer = xmalloc (size);
641 int nchars = readlink (filename, buffer, size);
648 if (nchars < size - 1)
657 #else /* Not UNIX. */
659 fn_readlink (const char *filename)
663 #endif /* Not UNIX. */
665 /* Environment variables. */
667 /* Simulates $VER and $ARCH environment variables. */
669 fn_getenv (const char *s)
671 if (!strcmp (s, "VER"))
672 return fn_getenv_default ("STAT_VER", bare_version);
673 else if (!strcmp (s, "ARCH"))
674 return fn_getenv_default ("STAT_ARCH", host_system);
679 /* Returns getenv(KEY) if that's non-NULL; else returns DEF. */
681 fn_getenv_default (const char *key, const char *def)
683 const char *value = getenv (key);
684 return value ? value : def;
687 /* Basic file handling. */
689 /* Used for giving an error message on a set_safer security
692 safety_violation (const char *fn)
694 msg (SE, _("Not opening pipe file `%s' because SAFER option set."), fn);
699 /* As a general comment on the following routines, a `sensible value'
700 for errno includes 0 if there is no associated system error. The
701 routines will only set errno to 0 if there is an error in a
702 callback that sets errno to 0; they themselves won't. */
704 /* File open routine that understands `-' as stdin/stdout and `|cmd'
705 as a pipe to command `cmd'. Returns resultant FILE on success,
706 NULL on failure. If NULL is returned then errno is set to a
709 fn_open (const char *fn, const char *mode)
711 assert (mode[0] == 'r' || mode[0] == 'w');
713 if (mode[0] == 'r' && (!strcmp (fn, "stdin") || !strcmp (fn, "-")))
715 else if (mode[0] == 'w' && (!strcmp (fn, "stdout") || !strcmp (fn, "-")))
717 else if (mode[0] == 'w' && !strcmp (fn, "stderr"))
724 return safety_violation (fn);
726 return popen (&fn[1], mode);
728 else if (*fn && fn[strlen (fn) - 1] == '|')
734 return safety_violation (fn);
736 s = local_alloc (strlen (fn));
737 memcpy (s, fn, strlen (fn) - 1);
738 s[strlen (fn) - 1] = 0;
749 FILE *f = fopen (fn, mode);
751 if (f && mode[0] == 'w')
752 setvbuf (f, NULL, _IOLBF, 0);
758 /* Counterpart to fn_open that closes file F with name FN; returns 0
759 on success, EOF on failure. If EOF is returned, errno is set to a
762 fn_close (const char *fn, FILE *f)
764 if (!strcmp (fn, "-"))
767 else if (fn[0] == '|' || (*fn && fn[strlen (fn) - 1] == '|'))
777 /* More extensive file handling. */
779 /* File open routine that extends fn_open(). Opens or reopens a
780 file according to the contents of file_ext F. Returns nonzero on
781 success. If 0 is returned, errno is set to a sensible value. */
783 fn_open_ext (struct file_ext *f)
787 p = strstr (f->filename, "%d");
790 char *s = local_alloc (strlen (f->filename) + INT_DIGITS - 1);
793 memcpy (s, f->filename, p - f->filename);
794 cp = spprintf (&s[p - f->filename], "%d", *f->sequence_no);
802 if (f->preclose (f) == 0)
805 if (EOF == fn_close (f->filename, f->file) || error)
819 f->file = fn_open (s, f->mode);
822 if (f->file && f->postopen)
823 if (f->postopen (f) == 0)
826 fn_close (f->filename, f->file);
832 return (f->file != NULL);
838 f->file = fn_open (f->filename, f->mode);
840 if (f->file && f->postopen)
841 if (f->postopen (f) == 0)
844 fn_close (f->filename, f->file);
850 return (f->file != NULL);
854 /* Properly closes the file associated with file_ext F, if any.
855 Return nonzero on success. If zero is returned, errno is set to a
858 fn_close_ext (struct file_ext *f)
865 if (f->preclose (f) == 0)
868 if (EOF == fn_close (f->filename, f->file) || error)