/* * FILES.C * * File Manager! * * (c)Copyright 1987 Matthew Dillon, All Rights Reserved. */ #include "files.h" extern LOCK *Lock(); extern LOCK *ParentDir(), *CurrentDir(); extern void *malloc(); extern void addentry(); RECORD *Rbase; /* All entries */ RECORD *DisplayTop; /* Entry at the display top */ RECORD *Highlighted; /* Highlighted entry */ short MaxNameLen; long NumEntries; long NumSelected; long NumTop; long NewNumTop; FIB *Fib; short Modified; short Xs, Xe, Ys, Ye, Rows, Cols; char Title[80]; redisplay(newtop) { short i; short noscroll = 0; uword percent, fill; RECORD *rec; bigboxbounds(&Xs,&Xe,&Ys,&Ye); Rows = (Ye-Ys)/Rp->TxHeight; Cols = (Xe-Xs)/Rp->TxWidth; if (newtop) { long delta = NumTop - NewNumTop; if (delta < 0) delta = -delta; if (delta >= Rows) noscroll = 1; } while (DisplayTop && !(DisplayTop->flags & R_SELECTED)) DisplayTop = DisplayTop->next; if (newtop) { while (NewNumTop != NumTop && DisplayTop) { if (NewNumTop < NumTop) { do { DisplayTop = DisplayTop->prev; } while (DisplayTop && !(DisplayTop->flags & R_SELECTED)); --NumTop; if (DisplayTop && !noscroll) { ScrollRaster(Rp, 0, -Rp->TxHeight, Xs, Ys, Xe-1, Ye-1); displayat(DisplayTop, 0); } } else { do { DisplayTop = DisplayTop->next; } while (DisplayTop && !(DisplayTop->flags & R_SELECTED)); ++NumTop; if (DisplayTop && !noscroll) { ScrollRaster(Rp, 0, Rp->TxHeight, Xs, Ys, Xe-1, Ye-1); displayrow(Rows-1); } } } if (DisplayTop && !noscroll) return(0); } sprintf(Title, "%ld/%ld", NumSelected, NumEntries); title(Title); if (DisplayTop == NULL) { DisplayTop = Rbase; NumTop = 0; } if (!newtop) { percent = fill = 0xFFFF; if (NumSelected) { if (NumTop+(Rows>>1) > NumSelected) percent = 0xFFFF; else percent = (NumTop + (Rows>>1)) * 0xFFFF / NumSelected; fill = Rows * 0xFFFF / NumSelected; if (Rows > NumSelected) fill = 0xFFFF; } setslider(percent, fill); } SetAPen(Rp, 0); RectFill(Rp, Xs, Ys, Xe-1, Ye-1); SetAPen(Rp, 1); for (rec = DisplayTop, i = 0; rec && i < Rows; rec = rec->next) { if (!(rec->flags & R_SELECTED)) continue; displayat(rec, i); ++i; } } redisplayone(rec) RECORD *rec; { RECORD *nrec; short i; for (i = 0, nrec = DisplayTop; nrec && i < Rows; nrec = nrec->next) { if (!(nrec->flags & R_SELECTED)) continue; if (nrec == rec) break; ++i; } if (i < Rows && nrec == rec) { SetAPen(Rp, 0); RectFill(Rp, Xs, Ys + (Rp->TxHeight*i), Xe-1, Ys + (Rp->TxHeight*i) + Rp->TxHeight - 1); SetAPen(Rp, 1); displayat(rec, i); } } displayrow(row) { register RECORD *rec = DisplayTop; register short i = row; while (i && rec) { rec = rec->next; while (rec && !(rec->flags & R_SELECTED)) rec = rec->next; --i; } if (rec && row < Rows) displayat(rec, row); } displayat(rec, i) RECORD *rec; { short len; len = strlen(rec->name); if (len > Cols) len = Cols; if (rec == Highlighted) { SetAPen(Rp, 0); SetBPen(Rp, 1); } Move(Rp, Xs, Ys + (Rp->TxHeight*i) + Rp->TxBaseline); Text(Rp, rec->name, len); if (Cols > MaxNameLen && rec->comment) { len = strlen(rec->comment); if (len > Cols - MaxNameLen) len = Cols - MaxNameLen; Move(Rp, Xs + MaxNameLen * Rp->TxWidth, Ys + (Rp->TxHeight * i) + Rp->TxBaseline); Text(Rp, rec->comment, len); } if (rec == Highlighted) { SetAPen(Rp, 1); SetBPen(Rp, 0); } } bigboxhit(y, up) { RECORD *hl = Highlighted; short row; Highlighted = NULL; if (hl) redisplayone(hl); row = (y - Ys) / Rp->TxHeight; if (row >= Rows || Rows < 0) return(0); for (hl = DisplayTop; hl && !(hl->flags & R_SELECTED); hl = hl->next); while (hl && row) { if (hl->flags & R_SELECTED) --row; hl = hl->next; } for (; hl && !(hl->flags & R_SELECTED); hl = hl->next); if (Highlighted = hl) { redisplayone(hl); setcomment((hl->comment) ? hl->comment : ""); if (up) activate_com(); } } sliderhit() { uword pos, fill; getsliderpos(&pos, &fill); NewNumTop = pos * (NumSelected - Rows + 1) / 0xFFFF; redisplay(1); } /* * Add a disk volume to the list. Determine * the root and add entries beginning at the * specification. */ void add_volume(str) char *str; { LOCK *lock; char path[128]; int len; Highlighted = NULL; Fib = malloc(sizeof(FIB)); if (Fib == NULL) return; resetsort(); /* also cleans up the database */ path[0] = 0; if (lock = Lock(str, ACCESS_READ)) { if (Examine(lock, Fib)) { buildpath(lock, path); len = strlen(path); if (path[len-1] == ':' || path[len-1] == '/') { path[len] = '*'; path[len+1] = 0; select_pattern(path, 1); path[len] = 0; } Examine(lock, Fib); if (Fib->fib_DirEntryType < 0) { addentry(path, Fib->fib_Comment, Fib->fib_Size); } else { RECORD *base; /* find start of killpatterns, if any */ for (base = Rbase; base; base = base->next) { if (strcmp(base->name, KILLNAME) < 0) continue; break; } title("Wait.. Scanning"); scandir(lock, path, base); } title("Wait.. Update"); rem_selected(NULL, 1); } UnLock(lock); } free(Fib); strcat(path, "*"); title("Select path"); select_pattern(path, 0); } buildpath(lock, path) LOCK *lock; char *path; { LOCK *parent; short plen, nlen; plen = strlen(path); nlen = strlen(Fib->fib_FileName) + 1; if (nlen == 1) { /* RAM: */ strcpy(Fib->fib_FileName, "ram"); nlen = 4; } bmov(path, path + nlen, plen + 1); strcpy(path, Fib->fib_FileName); if (Fib->fib_DirEntryType >= 0) path[nlen-1] = '/'; if (parent = ParentDir(lock)) { if (Examine(parent, Fib)) { buildpath(parent, path); } UnLock(parent); } else { path[nlen-1] = ':'; } } scandir(lock, path, base) LOCK *lock; char *path; RECORD *base; { short restorelen = strlen(path); short len = restorelen; LOCK *olddirlock; if (path[restorelen-1] != ':' && path[restorelen-1] != '/') { strcpy(path + restorelen, "/"); ++len; } olddirlock = CurrentDir(lock); if (notkilled(path, base)) addentry(path, Fib->fib_Comment, Fib->fib_Size); while (ExNext(lock, Fib)) { strcpy(path+len, Fib->fib_FileName); if (Fib->fib_DirEntryType < 0) { if (notkilled(path, base)) addentry(path, Fib->fib_Comment, Fib->fib_Size); } else { LOCK *lock = Lock(Fib->fib_FileName, ACCESS_READ); if (lock) { FIB *oldfib = Fib; if (Fib = malloc(sizeof(FIB))) { Examine(lock, Fib); scandir(lock, path, base); UnLock(lock); free(Fib); } Fib = oldfib; } } } CurrentDir(olddirlock); path[restorelen] = 0; } notkilled(path,base) char *path; RECORD *base; { while (base && strcmp(base->name, KILLNAME) == 0) { if (base->comment && newwildcmp(base->comment, path)) return(0); base = base->next; } return(1); } load_database(fi) FILE *fi; { char name[132]; char comm[132]; char size[32]; fgets(name, 128, fi); /* # entries per item */ Highlighted = NULL; resetsort(); title("Wait... Loading"); while (fgets(name, 128, fi) && fgets(comm, 128, fi) && fgets(size, 32, fi)) { name[strlen(name)-1] = 0; /* remove newlines */ comm[strlen(comm)-1] = 0; addentry(name, comm, atoi(size)); } rem_selected(NULL, 1); selectall(); redisplay(0); } save_database(fi) FILE *fi; { RECORD *rec; char buf[32]; cleanup(); title("Saving..."); fputs("3\n", fi); for (rec = Rbase; rec; rec = rec->next) { fwrite(rec->name, strlen(rec->name), 1, fi); putc('\n', fi); if (rec->comment) fwrite(rec->comment, strlen(rec->comment), 1, fi); putc('\n', fi); sprintf(buf, "%ld\n", rec->bytes); fputs(buf, fi); if (ferror(fi)) break; } } selectall() { RECORD *rec; short len; Highlighted = NULL; DisplayTop = NULL; MaxNameLen = 0; for (rec = Rbase; rec; rec = rec->next) { if (rec->flags & R_KILLPAT) continue; len = strlen(rec->name); if (MaxNameLen <= len) MaxNameLen = len + 1; rec->flags |= R_SELECTED; } NumSelected = NumEntries; } select_pattern(str, noref) char *str; { register RECORD *rec; register short len; short which = 0; if (*str == '+') /* ADD selected patterns */ ++str, which = 1; if (*str == '-') /* REMOVE selected patterns*/ ++str, which = 2; DisplayTop = NULL; Highlighted= NULL; switch(which) { case 0: NumSelected = 0; MaxNameLen = 0; for (rec = Rbase; rec; rec = rec->next) { rec->flags &= ~R_SELECTED; if (rec->flags & R_KILLPAT) continue; if (newwildcmp(str, rec->name) || (rec->comment && newwildcmp(str, rec->comment))) { if (noref) { rec->flags |= R_UPDATE; } else { rec->flags |= R_SELECTED; ++NumSelected; if ((len = strlen(rec->name)) >= MaxNameLen) MaxNameLen = len + 1; } } } break; case 1: for (rec = Rbase; rec; rec = rec->next) { if ((rec->flags & R_KILLPAT) || (rec->flags & R_SELECTED)) continue; if (newwildcmp(str, rec->name) || (rec->comment && newwildcmp(str, rec->comment))) { rec->flags |= R_SELECTED; ++NumSelected; if ((len = strlen(rec->name)) >= MaxNameLen) MaxNameLen = len + 1; } } break; case 2: for (rec = Rbase; rec; rec = rec->next) { if (!(rec->flags & R_SELECTED)) continue; if (newwildcmp(str, rec->name) || (rec->comment && newwildcmp(str, rec->comment))) { rec->flags &= ~R_SELECTED; --NumSelected; } } break; } if (!noref) redisplay(0); } /* * If onerec != NULL, remove the one record, * else remove all SELECTED records. */ rem_selected(onerec, noref) RECORD *onerec; { register RECORD *rec; register long len, maxlen; Highlighted = NULL; cleanup(); if (onerec) { if (onerec->flags & R_SELECTED) { onerec->flags &= ~R_SELECTED; --NumSelected; } onerec->flags |= R_KILLPAT; --NumEntries; } else { maxlen = 0; for (rec = Rbase; rec; rec = rec->next) { if (noref) { if (rec->flags & R_UPDATE) { rec->flags &= ~R_UPDATE; rec->flags |= R_KILLPAT; --NumEntries; } } else { if (rec->flags & R_SELECTED) { rec->flags &= ~R_SELECTED; rec->flags |= R_KILLPAT; --NumEntries; } } if (!(rec->flags & R_KILLPAT) && (len=strlen(rec->name)) > maxlen) maxlen = len; } if (!noref) NumSelected = 0; MaxNameLen = maxlen+1; } if (noref) cleanup(); else redisplay(0); } undo() { RECORD *rec; Highlighted = NULL; for (rec = Rbase; rec; rec = rec->next) { if (rec->flags & R_KILLPAT) { rec->flags &= ~R_KILLPAT; rec->flags |= R_SELECTED; ++NumSelected; ++NumEntries; if (strlen(rec->name) >= MaxNameLen) MaxNameLen = strlen(rec->name)+1; } } redisplay(0); } cleanup() { RECORD *rec, *nrec; for (rec = Rbase; rec; rec = nrec) { nrec = rec->next; if (rec->flags & R_KILLPAT) { if (rec == DisplayTop) DisplayTop = nrec; rmrecord(rec); } } } rmrecord(rec) RECORD *rec; { if (rec->flags & R_SOFTERR) { puts("panic: soft error"); exit(1); } if (rec->prev) rec->prev->next = rec->next; else Rbase = rec->next; if (rec->next) rec->next->prev = rec->prev; rec->flags |= R_SOFTERR; freestr(rec->name); freestr(rec->comment); freerecord(rec); } /* * modify the comment field for the highlighted * item. */ mod_comment(str) char *str; { if (Highlighted) { Modified = 1; freestr(Highlighted->comment); if (str[0]) { Highlighted->comment = allocstr(str); if (Highlighted->comment == NULL) title("OUT OF MEMORY!"); } else { Highlighted->comment = NULL; } redisplayone(Highlighted); } } static RECORD *Cache; resetsort() { cleanup(); Cache = Rbase; } void addentry(name, comm, size) char *name; char *comm; long size; { RECORD *rec; short n; Modified = 1; rec = allocrecord(); if (rec == NULL) { title("OUT OF MEMORY!"); return; } rec->name = allocstr(name); if (rec->name == NULL) { rmrecord(rec); title("OUT OF MEMORY!"); return; } rec->comment = NULL; if (strlen(comm)) { rec->comment = allocstr(comm); if (rec->comment == NULL) { freestr(rec->name); rmrecord(rec); title("OUT OF MEMORY!"); return; } } rec->bytes = size; if (Rbase == NULL) { Rbase = rec; rec->prev = NULL; rec->next = NULL; } else { short n = strcmp(name, Cache->name); if (n == 0 && strcmp(name, KILLNAME) == 0) n = 1; if (n < 0) { /* name < Cache, move backwards */ while ((Cache = Cache->prev) && (n=strcmp(name, Cache->name)) < 0); } else if (n > 0) { /* name > Cache, move forwards */ while (Cache->next && (n=strcmp(name, Cache->next->name)) > 0) Cache = Cache->next; if (Cache->next && n == 0) Cache = Cache->next; } if (Cache) { rec->next = Cache->next; /* insert after cache */ rec->prev = Cache; Cache->next = rec; } else { /* or at beginning */ rec->next = Rbase; rec->prev = NULL; Rbase = rec; } if (rec->next) rec->next->prev = rec; if (n == 0) { /* replace if exact */ if (Cache->comment) { char *swap = Cache->comment; Cache->comment = rec->comment; rec->comment = swap; Cache->flags |= R_UPDATE; } } } rec->flags = R_SELECTED; ++NumSelected; ++NumEntries; if (MaxNameLen <= strlen(rec->name)) MaxNameLen = strlen(rec->name) + 1; Cache = rec; }