/* * SUB.C * * (c)1986 Matthew Dillon 9 October 1986 * * Subroutines used throughout the shell (not very descriptive, am I?) * * */ #include #include #include #include #include "shell.h" #define HM_STR 0 /* various HISTORY retrieval modes */ #define HM_REL 1 #define HM_ABS 2 extern struct FileLock *Lock(), *DupLock(), *CurrentDir(); extern struct FileLock *Clock; seterr() { char buf[32]; int stat; sprintf(buf, "%ld", Lastresult); set_var(LEVEL_SET, V_LASTERR, buf); stat = atoi(get_var(LEVEL_SET, V_STAT)); if (stat < Lastresult) stat = Lastresult; sprintf(buf, "%ld", stat); set_var(LEVEL_SET, V_STAT, buf); } char * next_word(str) register char *str; { while (*str && *str != ' ' && *str != 9) ++str; while (*str && (*str == ' ' || *str == 9)) ++str; return (str); } char * compile_av(av, start, end) short start, end; char **av; { char *cstr; short i, len; len = 0; for (i = start; i < end; ++i) len += strlen(av[i]) + 1; cstr = malloc(len + 1); *cstr = '\0'; for (i = start; i < end; ++i) { strcat (cstr, av[i]); strcat (cstr, " "); } return (cstr); } /* * FREE(ptr) --frees without actually freeing, so the data is still good * immediately after the free. */ Free(ptr) char *ptr; { static char *old_ptr; if (old_ptr) free (old_ptr); old_ptr = ptr; } /* * Add new string to history (H_head, H_tail, H_len, * S_histlen */ add_history(str) char *str; { register struct HIST *hist; while (H_len > S_histlen) del_history(); hist = (struct HIST *)malloc (sizeof(struct HIST)); if (H_head == NULL) { H_head = H_tail = hist; hist->next = NULL; } else { hist->next = H_head; H_head->prev = hist; H_head = hist; } hist->prev = NULL; hist->line = malloc (strlen(str) + 1); strcpy (hist->line, str); ++H_len; } del_history() { if (H_tail) { --H_len; ++H_tail_base; free (H_tail->line); if (H_tail->prev) { H_tail = H_tail->prev; free (H_tail->next); H_tail->next = NULL; } else { free (H_tail); H_tail = H_head = NULL; } } } char * last_history_entry() { if (H_head) return(H_head->line); return(""); } char * get_history(ptr) char *ptr; { register struct HIST *hist; register short len; short mode = HM_REL; long num = 1; char *str; char *result = NULL; if (ptr[1] >= '0' && ptr[1] <= '9') { mode = HM_ABS; num = atoi(&ptr[1]); goto skip; } switch (ptr[1]) { case '!': break; case '-': num += atoi(&ptr[2]); break; default: mode = HM_STR; str = ptr + 1; break; } skip: switch (mode) { case HM_STR: len = strlen(str); for (hist = H_head; hist; hist = hist->next) { if (strncmp(hist->line, str, len) == 0 && *hist->line != '!') { result = hist->line; break; } } break; case HM_REL: for (hist = H_head; hist && num--; hist = hist->next); if (hist) result = hist->line; break; case HM_ABS: len = H_tail_base; for (hist = H_tail; hist && len != num; hist = hist->prev, ++len); if (hist) result = hist->line; break; } if (result) { Eputs (result); return(result); } Eputs ("History substitution failed"); return (""); } replace_head(str) char *str; { if (str == NULL) str = ""; if (H_head) { free (H_head->line); H_head->line = malloc (strlen(str)+1); strcpy (H_head->line, str); } } perror(str) char *str; { ierror(str, IoErr()); } ierror(str, err) register char *str; short err; { register struct PERROR *per = Perror; if (err) { for (; per->errstr; ++per) { if (per->errnum == err) { fprintf (Cerr, "%s%s%s\n", per->errstr, (str) ? ": " : "", (str) ? str : ""); return (err); } } fprintf (Cerr, "Unknown DOS error %ld %s\n", err, (str) ? str : ""); } return (err); } /* * Disk directory routines * * dptr = dopen(name, stat) * struct DPTR *dptr; * char *name; * int *stat; * * dnext(dptr, name, stat) * struct DPTR *dptr; * char **name; * int *stat; * * dclose(dptr) -may be called with NULL without harm * * dopen() returns a struct DPTR, or NULL if the given file does not * exist. stat will be set to 1 if the file is a directory. If the * name is "", then the current directory is openned. * * dnext() returns 1 until there are no more entries. The **name and * *stat are set. *stat = 1 if the file is a directory. * * dclose() closes a directory channel. * */ struct DPTR * dopen(name, stat) char *name; register int *stat; { register struct DPTR *dp; *stat = 0; dp = (struct DPTR *)malloc(sizeof(struct DPTR)); if (*name == '\0') dp->lock = DupLock (Clock); else dp->lock = Lock (name, ACCESS_READ); if (dp->lock == NULL) { free (dp); return (NULL); } dp->fib = (struct FileInfoBlock *) AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC); if (!Examine (dp->lock, dp->fib)) { perror (name); dclose (dp); return (NULL); } if (dp->fib->fib_DirEntryType >= 0) *stat = 1; return (dp); } dnext(dp, pname, stat) register struct DPTR *dp; char **pname; int *stat; { if (dp == NULL) return (0); if (ExNext (dp->lock, dp->fib)) { *stat = (dp->fib->fib_DirEntryType < 0) ? 0 : 1; *pname = dp->fib->fib_FileName; return (1); } return (0); } dclose(dp) register struct DPTR *dp; { if (dp == NULL) return (1); if (dp->fib) FreeMem (dp->fib, sizeof(*dp->fib)); if (dp->lock) UnLock (dp->lock); free (dp); return (1); } isdir(file) char *file; { register struct DPTR *dp; int stat; stat = 0; if (dp = dopen (file, &stat)) dclose(dp); return (stat == 1); } free_expand(av) register char **av; { register char **base = av; if (av) { while (*av) { free (*av); ++av; } free (base); } } /* * EXPAND(wild_name, pac) * wild_name - char * (example: "df0:*.c") * pac - int * will be set to # of arguments. * * Standalone, except in requires Clock to point to the Current-Directory * lock. */ char ** expand(base, pac) char *base; int *pac; { register char *ptr; char **eav = (char **)malloc (sizeof(char *)); short eleft, eac; char *name; char *bname, *ename, *tail; int stat, scr; register struct DPTR *dp; *pac = eleft = eac = 0; base = strcpy(malloc(strlen(base)+1), base); for (ptr = base; *ptr && *ptr != '?' && *ptr != '*'; ++ptr); for (; ptr >= base && !(*ptr == '/' || *ptr == ':'); --ptr); if (ptr < base) { bname = strcpy (malloc(1), ""); } else { scr = ptr[1]; ptr[1] = '\0'; bname = strcpy (malloc(strlen(base)+1), base); ptr[1] = scr; } ename = ptr + 1; for (ptr = ename; *ptr && *ptr != '/'; ++ptr); scr = *ptr; *ptr = '\0'; tail = (scr) ? ptr + 1 : NULL; if ((dp = dopen (bname, &stat)) == NULL || stat == 0) { free (bname); free (base); free (eav); Eputs ("Could not open directory"); return (NULL); } while (dnext (dp, &name, &stat)) { if (compare_ok(ename, name)) { if (tail) { int alt_ac; char *search, **alt_av, **scrav; struct FileLock *lock; if (!stat) /* expect more dirs, but this not a dir */ continue; lock = CurrentDir (Clock = dp->lock); search = malloc(strlen(name)+strlen(tail)+2); strcpy (search, name); strcat (search, "/"); strcat (search, tail); scrav = alt_av = expand (search, &alt_ac); CurrentDir (Clock = lock); if (scrav) { while (*scrav) { if (eleft < 2) { char **scrav = (char **)malloc(sizeof(char *) * (eac + 10)); bmov (eav, scrav, (eac + 1) << 2); free (eav); eav = scrav; eleft = 10; } eav[eac] = malloc(strlen(bname)+strlen(*scrav)+1); strcpy(eav[eac], bname); strcat(eav[eac], *scrav); free (*scrav); ++scrav; --eleft, ++eac; } free (alt_av); } } else { if (eleft < 2) { char **scrav = (char **)malloc(sizeof(char *) * (eac + 10)); bmov (eav, scrav, (eac + 1) << 2); free (eav); eav = scrav; eleft = 10; } eav[eac] = malloc (strlen(bname)+strlen(name)+1); eav[eac] = strcpy(eav[eac], bname); strcat(eav[eac], name); --eleft, ++eac; } } } dclose (dp); *pac = eac; eav[eac] = NULL; free (bname); free (base); if (eac) return (eav); free (eav); return (NULL); } /* * Compare a wild card name with a normal name */ #define MAXB 8 compare_ok(wild, name) char *wild, *name; { register char *w = wild; register char *n = name; char *back[MAXB][2]; register char s1, s2; register short bi = 0; while (*n || *w) { switch (*w) { case '*': if (bi == MAXB) { Eputs ("Too many levels of '*'"); return (0); } back[bi][0] = w; back[bi][1] = n; ++bi; ++w; continue; goback: --bi; while (bi >= 0 && *back[bi][1] == '\0') --bi; if (bi < 0) return (0); w = back[bi][0] + 1; n = ++back[bi][1]; ++bi; continue; case '?': if (!*n) { if (bi) goto goback; return (0); } break; default: s1 = (*n >= 'A' && *n <= 'Z') ? *n - 'A' + 'a' : *n; s2 = (*w >= 'A' && *w <= 'Z') ? *w - 'A' + 'a' : *w; if (s1 != s2) { if (bi) goto goback; return (0); } break; } if (*n) ++n; if (*w) ++w; } return (1); } Oputs(str) char *str; { Write (Cout, str, strlen(str)); Write (Cout, "\n", 1); } Eputs(str) char *str; { Write (Cerr, str, strlen(str)); Write (Cerr, "\n", 1); } char * Ogets(str) char *str; { register int i = 0; while (Read(Cin, str + i, 1) == 1) { if (str[i] == '\n') { str[i] = 0; return (str); } if (++i == 255) { str[i] = 0; return (str); } } return (NULL); }