/*
* console.c - user interface I/O routines
*
* Copyright (C) 1998-2003 Gero Kuhlmann <gero@gkminix.han.de>
*
* 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 <common.h>
#include <nblib.h>
#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 <ENTER> 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);
}
syntax highlighted by Code2HTML, v. 0.9.1