/* general.c -- Stuff that is used by all files. */ /* Copyright (C) 1987,1989 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. Bash is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. Bash is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Bash; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include "shell.h" #ifdef SYSV #include #else #include #endif /* SYSV */ #ifndef NULL #define NULL 0x0 #endif #if !defined (rindex) extern char *rindex (); #endif /* **************************************************************** */ /* */ /* Memory Allocation and Deallocation. */ /* */ /* **************************************************************** */ char * xmalloc (size) int size; { register char *temp = (char *)malloc (size); if (!temp) fatal_error ("Out of virtual memory!"); return (temp); } char * xrealloc (pointer, size) register char *pointer; int size; { pointer = (char *)realloc (pointer, size); if (!pointer) fatal_error ("Out of virtual memory!"); return (pointer); } /* **************************************************************** */ /* */ /* Generic List Functions */ /* */ /* **************************************************************** */ /* Call FUNCTION on every member of LIST, a generic list. */ map_over_list (list, function) GENERIC_LIST *list; Function *function; { while (list) { (*function) (list); list = list->next; } } /* Call FUNCTION on every string in WORDS. */ map_over_words (words, function) WORD_LIST *words; Function *function; { while (words) { (*function)(words->word->word); words = words->next; } } /* Reverse the chain of structures in LIST. Output the new head of the chain. You should always assign the output value of this function to something, or you will lose the chain. */ GENERIC_LIST * reverse_list (list) register GENERIC_LIST *list; { register GENERIC_LIST *next, *prev = (GENERIC_LIST *)NULL; while (list) { next = list->next; list->next = prev; prev = list; list = next; } return (prev); } /* Return the number of elements in LIST, a generic list. */ list_length (list) register GENERIC_LIST *list; { register int i; for (i = 0; list; list = list->next, i++); return (i); } /* Delete the element of LIST which satisfies the predicate function COMPARER. Returns the element that was deleted, so you can dispose of it, or -1 if the element wasn't found. COMPARER is called with the list element and then ARG. Note that LIST contains the address of a variable which points to the list. You might call this function like this: SHELL_VAR *elt = delete_element (&variable_list, check_var_has_name, "foo"); dispose_variable (elt); */ GENERIC_LIST * delete_element (list, comparer, arg) GENERIC_LIST **list; Function *comparer; { register GENERIC_LIST *prev = (GENERIC_LIST *)NULL; register GENERIC_LIST *temp = *list; while (temp) { if ((*comparer) (temp, arg)) { if (prev) prev->next = temp->next; else *list = temp->next; return (temp); } prev = temp; temp = temp->next; } return ((GENERIC_LIST *)-1); } /* Find NAME in ARRAY. Return the index of NAME, or -1 if not present. ARRAY shoudl be NULL terminated. */ find_name_in_list (name, array) char *name, *array[]; { int i; for (i=0; array[i]; i++) if (strcmp (name, array[i]) == 0) return (i); return (-1); } /* Return the length of ARRAY, a NULL terminated array of char *. */ array_len (array) register char **array; { register int i; for (i=0; array[i]; i++); return (i); } /* Free the contents of ARRAY, a NULL terminated array of char *. */ free_array (array) register char **array; { register int i = 0; if (!array) return; while (array[i]) free (array[i++]); free (array); } /* Append LIST2 to LIST1. Return the header of the list. */ GENERIC_LIST * list_append (head, tail) GENERIC_LIST *head, *tail; { register GENERIC_LIST *t_head = head; if (!t_head) return (tail); while (t_head->next) t_head = t_head->next; t_head->next = tail; return (head); } /* Some random string stuff. */ /* Remove all leading whitespace from STRING. This includes newlines. STRING should be terminated with a zero. */ strip_leading (string) char *string; { char *start = string; while (*string && (whitespace (*string) || *string == '\n')) string++; if (string != start) { int len = strlen (string); bcopy (string, start, len); start[len] = '\0'; } } /* Remove all trailing whitespace from STRING. This includes newlines. STRING should be terminated with a zero. */ strip_trailing (string) char *string; { int len = strlen (string); while (len--) if (!whitespace (string[len]) && string[len] != '\n') { string[len + 1] = '\0'; return; } } /* Turn STRING (a pathname) into an absolute pathname, assuming that DOT_PATH contains the symbolic location of '.'. This always returns a new string, even if STRING was an absolute pathname to begin with. */ #ifndef MAXPATHLEN #define MAXPATHLEN 1024 #endif static char current_path[MAXPATHLEN]; char * make_absolute (string, dot_path) char *string, *dot_path; { register char *cp; if (!dot_path || *string == '/') return (savestring (string)); strcpy (current_path, dot_path); if (!current_path[0]) strcpy (current_path, "./"); cp = current_path + (strlen (current_path) - 1); if (*cp++ != '/') *cp++ = '/'; *cp = '\0'; while (*string) { if (*string == '.') { if (!string[1]) return (savestring (current_path)); if (string[1] == '/') { string += 2; continue; } if (string[1] == '.' && (string[2] == '/' || !string[2])) { string += 2; if (*string) string++; pathname_backup (current_path, 1); cp = current_path + strlen (current_path); continue; } } while (*string && *string != '/') *cp++ = *string++; if (*string) *cp++ = *string++; *cp = '\0'; } return (savestring (current_path)); } /* Remove the last N directories from PATH. Do not leave a blank path. PATH must contain enough space for MAXPATHLEN characters. */ pathname_backup (path, n) char *path; int n; { register char *p = path + strlen (path); if (*path) p--; while (n--) { while (*p == '/') p--; while (*p != '/') p--; *++p = '\0'; } } /* Return 1 if STRING contains an absolute pathname, else 0. */ absolute_pathname (string) char *string; { if (!string || !strlen (string)) return (0); if (*string == '/') return (1); if (*string++ == '.') { if ((!*string) || *string == '/') return (1); if (*string++ == '.') if (!*string || *string == '/') return (1); } return (0); } /* Return the `basename' of the pathname in STRING (the stuff after the last '/'). If STRING is not a full pathname, simply return it. */ char * base_pathname (string) char *string; { char *p = rindex (string, '/'); if (*string != '/') return (string); if (p) return (++p); else return (string); } /* Determine if s2 occurs in s1. If so, return a pointer to the match in s1. The compare is case insensitive. */ char * strindex (s1, s2) register char *s1, *s2; { register int i, l = strlen (s2); register int len = strlen (s1); for (i = 0; (len - i) >= l; i++) if (strnicmp (&s1[i], s2, l) == 0) return (s1 + i); return ((char *)NULL); } #ifndef to_upper #define lowercase_p(c) (((c) > ('a' - 1) && (c) < ('z' + 1))) #define uppercase_p(c) (((c) > ('A' - 1) && (c) < ('Z' + 1))) #define pure_alphabetic(c) (lowercase_p(c) || uppercase_p(c)) #define to_upper(c) (lowercase_p(c) ? ((c) - 32) : (c)) #define to_lower(c) (uppercase_p(c) ? ((c) + 32) : (c)) #endif /* Compare at most COUNT characters from string1 to string2. Case doesn't matter. */ int strnicmp (string1, string2, count) char *string1, *string2; { register char ch1, ch2; while (count) { ch1 = *string1++; ch2 = *string2++; if (to_upper(ch1) == to_upper(ch2)) count--; else break; } return (count); } /* strcmp (), but caseless. */ int stricmp (string1, string2) char *string1, *string2; { register char ch1, ch2; while (*string1 && *string2) { ch1 = *string1++; ch2 = *string2++; if (to_upper(ch1) != to_upper(ch2)) return (1); } return (*string1 | *string2); } #if defined (SONY) char * strchr (s, c) char *s; int c; { char *index (); return (index (s, c)); } #endif /* SONY */ extern int errno; #include #include #ifdef NO_DUP2 dup2 (fd1, fd2) int fd1, fd2; { if (fcntl (fd1, F_GETFL, 0) == -1) /* fd1 is an invalid fd */ return (-1); if (fd2 < 0 || fd2 >= NOFILE) { errno = EBADF; return (-1); } if (fd1 == fd2) return (0); (void) close (fd2); return (fcntl (fd1, F_DUPFD, fd2)); } #endif /* NO_DUP */ #ifdef SYSV #include bcopy(s,d,n) char *d,*s; { while(n--) *d++ = *s++; } char *getwd(s) char *s; { getcwd(s,MAXPATHLEN); return s; } char *index(s,c) char *s; { char *strchr(); return strchr(s,c); } char *rindex(s,c) char *s; { char *strrchr(); return strrchr(s,c); } gethostname (name, namelen) char *name; int namelen; { int i; struct utsname uts; --namelen; uname (&uts); i = strlen (uts.nodename) + 1; strncpy (name, uts.nodename, i < namelen ? i : namelen); name[namelen] = '\0'; return (0); } int sysv_getc (stream) FILE *stream; { int result; char c; while (1) { result = read (fileno (stream), &c, sizeof (char)); if (result == sizeof (char)) return (c); if (errno != EINTR) return (EOF); } } #endif /* SYSV */