/* * SUB.C * * Matthew Dillon, 24 Feb 1986 * */ #include #include #include #include #include "shell.h" #define HM_STR 0 #define HM_REL 1 #define HM_ABS 2 extern struct FileLock *Lock(), *DupLock(), *CurrentDir(); extern struct FileLock *Clock; 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) char **av; { char *cstr; int 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) 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 * get_history(ptr) char *ptr; { register struct HIST *hist; register int len; int mode = HM_REL; int num = 1; char *str; 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) return (hist->line); } return (NULL); case HM_REL: for (hist = H_head; hist && num--; hist = hist->next); return ((hist) ? hist->line : NULL); case HM_ABS: len = H_tail_base; for (hist = H_tail; hist && len != num; hist = hist->prev, ++len); return ((hist) ? hist->line : NULL); } return (NULL); } replace_head(str1, str2, flag) char *str1, *str2; { char *str3; if (str1 == NULL) str1 = ""; if (str2 == NULL) { str2 = ""; flag = 0; } str3 = ((flag & (FL_EOC|FL_EOL)) == FL_EOC) ? ";" : " "; if (H_head) { free (H_head->line); H_head->line = malloc (strlen(str1)+strlen(str2)+2); strcpy (H_head->line, str1); strcat (H_head->line, str3); strcat (H_head->line, str2); } } perror(str) char *str; { struct PERROR *per = Perror; int err = IoErr(); if (err) { for (; per->errstr; ++per) { if (per->errnum == err) { printf ("%s%s%s\n", per->errstr, (str) ? ": " : "", (str) ? str : ""); return (err); } } printf ("Unknown DOS error %d %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; int *stat; { struct DPTR *dp; int namelen, endslash = 0; namelen = strlen(name); if (namelen && name[namelen - 1] == '/') { name[namelen - 1] = '\0'; endslash = 1; } *stat = 0; dp = (struct DPTR *)malloc(sizeof(struct DPTR)); if (*name == '\0') dp->lock = DupLock (Clock); else dp->lock = Lock (name, ACCESS_READ); if (endslash) name[namelen - 1] = '/'; 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) 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) 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); } free_expand(av) char **av; { 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; { char **eav = (char **)malloc (sizeof(char *)); int eleft, eac; char *ptr, *name; char *bname, *ename, *tail; int stat, scr; 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, NULL, &stat)) == NULL || stat == 0) { free (bname); free (base); free (eav); puts ("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)); movmem (eav, scrav, sizeof(char *) * (eac + 1)); 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)); movmem (eav, scrav, sizeof(char *) * (eac + 1)); 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; { char *w = wild; char *n = name; char *back[MAXB][2]; int bi = 0; while (*n || *w) { switch (*w) { case '*': if (bi == MAXB) { puts ("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: if (*n != *w) { if (bi) goto goback; return (0); } break; } if (*n) ++n; if (*w) ++w; } return (1); }