Imported from ../bash-1.14.7.tar.gz.
[platform/upstream/bash.git] / general.c
1 /* general.c -- Stuff that is used by all files. */
2
3 /* Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992
4    Free Software Foundation, Inc.
5
6    This file is part of GNU Bash, the Bourne Again SHell.
7
8    Bash is free software; you can redistribute it and/or modify it under
9    the terms of the GNU General Public License as published by the Free
10    Software Foundation; either version 2, or (at your option) any later
11    version.
12
13    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
14    WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16    for more details.
17
18    You should have received a copy of the GNU General Public License along
19    with Bash; see the file COPYING.  If not, write to the Free Software
20    Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
21
22 #include "config.h"     /* includes unistd.h for us */
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include "bashtypes.h"
27 #include <sys/param.h>
28 #if defined (_POSIX_VERSION)
29 #  if defined (amiga) && defined (USGr4)
30 #    define _POSIX_SOURCE
31 #  endif
32 #  include <signal.h>
33 #  if defined (amiga) && defined (USGr4)
34 #    undef _POSIX_SOURCE
35 #  endif
36 #endif /* _POSIX_VERSION */
37 #include "filecntl.h"
38 #include "bashansi.h"
39 #include "shell.h"
40 #include <tilde/tilde.h>
41
42 #if !defined (USG) || defined (HAVE_RESOURCE)
43 #  include <sys/time.h>
44 #endif
45
46 #include <sys/times.h>
47 #include "maxpath.h"
48
49 #if !defined (errno)
50 extern int errno;
51 #endif /* !errno */
52
53 /* Make the functions strchr and strrchr if they do not exist. */
54 #if !defined (HAVE_STRCHR)
55 char *
56 strchr (string, c)
57      char *string;
58      int c;
59 {
60   register int i;
61
62   for (i = 0; string && string[i]; i++)
63     if (string[i] == c)
64       return ((char *) (string + i));
65
66   return ((char *) NULL);
67 }
68
69 char *
70 strrchr (string, c)
71      char *string;
72      int c;
73 {
74   register int i;
75
76   if (string)
77     i = strlen (string) - 1;
78   else
79     i = -1;
80
81   for (; string && i > -1; i--)
82     if (string[i] == c)
83       return ((char *) (string + i));
84
85   return ((char *) NULL);
86 }
87 #endif /* !HAVE_STRCHR */
88
89 /* **************************************************************** */
90 /*                                                                  */
91 /*                 Memory Allocation and Deallocation.              */
92 /*                                                                  */
93 /* **************************************************************** */
94
95 char *
96 xmalloc (size)
97      int size;
98 {
99   register char *temp = (char *)malloc (size);
100
101   if (!temp)
102     fatal_error ("Out of virtual memory!");
103
104   return (temp);
105 }
106
107 char *
108 xrealloc (pointer, size)
109      GENPTR pointer;
110      int size;
111 {
112   char *temp;
113
114   if (!pointer)
115     temp = xmalloc (size);
116   else
117     temp = (char *)realloc (pointer, size);
118
119   if (!temp)
120     fatal_error ("Out of virtual memory!");
121
122   return (temp);
123 }
124
125 /* Use this as the function to call when adding unwind protects so we
126    don't need to know what free() returns. */
127 void
128 xfree (string)
129      char *string;
130 {
131   free (string);
132 }
133
134 /* **************************************************************** */
135 /*                                                                  */
136 /*                   Integer to String Conversion                   */
137 /*                                                                  */
138 /* **************************************************************** */
139
140 /* Number of characters that can appear in a string representation
141    of an integer.  32 is larger than the string rep of 2^^31 - 1. */
142 #define MAX_INT_LEN 32
143
144 /* Integer to string conversion.  This conses the string; the
145    caller should free it. */
146 char *
147 itos (i)
148      int i;
149 {
150   char *buf, *p, *ret;
151   int negative = 0;
152   unsigned int ui;
153
154   buf = xmalloc (MAX_INT_LEN);
155
156   if (i < 0)
157     {
158       negative++;
159       i = -i;
160     }
161
162   ui = (unsigned int) i;
163
164   buf[MAX_INT_LEN - 1] = '\0';
165   p = &buf[MAX_INT_LEN - 2];
166
167   do
168     *p-- = (ui % 10) + '0';
169   while (ui /= 10);
170
171   if (negative)
172     *p-- = '-';
173
174   ret = savestring (p + 1);
175   free (buf);
176   return (ret);
177 }
178
179 /* Return non-zero if all of the characters in STRING are digits. */
180 int
181 all_digits (string)
182      char *string;
183 {
184   while (*string)
185     {
186       if (!digit (*string))
187         return (0);
188       else
189         string++;
190     }
191   return (1);
192 }
193
194 /* atol(3) is not universal */
195 long
196 string_to_long (s)
197      char *s;
198 {
199   long ret = 0L;
200   int neg = 0;
201
202   while (s && *s && whitespace (*s))
203     s++;
204   if (*s == '-' || *s == '+')
205     {
206       neg = *s == '-';
207       s++;
208     }
209   for ( ; s && *s && digit (*s); s++)
210     ret = (ret * 10) + digit_value (*s);
211   return (neg ? -ret : ret);
212 }
213
214 #if defined (RLIMTYPE)
215 RLIMTYPE
216 string_to_rlimtype (s)
217      char *s;
218 {
219   RLIMTYPE ret = 0;
220   int neg = 0;
221
222   while (s && *s && whitespace (*s))
223     s++;
224   if (*s == '-' || *s == '+')
225     {
226       neg = *s == '-';
227       s++;
228     }
229   for ( ; s && *s && digit (*s); s++)
230     ret = (ret * 10) + digit_value (*s);
231   return (neg ? -ret : ret);
232 }
233
234 void
235 print_rlimtype (n, addnl)
236      RLIMTYPE n;
237      int addnl;
238 {
239   char s[sizeof (RLIMTYPE) * 3 + 1];
240   int len = sizeof (RLIMTYPE) * 3 + 1;
241
242   if (n == 0)
243     {
244       printf ("0%s", addnl ? "\n" : "");
245       return;
246     }
247
248   if (n < 0)
249     {
250       putchar ('-');
251       n = -n;
252     }
253
254   s[--len] = '\0';
255   for ( ; n != 0; n /= 10)
256     s[--len] = n % 10 + '0';
257   printf ("%s%s", s + len, addnl ? "\n" : "");
258 }
259 #endif /* RLIMTYPE */
260
261 /* Return 1 if this token is a legal shell `identifier'; that is, it consists
262    solely of letters, digits, and underscores, and does not begin with a
263    digit. */
264 int
265 legal_identifier (name)
266      char *name;
267 {
268   register char *s;
269
270   if (!name || !*name || digit (*name))
271     return (0);
272
273   for (s = name; s && *s; s++)
274     {
275       if (!isletter (*s) && !digit (*s) && (*s != '_'))
276         return (0);
277     }
278   return (1);
279 }
280
281 /* Make sure that WORD is a valid shell identifier, i.e.
282    does not contain a dollar sign, nor is quoted in any way.  Nor
283    does it consist of all digits.  If CHECK_WORD is non-zero,
284    the word is checked to ensure that it consists of only letters,
285    digits, and underscores. */
286 check_identifier (word, check_word)
287      WORD_DESC *word;
288      int check_word;
289 {
290   if (word->dollar_present || word->quoted || all_digits (word->word))
291     {
292       report_error ("`%s' is not a valid identifier", word->word);
293       return (0);
294     }
295   else if (check_word && legal_identifier (word->word) == 0)
296     {
297       report_error ("`%s' is not a valid identifier", word->word);
298       return (0);
299     }
300   else
301     return (1);
302 }
303
304 /* A function to unset no-delay mode on a file descriptor.  Used in shell.c
305    to unset it on the fd passed as stdin.  Should be called on stdin if
306    readline gets an EAGAIN or EWOULDBLOCK when trying to read input. */
307
308 #if !defined (O_NDELAY)
309 #  if defined (FNDELAY)
310 #    define O_NDELAY FNDELAY
311 #  endif
312 #endif /* O_NDELAY */
313
314 /* Make sure no-delay mode is not set on file descriptor FD. */
315 void
316 unset_nodelay_mode (fd)
317      int fd;
318 {
319   int flags, set = 0;
320
321   if ((flags = fcntl (fd, F_GETFL, 0)) < 0)
322     return;
323
324 #if defined (O_NONBLOCK)
325   if (flags & O_NONBLOCK)
326     {
327       flags &= ~O_NONBLOCK;
328       set++;
329     }
330 #endif /* O_NONBLOCK */
331
332 #if defined (O_NDELAY)
333   if (flags & O_NDELAY)
334     {
335       flags &= ~O_NDELAY;
336       set++;
337     }
338 #endif /* O_NDELAY */
339
340   if (set)
341     fcntl (fd, F_SETFL, flags);
342 }
343
344
345 /* **************************************************************** */
346 /*                                                                  */
347 /*                      Generic List Functions                      */
348 /*                                                                  */
349 /* **************************************************************** */
350
351 /* Call FUNCTION on every member of LIST, a generic list. */
352 void
353 map_over_list (list, function)
354      GENERIC_LIST *list;
355      Function *function;
356 {
357   while (list)
358     {
359       (*function) (list);
360       list = list->next;
361     }
362 }
363
364 /* Call FUNCTION on every string in WORDS. */
365 void
366 map_over_words (words, function)
367      WORD_LIST *words;
368      Function *function;
369 {
370   while (words)
371     {
372       (*function)(words->word->word);
373       words = words->next;
374     }
375 }
376
377 /* Reverse the chain of structures in LIST.  Output the new head
378    of the chain.  You should always assign the output value of this
379    function to something, or you will lose the chain. */
380 GENERIC_LIST *
381 reverse_list (list)
382      GENERIC_LIST *list;
383 {
384   register GENERIC_LIST *next, *prev = (GENERIC_LIST *)NULL;
385
386   while (list)
387     {
388       next = list->next;
389       list->next = prev;
390       prev = list;
391       list = next;
392     }
393   return (prev);
394 }
395
396 /* Return the number of elements in LIST, a generic list. */
397 int
398 list_length (list)
399      GENERIC_LIST *list;
400 {
401   register int i;
402
403   for (i = 0; list; list = list->next, i++);
404   return (i);
405 }
406
407 /* A global variable which acts as a sentinel for an `error' list return. */
408 GENERIC_LIST global_error_list;
409
410 /* Delete the element of LIST which satisfies the predicate function COMPARER.
411    Returns the element that was deleted, so you can dispose of it, or -1 if
412    the element wasn't found.  COMPARER is called with the list element and
413    then ARG.  Note that LIST contains the address of a variable which points
414    to the list.  You might call this function like this:
415
416    SHELL_VAR *elt = delete_element (&variable_list, check_var_has_name, "foo");
417    dispose_variable (elt);
418 */
419 GENERIC_LIST *
420 delete_element (list, comparer, arg)
421      GENERIC_LIST **list;
422      Function *comparer;
423      char *arg;
424 {
425   register GENERIC_LIST *prev = (GENERIC_LIST *)NULL;
426   register GENERIC_LIST *temp = *list;
427
428   while (temp)
429     {
430       if ((*comparer) (temp, arg))
431         {
432           if (prev)
433             prev->next = temp->next;
434           else
435             *list = temp->next;
436           return (temp);
437         }
438       prev = temp;
439       temp = temp->next;
440     }
441   return ((GENERIC_LIST *)&global_error_list);
442 }
443
444 /* Find NAME in ARRAY.  Return the index of NAME, or -1 if not present.
445    ARRAY should be NULL terminated. */
446 int
447 find_name_in_list (name, array)
448      char *name, **array;
449 {
450   int i;
451
452   for (i = 0; array[i]; i++)
453     if (strcmp (name, array[i]) == 0)
454       return (i);
455
456   return (-1);
457 }
458
459 /* Return the length of ARRAY, a NULL terminated array of char *. */
460 int
461 array_len (array)
462      char **array;
463 {
464   register int i;
465   for (i = 0; array[i]; i++);
466   return (i);
467 }
468
469 /* Free the contents of ARRAY, a NULL terminated array of char *. */
470 void
471 free_array (array)
472      char **array;
473 {
474   register int i = 0;
475
476   if (!array) return;
477
478   while (array[i])
479     free (array[i++]);
480   free (array);
481 }
482
483 /* Allocate and return a new copy of ARRAY and its contents. */
484 char **
485 copy_array (array)
486      char **array;
487 {
488   register int i;
489   int len;
490   char **new_array;
491
492   len = array_len (array);
493
494   new_array = (char **)xmalloc ((len + 1) * sizeof (char *));
495   for (i = 0; array[i]; i++)
496     new_array[i] = savestring (array[i]);
497   new_array[i] = (char *)NULL;
498
499   return (new_array);
500 }
501
502 /* Comparison routine for use with qsort() on arrays of strings. */
503 int
504 qsort_string_compare (s1, s2)
505      register char **s1, **s2;
506 {
507   int result;
508
509   if ((result = **s1 - **s2) == 0)
510     result = strcmp (*s1, *s2);
511
512   return (result);
513 }
514
515 /* Append LIST2 to LIST1.  Return the header of the list. */
516 GENERIC_LIST *
517 list_append (head, tail)
518      GENERIC_LIST *head, *tail;
519 {
520   register GENERIC_LIST *t_head = head;
521
522   if (!t_head)
523     return (tail);
524
525   while (t_head->next)
526     t_head = t_head->next;
527   t_head->next = tail;
528   return (head);
529 }
530
531 /* Some random string stuff. */
532
533 /* Remove all leading whitespace from STRING.  This includes
534    newlines.  STRING should be terminated with a zero. */
535 void
536 strip_leading (string)
537      char *string;
538 {
539   char *start = string;
540
541   while (*string && (whitespace (*string) || *string == '\n'))
542     string++;
543
544   if (string != start)
545     {
546       int len = strlen (string);
547       FASTCOPY (string, start, len);
548       start[len] = '\0';
549     }
550 }
551
552 /* Remove all trailing whitespace from STRING.  This includes
553    newlines.  If NEWLINES_ONLY is non-zero, only trailing newlines
554    are removed.  STRING should be terminated with a zero. */
555 void
556 strip_trailing (string, newlines_only)
557      char *string;
558      int newlines_only;
559 {
560   int len = strlen (string) - 1;
561
562   while (len >= 0)
563     {
564       if ((newlines_only && string[len] == '\n') ||
565           (!newlines_only && whitespace (string[len])))
566         len--;
567       else
568         break;
569     }
570   string[len + 1] = '\0';
571 }
572
573 /* Canonicalize PATH, and return a new path.  The new path differs from PATH
574    in that:
575         Multple `/'s are collapsed to a single `/'.
576         Leading `./'s and trailing `/.'s are removed.
577         Trailing `/'s are removed.
578         Non-leading `../'s and trailing `..'s are handled by removing
579         portions of the path. */
580 char *
581 canonicalize_pathname (path)
582      char *path;
583 {
584   register int i, start;
585   char stub_char;
586   char *result;
587
588   /* The result cannot be larger than the input PATH. */
589   result = savestring (path);
590
591   stub_char = (*path == '/') ? '/' : '.';
592
593   /* Walk along RESULT looking for things to compact. */
594   i = 0;
595   while (1)
596     {
597       if (!result[i])
598         break;
599
600       while (result[i] && result[i] != '/')
601         i++;
602
603       start = i++;
604
605       /* If we didn't find any slashes, then there is nothing left to do. */
606       if (!result[start])
607         break;
608
609       /* Handle multiple `/'s in a row. */
610       while (result[i] == '/')
611         i++;
612
613 #if !defined (apollo)
614       if ((start + 1) != i)
615 #else
616       if ((start + 1) != i && (start != 0 || i != 2))
617 #endif /* apollo */
618         {
619           strcpy (result + start + 1, result + i);
620           i = start + 1;
621         }
622
623 #if 0
624       /* Handle backslash-quoted `/'. */
625       if (start > 0 && result[start - 1] == '\\')
626         continue;
627 #endif
628
629       /* Check for trailing `/'. */
630       if (start && !result[i])
631         {
632         zero_last:
633           result[--i] = '\0';
634           break;
635         }
636
637       /* Check for `../', `./' or trailing `.' by itself. */
638       if (result[i] == '.')
639         {
640           /* Handle trailing `.' by itself. */
641           if (!result[i + 1])
642             goto zero_last;
643
644           /* Handle `./'. */
645           if (result[i + 1] == '/')
646             {
647               strcpy (result + i, result + i + 1);
648               i = (start < 0) ? 0 : start;
649               continue;
650             }
651
652           /* Handle `../' or trailing `..' by itself. */
653           if (result[i + 1] == '.' &&
654               (result[i + 2] == '/' || !result[i + 2]))
655             {
656               while (--start > -1 && result[start] != '/');
657               strcpy (result + start + 1, result + i + 2);
658               i = (start < 0) ? 0 : start;
659               continue;
660             }
661         }
662     }
663
664   if (!*result)
665     {
666       *result = stub_char;
667       result[1] = '\0';
668     }
669   return (result);
670 }
671
672 /* Turn STRING (a pathname) into an absolute pathname, assuming that
673    DOT_PATH contains the symbolic location of `.'.  This always
674    returns a new string, even if STRING was an absolute pathname to
675    begin with. */
676 char *
677 make_absolute (string, dot_path)
678      char *string, *dot_path;
679 {
680   char *result;
681   int result_len;
682   
683   if (!dot_path || *string == '/')
684     result = savestring (string);
685   else
686     {
687       if (dot_path && dot_path[0])
688         {
689           result = xmalloc (2 + strlen (dot_path) + strlen (string));
690           strcpy (result, dot_path);
691           result_len = strlen (result);
692           if (result[result_len - 1] != '/')
693             {
694               result[result_len++] = '/';
695               result[result_len] = '\0';
696             }
697         }
698       else
699         {
700           result = xmalloc (3 + strlen (string));
701           result[0] = '.'; result[1] = '/'; result[2] = '\0';
702           result_len = 2;
703         }
704
705       strcpy (result + result_len, string);
706     }
707
708   return (result);
709 }
710
711 /* Return 1 if STRING contains an absolute pathname, else 0. */
712 int
713 absolute_pathname (string)
714      char *string;
715 {
716   if (!string || !*string)
717     return (0);
718
719   if (*string == '/')
720     return (1);
721
722   if (*string++ == '.')
723     {
724       if (!*string || *string == '/')
725         return (1);
726
727       if (*string == '.' && (string[1] == '\0' || string[1] == '/'))
728         return (1);
729     }
730   return (0);
731 }
732
733 /* Return 1 if STRING is an absolute program name; it is absolute if it
734    contains any slashes.  This is used to decide whether or not to look
735    up through $PATH. */
736 int
737 absolute_program (string)
738      char *string;
739 {
740   return ((char *)strchr (string, '/') != (char *)NULL);
741 }
742
743 /* Return the `basename' of the pathname in STRING (the stuff after the
744    last '/').  If STRING is not a full pathname, simply return it. */
745 char *
746 base_pathname (string)
747      char *string;
748 {
749   char *p;
750
751   if (!absolute_pathname (string))
752     return (string);
753
754   p = (char *)strrchr (string, '/');
755   if (p)
756     return (++p);
757   else
758     return (string);
759 }
760
761 /* Return the full pathname of FILE.  Easy.  Filenames that begin
762    with a '/' are returned as themselves.  Other filenames have
763    the current working directory prepended.  A new string is
764    returned in either case. */
765 char *
766 full_pathname (file)
767      char *file;
768 {
769   char *disposer;
770
771   if (*file == '~')
772     file = tilde_expand (file);
773   else
774     file = savestring (file);
775
776   if ((*file == '/') && absolute_pathname (file))
777     return (file);
778
779   disposer = file;
780
781   {
782     char *current_dir = xmalloc (2 + MAXPATHLEN + strlen (file));
783     int dlen;
784     if (getwd (current_dir) == 0)
785       {
786         report_error (current_dir);
787         free (current_dir);
788         return ((char *)NULL);
789       }
790     dlen = strlen (current_dir);
791     current_dir[dlen++] = '/';
792
793     /* Turn /foo/./bar into /foo/bar. */
794     if (file[0] == '.' && file[1] == '/')
795       file += 2;
796
797     strcpy (current_dir + dlen, file);
798     free (disposer);
799     return (current_dir);
800   }
801 }
802
803 #if !defined (HAVE_STRCASECMP)
804
805 #if !defined (to_upper)
806 #  define to_upper(c) (islower(c) ? toupper(c) : (c))
807 #endif /* to_upper */
808
809 /* Compare at most COUNT characters from string1 to string2.  Case
810    doesn't matter. */
811 int
812 strnicmp (string1, string2, count)
813      char *string1, *string2;
814      int count;
815 {
816   register char ch1, ch2;
817
818   while (count)
819     {
820       ch1 = *string1++;
821       ch2 = *string2++;
822       if (to_upper(ch1) == to_upper(ch2))
823         count--;
824       else
825         break;
826     }
827   return (count);
828 }
829
830 /* strcmp (), but caseless. */
831 int
832 stricmp (string1, string2)
833      char *string1, *string2;
834 {
835   register char ch1, ch2;
836
837   while (*string1 && *string2)
838     {
839       ch1 = *string1++;
840       ch2 = *string2++;
841       if (to_upper(ch1) != to_upper(ch2))
842         return (1);
843     }
844   return (*string1 - *string2);
845 }
846 #endif /* !HAVE_STRCASECMP */
847
848 /* Determine if s2 occurs in s1.  If so, return a pointer to the
849    match in s1.  The compare is case insensitive. */
850 char *
851 strindex (s1, s2)
852      char *s1, *s2;
853 {
854   register int i, l = strlen (s2);
855   register int len = strlen (s1);
856
857   for (i = 0; (len - i) >= l; i++)
858     if (strnicmp (s1 + i, s2, l) == 0)
859       return (s1 + i);
860   return ((char *)NULL);
861 }
862
863 /* Set the environment variables $LINES and $COLUMNS in response to
864    a window size change. */
865 void
866 set_lines_and_columns (lines, cols)
867      int lines, cols;
868 {
869   char *val;
870
871   val = itos (lines);
872   bind_variable ("LINES", val);
873   free (val);
874
875   val = itos (cols);
876   bind_variable ("COLUMNS", val);
877   free (val);
878 }
879
880 /* A wrapper for bcopy that can be prototyped in general.h */
881 void
882 xbcopy (s, d, n)
883      char *s, *d;
884      int n;
885 {
886   FASTCOPY (s, d, n);
887 }
888
889 /* Return a string corresponding to the error number E.  From
890    the ANSI C spec. */
891 #if defined (strerror)
892 #  undef strerror
893 #endif
894
895 #if !defined (HAVE_STRERROR)
896 char *
897 strerror (e)
898      int e;
899 {
900   extern int sys_nerr;
901   extern char *sys_errlist[];
902   static char emsg[40];
903
904   if (e > 0 && e < sys_nerr)
905     return (sys_errlist[e]);
906   else
907     {
908       sprintf (emsg, "Unknown error %d", e);
909       return (&emsg[0]);
910     }
911 }
912 #endif /* HAVE_STRERROR */
913
914 #if (defined (USG) && !defined (HAVE_TIMEVAL)) || defined (Minix)
915 #  define TIMEVAL_MISSING
916 #endif
917
918 #if !defined (TIMEVAL_MISSING) || defined (HAVE_RESOURCE)
919 /* Print the contents of a struct timeval * in a standard way. */
920 void
921 print_timeval (tvp)
922      struct timeval *tvp;
923 {
924   int minutes, seconds_fraction;
925   long seconds;
926
927   seconds = tvp->tv_sec;
928
929   seconds_fraction = tvp->tv_usec % 1000000;
930   seconds_fraction = (seconds_fraction * 100) / 1000000;
931
932   minutes = seconds / 60;
933   seconds %= 60;
934
935   printf ("%0dm%0ld.%02ds",  minutes, seconds, seconds_fraction);
936 }
937 #endif /* !TIMEVAL_MISSING || HAVE_RESOURCE */
938
939 /* Print the time defined by a time_t (returned by the `times' and `time'
940    system calls) in a standard way.  This is scaled in terms of HZ, which
941    is what is returned by the `times' call. */
942
943 #if !defined (BrainDeath)
944 #  if !defined (HZ)
945 #    if defined (USG)
946 #      define HZ 100            /* From my Sys V.3.2 manual for times(2) */
947 #    else
948 #      define HZ 60             /* HZ is always 60 on BSD systems */
949 #    endif /* USG */
950 #  endif /* HZ */
951
952 void
953 print_time_in_hz (t)
954   time_t t;
955 {
956   int minutes, seconds_fraction;
957   long seconds;
958
959   seconds_fraction = t % HZ;
960   seconds_fraction = (seconds_fraction * 100) / HZ;
961
962   seconds = t / HZ;
963
964   minutes = seconds / 60;
965   seconds %= 60;
966
967   printf ("%0dm%0ld.%02ds",  minutes, seconds, seconds_fraction);
968 }
969 #endif /* BrainDeath */
970
971 #if !defined (HAVE_DUP2)
972 /* Replacement for dup2 (), for those systems which either don't have it,
973    or supply one with broken behaviour. */
974 int
975 dup2 (fd1, fd2)
976      int fd1, fd2;
977 {
978   extern int getdtablesize ();
979   int saved_errno, r;
980
981   /* If FD1 is not a valid file descriptor, then return immediately with
982      an error. */
983   if (fcntl (fd1, F_GETFL, 0) == -1)
984     return (-1);
985
986   if (fd2 < 0 || fd2 >= getdtablesize ())
987     {
988       errno = EBADF;
989       return (-1);
990     }
991
992   if (fd1 == fd2)
993     return (0);
994
995   saved_errno = errno;
996
997   (void) close (fd2);
998   r = fcntl (fd1, F_DUPFD, fd2);
999
1000   if (r >= 0)
1001     errno = saved_errno;
1002   else
1003     if (errno == EINVAL)
1004       errno = EBADF;
1005
1006   /* Force the new file descriptor to remain open across exec () calls. */
1007   SET_OPEN_ON_EXEC (fd2);
1008   return (r);
1009 }
1010 #endif /* !HAVE_DUP2 */
1011
1012 /*
1013  * Return the total number of available file descriptors.
1014  *
1015  * On some systems, like 4.2BSD and its descendents, there is a system call
1016  * that returns the size of the descriptor table: getdtablesize().  There are
1017  * lots of ways to emulate this on non-BSD systems.
1018  *
1019  * On System V.3, this can be obtained via a call to ulimit:
1020  *      return (ulimit(4, 0L));
1021  *
1022  * On other System V systems, NOFILE is defined in /usr/include/sys/param.h
1023  * (this is what we assume below), so we can simply use it:
1024  *      return (NOFILE);
1025  *
1026  * On POSIX systems, there are specific functions for retrieving various
1027  * configuration parameters:
1028  *      return (sysconf(_SC_OPEN_MAX));
1029  *
1030  */
1031
1032 #if !defined (USG) && !defined (HPUX) && !defined (HAVE_GETDTABLESIZE)
1033 #  define HAVE_GETDTABLESIZE
1034 #endif /* !USG && !HPUX && !HAVE_GETDTABLESIZE */
1035
1036 #if defined (hppa) && (defined (hpux_8) || defined (hpux_9))
1037 #  undef HAVE_GETDTABLESIZE
1038 #endif /* hppa && hpux_8 */
1039
1040 #if !defined (HAVE_GETDTABLESIZE)
1041 int
1042 getdtablesize ()
1043 {
1044 #  if defined (_POSIX_VERSION) && defined (_SC_OPEN_MAX)
1045   return (sysconf(_SC_OPEN_MAX));       /* Posix systems use sysconf */
1046 #  else /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */
1047 #    if defined (USGr3)
1048   return (ulimit (4, 0L));      /* System V.3 systems use ulimit(4, 0L) */
1049 #    else /* !USGr3 */
1050 #      if defined (NOFILE)      /* Other systems use NOFILE */
1051   return (NOFILE);
1052 #      else /* !NOFILE */
1053   return (20);                  /* XXX - traditional value is 20 */
1054 #      endif /* !NOFILE */
1055 #    endif /* !USGr3 */
1056 #  endif /* ! (_POSIX_VERSION && _SC_OPEN_MAX) */
1057 }
1058 #endif /* !HAVE_GETDTABLESIZE */
1059
1060 #if defined (USG)
1061
1062 #if !defined (HAVE_BCOPY)
1063 bcopy (s,d,n) char *d,*s; { FASTCOPY (s, d, n); }
1064 bzero (s,n) char *s; int n; { memset(s, '\0', n); }
1065 #endif /* !HAVE_BCOPY */
1066
1067 #if !defined (HAVE_GETHOSTNAME)
1068 #include <sys/utsname.h>
1069 int
1070 gethostname (name, namelen)
1071      char *name;
1072      int namelen;
1073 {
1074   int i;
1075   struct utsname ut;
1076
1077   --namelen;
1078
1079   uname (&ut);
1080   i = strlen (ut.nodename) + 1;
1081   strncpy (name, ut.nodename, i < namelen ? i : namelen);
1082   name[namelen] = '\0';
1083   return (0);
1084 }
1085 #endif /* !HAVE_GETHOSTNAME */
1086 #endif /* USG */
1087
1088 #if !defined (HAVE_GETWD)
1089 char *
1090 getwd (string)
1091      char *string;
1092 {
1093   extern char *getcwd ();
1094   char *result;
1095
1096   result = getcwd (string, MAXPATHLEN);
1097   if (result == NULL)
1098     strcpy (string, "getwd: cannot access parent directories");
1099   return (result);
1100 }
1101 #endif /* !HAVE_GETWD */
1102
1103 /* A slightly related function.  Get the prettiest name of this
1104    directory possible. */
1105 static char tdir[MAXPATHLEN];
1106
1107 /* Return a pretty pathname.  If the first part of the pathname is
1108    the same as $HOME, then replace that with `~'.  */
1109 char *
1110 polite_directory_format (name)
1111      char *name;
1112 {
1113   char *home = get_string_value ("HOME");
1114   int l = home ? strlen (home) : 0;
1115
1116   if (l > 1 && strncmp (home, name, l) == 0 && (!name[l] || name[l] == '/'))
1117     {
1118       strcpy (tdir + 1, name + l);
1119       tdir[0] = '~';
1120       return (tdir);
1121     }
1122   else
1123     return (name);
1124 }
1125
1126 #if defined (NO_READ_RESTART_ON_SIGNAL)
1127 static char localbuf[128];
1128 static int local_index = 0, local_bufused = 0;
1129
1130 /* Posix and USG systems do not guarantee to restart read () if it is
1131    interrupted by a signal.  We do the read ourselves, and restart it
1132    if it returns EINTR. */
1133 int
1134 getc_with_restart (stream)
1135      FILE *stream;
1136 {
1137   /* Try local buffering to reduce the number of read(2) calls. */
1138   if (local_index == local_bufused || local_bufused == 0)
1139     {
1140       while (1)
1141         {
1142           local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
1143           if (local_bufused > 0)
1144             break;
1145           else if (local_bufused == 0 || errno != EINTR)
1146             {
1147               local_index = 0;
1148               return EOF;
1149             }
1150         }
1151       local_index = 0;
1152     }
1153   return (localbuf[local_index++]);
1154 }
1155
1156 int
1157 ungetc_with_restart (c, fp)
1158      int c;
1159      FILE *fp;
1160 {
1161   if (local_index == 0 || local_bufused == 0 || c == EOF)
1162     return EOF;
1163   return (localbuf[--local_index] = c);
1164 }
1165
1166 #endif /* NO_READ_RESTART_ON_SIGNAL */
1167
1168 #if defined (USG) || defined (AIX) || (defined (_POSIX_VERSION) && defined (Ultrix))
1169 /* USG and strict POSIX systems do not have killpg ().  But we use it in
1170    jobs.c, nojobs.c and some of the builtins.  This can also be redefined
1171    as a macro if necessary. */
1172 #if !defined (_POSIX_VERSION)
1173 #  define pid_t int
1174 #endif /* _POSIX_VERSION */
1175
1176 int
1177 killpg (pgrp, sig)
1178      pid_t pgrp;
1179      int sig;
1180 {
1181   return (kill (-pgrp, sig));
1182 }
1183 #endif /* USG  || AIX || (_POSIX_VERSION && Ultrix) */
1184
1185 /* **************************************************************** */
1186 /*                                                                  */
1187 /*                  Tilde Initialization and Expansion              */
1188 /*                                                                  */
1189 /* **************************************************************** */
1190
1191 /* If tilde_expand hasn't been able to expand the text, perhaps it
1192    is a special shell expansion.  This function is installed as the
1193    tilde_expansion_failure_hook.  It knows how to expand ~- and ~+. */
1194 static char *
1195 bash_tilde_expand (text)
1196      char *text;
1197 {
1198   char *result = (char *)NULL;
1199
1200   if (!text[1])
1201     {
1202       if (*text == '+')
1203         result = get_string_value ("PWD");
1204       else if (*text == '-')
1205         result = get_string_value ("OLDPWD");
1206     }
1207
1208   if (result)
1209     result = savestring (result);
1210
1211   return (result);
1212 }
1213
1214 /* Initialize the tilde expander.  In Bash, we handle `~-' and `~+', as
1215    well as handling special tilde prefixes; `:~" and `=~' are indications
1216    that we should do tilde expansion. */
1217 void
1218 tilde_initialize ()
1219 {
1220   static int times_called = 0;
1221
1222   /* Tell the tilde expander that we want a crack if it fails. */
1223   tilde_expansion_failure_hook = (CPFunction *)bash_tilde_expand;
1224
1225   /* Tell the tilde expander about special strings which start a tilde
1226      expansion, and the special strings that end one.  Only do this once.
1227      tilde_initialize () is called from within bashline_reinitialize (). */
1228   if (times_called == 0)
1229     {
1230       tilde_additional_prefixes = (char **)xmalloc (3 * sizeof (char *));
1231       tilde_additional_prefixes[0] = "=~";
1232       tilde_additional_prefixes[1] = ":~";
1233       tilde_additional_prefixes[2] = (char *)NULL;
1234
1235       tilde_additional_suffixes = (char **)xmalloc (3 * sizeof (char *));
1236       tilde_additional_suffixes[0] = ":";
1237       tilde_additional_suffixes[1] = "=~";
1238       tilde_additional_suffixes[2] = (char *)NULL;
1239     }
1240   times_called++;
1241 }
1242
1243 #if defined (_POSIX_VERSION)
1244
1245 #if !defined (SA_INTERRUPT)
1246 #  define SA_INTERRUPT 0
1247 #endif
1248
1249 #if !defined (SA_RESTART)
1250 #  define SA_RESTART 0
1251 #endif
1252
1253 SigHandler *
1254 set_signal_handler (sig, handler)
1255      int sig;
1256      SigHandler *handler;
1257 {
1258   struct sigaction act, oact;
1259
1260   act.sa_handler = handler;
1261   act.sa_flags = 0;
1262 #if 0
1263   if (sig == SIGALRM)
1264     act.sa_flags |= SA_INTERRUPT;       /* XXX */
1265   else
1266     act.sa_flags |= SA_RESTART;         /* XXX */
1267 #endif
1268   sigemptyset (&act.sa_mask);
1269   sigemptyset (&oact.sa_mask);
1270   sigaction (sig, &act, &oact);
1271   return (oact.sa_handler);
1272 }
1273 #endif /* _POSIX_VERSION */