/* * console.c - user interface I/O routines * * Copyright (C) 1998-2003 Gero Kuhlmann * * This program 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 2 of the License, or * any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: console.c,v 1.4 2003/01/25 23:29:42 gkminix Exp $ */ #define NEED_DIR 1 #include #include #include "console.h" /* * Variables local to this module */ static int curline = 0; /* current screen line */ /* * Directory entry name list */ struct direntry { struct direntry *next; char *fname; }; /* * Compare a description table entry for qsort routine */ static int descmp(entry1, entry2) const voidstar entry1; const voidstar entry2; { struct direntry *dp1 = *((struct direntry **)entry1); struct direntry *dp2 = *((struct direntry **)entry2); assert(dp1 != NULL && dp2 != NULL); if (dp1->fname == NULL && dp2->fname != NULL) return(-1); else if (dp1->fname != NULL && dp2->fname == NULL) return(1); else if (dp1->fname == NULL && dp2->fname == NULL) return(0); return(strcmp(dp1->fname, dp2->fname)); } /* * Compare a directory entry name against one pattern. */ static int singledircmp(name, pat) char *name; char *pat; { while (*pat && *name) { if (*pat == '*') { pat++; if (!*pat) return(TRUE); while (*name && !singledircmp(name, pat)) name++; return(*name); } else if (*pat == '?' || *pat == *name) { pat++; name++; } else break; } return(!*pat && !*name); } /* * Compare a directory entry name against a list of patterns. */ static int dircmp(name, pattern) char *name; char *pattern; { char *cp1, *cp2; char *pat = NULL; if (pattern == NULL) return(TRUE); copystr(&pat, pattern); cp1 = pat; while (cp1 != NULL) { if ((cp2 = strchr(cp1, ':')) != NULL) *(cp2++) = '\0'; if (*cp1 && singledircmp(name, cp1)) { free(pat); return(TRUE); } cp1 = cp2; } free(pat); return(FALSE); } /* * Get a list of directory entries with name patterns. */ static struct direntry **getdirlist(dirname, pattern) char *dirname; char *pattern; { DIR *dir; struct dirent *ent; struct direntry *dp; struct direntry **dirlist = NULL; struct direntry *firstdir = NULL; int count, i; /* Open the directory */ if ((dir = opendir(dirname)) == NULL) return(NULL); /* Step through all directory entries */ count = 0; while ((ent = readdir(dir)) != NULL) { if (dircmp(ent->d_name, pattern)) { dp = (struct direntry *)nbmalloc(sizeof(struct direntry)); copystr(&(dp->fname), ent->d_name); dp->next = firstdir; firstdir = dp; count++; } } closedir(dir); /* Generate sorted array of directory entries */ if (count > 0) { dirlist = (struct direntry **)nbmalloc((count + 1) * sizeof(struct direntry *)); i = 0; dp = firstdir; while (dp != NULL && i < count) { dirlist[i] = dp; dp = dp->next; dirlist[i]->next = NULL; i++; } assert(i == count); dirlist[i] = NULL; qsort(dirlist, count, sizeof(struct direntry *), &descmp); } return(dirlist); } /* * Delete directory list */ static void deldirlist(dirlist) struct direntry **dirlist; { struct direntry **dpp; if (dirlist == NULL) return; dpp = dirlist; while (*dpp != NULL) { free((*dpp)->fname); free(*dpp); dpp++; } free(dirlist); } /* * Print a new line, and increase the number of displayed lines */ static void printnl() { putchar('\n'); curline++; if (curline > LISTLINES) { printf("\nPress to continue listing "); (void)getstring(NULL); putchar('\n'); curline = 0; } } /* * Print list of directory entries matching a pattern */ static void printdir(dirname, pattern) char *dirname; char *pattern; { struct direntry **dirlist; char *dirbuf = NULL; char *cp1, *cp2, *cp3; int i, j, k; /* Generate local copy of directory name list */ copystr(&dirbuf, dirname); cp1 = dirbuf; while (cp1 != NULL) { /* Find end of subdirectory name */ if ((cp2 = strchr(cp1, ':')) != NULL) *(cp2++) = '\0'; /* Get list of files in directory */ if ((dirlist = getdirlist(cp1, pattern)) == NULL) { cp1 = cp2; continue; } /* Print listing header */ printf("Contents of %s:", cp1); printnl(); /* Print all files in directory */ i = 0; while (dirlist[i] != NULL) { printf(" "); for (j = 0; j < 3 && dirlist[i] != NULL; i++, j++) { cp3 = dirlist[i]->fname; for (k = 0; k < 20 && *cp3; k++, cp3++) putchar(*cp3); for ( ; k < 24; k++) putchar(' '); } printnl(); } /* Prepare for next directory */ deldirlist(dirlist); if ((cp1 = cp2) != NULL) { printnl(); printnl(); } } free(dirbuf); } /* * Get a string response from the user */ char *getstring(prompt) char *prompt; { static char buf[1024]; char *cp; if (prompt != NULL) printf("%s: ", prompt); fflush(stdout); fgets(buf, sizeof(buf) - 1, stdin); for (cp = buf; *cp && *cp != '\n'; cp++) ; *cp = '\0'; return(buf); } /* * Get a numeric response from the user */ long getnum(prompt, min, max, hex) char *prompt; long min; long max; int hex; { char *cp; long j; int i, indent = 0; if (prompt != NULL) indent = strspn(prompt, " "); while (TRUE) { if (prompt != NULL) printf("%s (%s): ", prompt, hex ? "hex" : "decimal"); cp = getstring(NULL); if (*cp) { if ((hex ? sscanf(cp, "%lx", &j) : sscanf(cp, "%ld", &j)) != 1) j = min - 1; if (j < min || j > max) { for (i = 0; i < indent; i++) putchar(' '); if (hex) printf(" Allowed values are [%lX..%lX]\n", min, max); else printf(" Allowed values are [%ld..%ld]\n", min, max); } else break; } } return(j); } /* * Get a list selection from the user */ int getsel(prompt, minsel, maxsel, defsel) char *prompt; int minsel; int maxsel; int defsel; { char *cp; int sel = minsel - 1; int i; while (TRUE) { if (defsel >= minsel && defsel <= maxsel) { i = 1; if (prompt != NULL) printf("%s [%d]: ", prompt, defsel); cp = getstring(NULL); if (!*cp) sel = defsel; else i = sscanf(cp, "%d", &sel); } else { i = 0; if (prompt != NULL) printf("%s: ", prompt); cp = getstring(NULL); if (*cp) i = sscanf(cp, "%d", &sel); } if (i == 1 && sel >= minsel && sel <= maxsel) break; } return(sel); } /* * Get a yes/no response from the user */ int getyn(prompt, def) char *prompt; int def; { char *cp; while (TRUE) { if (prompt != NULL) printf("%s (y/n) [%s] ? ", prompt, def ? "yes" : "no" ); cp = getstring(NULL); if (!*cp) return(def); else if (toupper(*cp) == 'Y') return(TRUE); else if (toupper(*cp) == 'N') return(FALSE); } } /* * Ask user about a file name */ char *getfilename(prompt, searchdir, pattern) char *prompt; char *searchdir; char *pattern; { char *filename, *cp, *dir; filename = NULL; while (filename == NULL) { if (prompt != NULL) { printf(prompt); dir = getstring(" ('*' for directory listing)"); } else { dir = getstring(NULL); } dir += strspn(dir, " \t"); cp = dir + strcspn(dir, " \t:"); *cp = '\0'; if ((cp = strchr(dir, '*')) != NULL) { if ((cp > dir && cp[-1] != '/') || cp[1] != '\0') printf("Invalid directory specification\n"); else if (dir == cp) printdir(searchdir, pattern); else { cp[-1] = '\0'; if (!*dir) printdir("/", pattern); else printdir(dir, pattern); } } else if (*dir) { copystr(&filename, dir); checkaccess(&filename, searchdir); if (filename == NULL) printf("Unable to find and/or access file %s\n", dir); } } return(filename); }