Date: Fri, 6 Jul 2012 18:24:04 GMT From: Brooks Davis <brooks@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 213989 for review Message-ID: <201207061824.q66IO4c9073215@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@213989?ac=10 Change 213989 by brooks@brooks_ecr_current on 2012/07/06 18:23:32 Checkpoint with text based file browser support and basic rendering including file names and placeholders for icons. Affected files ... .. //depot/projects/ctsrd/beribsd/src/ctsrd/browser/browser.c#2 edit Differences ... ==== //depot/projects/ctsrd/beribsd/src/ctsrd/browser/browser.c#2 (text+ko) ==== @@ -31,13 +31,17 @@ #include <sys/types.h> #include <sys/param.h> +#include <sys/stat.h> #include <sys/wait.h> +#include <ctype.h> #include <de4tc.h> +#include <dirent.h> #include <err.h> #include <errno.h> #include <fcntl.h> #include <libutil.h> +#include <magic.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -47,11 +51,42 @@ #define BASEIMG "/usr/share/images/browser.png" -#define black fb_colour(0, 0, 0) -#define white fb_colour(0xff, 0xff, 0xff); -#define red fb_colour(0xff, 0, 0) -#define green fb_colour(0, 0xff, 0) -#define blue fb_colour(0, 0, 0xff) +#define vwhite(v) fb_colour((v), (v), (v)) +#define vred(v) fb_colour((v), 0, 0) +#define vgreen(v) fb_colour(0, (v), 0) +#define vblue(v) fb_colour(0, 0, (v)) +#define black vwhite(0) +#define white vwhite(0xFF) +#define red vred(0xFF) +#define green vgreen(0xFF) +#define blue vblue(0xFF) + +/* + * Each file is displayed in a 266x40 box: + * +--------------------------------------------------------------------------+ + * | 4 pixel border | + * |4 +------+ 4+----------------------------------------------------------+ | + * |p |32x32 | p| Text in 16x32 characters | | + * |x |icon | x| | | + * | +------+ +----------------------------------------------------------+ | + * | 4 pixel border | + * +--------------------------------------------------------------------------+ + * |----------------------------------(800/3 = 266) pixels--------------------| + */ +#define FROW 41 +#define NCOL 3 +#define NROW 10 +#define NSLOTS (NCOL * NROW) +#define CWIDTH 266 +#define RHEIGHT 40 +#define ICON_WH 32 +#define BORDER 4 +#define CHAR_HEIGHT 32 +#define CHAR_WIDTH 16 +#define TEXT_OFFSET (BORDER + ICON_WH + BORDER) +#define _TEXTSPACE (CWIDTH - (TEXT_OFFSET + BORDER)) +#define TEXTSPACE (_TEXTSPACE - _TEXTSPACE % CHAR_WIDTH) + /* Beginning and ending colums of each sandbox type's name */ #define SB_IMG_SPACING 20 @@ -66,6 +101,9 @@ #define SB_MINROW (fb_height - 39) #define SB_MAXROW (fb_height - 1) +/* Start offsets for browser columns */ +const int colstart[] = {0, 267, 534}; + enum _sbtype { SB_NONE = 1, SB_CAPSICUM, @@ -83,20 +121,55 @@ { 0, 0, 0 } }; -static u_int32_t *image; +static u_int32_t *bgimage; +static magic_t magic; static void usage(void) { - printf("usage: browser\n"); + printf("usage: browser <dir> <tty>\n"); + printf(" browser -T <dir>\n"); exit(1); } static void +init_tty(char *tty_name) { + int tty; + char *devpath; + + if (tty_name[0] != '/') + asprintf(&devpath, "/dev/%s", tty_name); + else + devpath = tty_name; + if ((tty = open(devpath, O_RDWR)) < 0) { + syslog(LOG_ALERT, "open failed with %s", strerror(errno)); + err(1, "open(%s)", devpath); + } + if (login_tty(tty) < 0) { + syslog(LOG_ALERT, "login_tty failed: %s", strerror(errno)); + err(1, "login_tty()"); + } + if (devpath != tty_name) + free(devpath); +} + +static void +init_magic(void) { + magic = magic_open(MAGIC_MIME_TYPE); + if (magic == NULL) + errx(1, "magic_open()"); + if (magic_load(magic, NULL) == -1) { + warnx("magic_load() %s", magic_error(magic)); + magic_close(magic); + exit(1); + } +} + +static void update_sandbox(enum _sbtype type) { - int bcol, ecol, i, j, pixel; + int bcol, ecol, i, j, pixel, value; sbtype = type; @@ -110,65 +183,282 @@ for (j = SB_MINROW; j < SB_MAXROW; j++) { for (i = SB_MINCOL; i <= SB_MAXCOL; i++) { pixel = (j * fb_width) + i; - /* XXX: messes up anti-aliasing */ - if (image[pixel] != black) - image[pixel] = (i >= bcol && i <= ecol) ? - blue : white; + if (bgimage[pixel] != black) { + /* XXX: Assuming we're either blue or white */ + value = (bgimage[pixel] >> 8) & 0xFF; + if (value == 0) { + printf("unexpected zero value, pixel %08x\n", + bgimage[pixel]); + value = 0xff; + } + bgimage[pixel] = (i >= bcol && i <= ecol) ? + vblue(value) : vwhite(value); + } + } + } + fb_post(bgimage); +} + +static const char * +get_desc(int dfd, struct dirent *entry) +{ + int fd, type; + const char *desc; + struct stat sbuf; + + if (entry->d_type == DT_LNK) { + if (fstatat(dfd, entry->d_name, &sbuf, 0) == -1) + type = DT_UNKNOWN; + else + type = IFTODT(sbuf.st_mode); + } else + type = entry->d_type; + + switch (type) { + case DT_UNKNOWN: + desc = "unknown"; + break; + case DT_REG: + if ((fd = openat(dfd, entry->d_name, O_RDONLY)) == -1) + desc = "unknown"; + else { + desc = magic_descriptor(magic, fd); + close(fd); } + break; + case DT_FIFO: + desc = "special/fifo"; + break; + case DT_CHR: + desc = "special/character"; + break; + case DT_DIR: + desc = "directory"; + break; + case DT_BLK: + desc = "special/block"; + break; + case DT_SOCK: + desc = "special/socket"; + break; + case DT_WHT: + desc = "special/whiteout"; + break; + default: + err(1, "Unhandled type %d", type); } - fb_post(image); + + return (desc); } -static void -event_loop(void) +static int +browsedir(int dfd) { - for(;;) { - sleep(1); + int f, i, j, s, nlines; + long curloc, nextloc; + DIR *dirp; + struct dirent *entry, *entry2; + u_int32_t iconbuf[ICON_WH*ICON_WH], textbuf[TEXTSPACE*CHAR_HEIGHT]; + char line[256]; + + if ((dirp = fdopendir(dfd)) == NULL) + err(1, "fdopendir()"); + + for (i = 0; i < 32*32; i++) + iconbuf[i] = blue; + + fb_fill_region(black, colstart[0], FROW, + colstart[NCOL-1] - colstart[0], NROW * RHEIGHT); + + nlines = NSLOTS - 1; + curloc = telldir(dirp); + nextloc = 0; + i = 0; +start: + seekdir(dirp, curloc); + /* telldir() return values are only good once so make a new copy! */ + curloc = telldir(dirp); + s = 0; + if (i > 0) { + printf("p %20s\n", "previous page"); + memset(textbuf, 0, sizeof(textbuf)); + fb_render_text("previous page", 2, white, black, textbuf, + TEXTSPACE, CHAR_HEIGHT); + fb_post_region(textbuf, colstart[(s/NROW)] + TEXT_OFFSET, + FROW + (RHEIGHT * (s % NROW)) + BORDER, TEXTSPACE, + CHAR_HEIGHT); + fb_post_region(iconbuf, colstart[(s/NROW)] + BORDER, + FROW + (RHEIGHT * (s % NROW)) + BORDER, ICON_WH, ICON_WH); + s = 1; + } + entry = NULL; /* XXX: gcc warning */ + while(s < NSLOTS - 1 && (entry = readdir(dirp)) != NULL) { + printf("%2d %20s %s\n", s, entry->d_name, get_desc(dfd, entry)); + memset(textbuf, 0, sizeof(textbuf)); + fb_render_text(entry->d_name, 2, white, black, textbuf, + TEXTSPACE, CHAR_HEIGHT); + fb_post_region(textbuf, colstart[(s/NROW)]+TEXT_OFFSET, + FROW + (RHEIGHT * (s % NROW)) + BORDER, TEXTSPACE, CHAR_HEIGHT); + fb_post_region(iconbuf, colstart[(s/NROW)] + BORDER, + FROW + (RHEIGHT * (s % NROW)) + BORDER, ICON_WH, ICON_WH); + s++; + } + + nextloc = telldir(dirp); + if (s == NSLOTS - 1 && entry != NULL) { + /* + * If there are at least two more files then we don't want to + * display a "next" button and instead want either nothing or + * the final entry. + */ + entry = readdir(dirp); + if (entry == NULL) + nextloc = 0; + else { + entry2 = readdir(dirp); + if (entry2 == NULL) { + printf("%2d %20s %s\n", s, + entry->d_name, + get_desc(dfd, entry)); + memset(textbuf, 0, sizeof(textbuf)); + fb_render_text(entry->d_name, 2, white, black, + textbuf, TEXTSPACE, CHAR_HEIGHT); + fb_post_region(textbuf, + colstart[(s/NROW)]+TEXT_OFFSET, + FROW + (RHEIGHT * (s % NROW)) + BORDER, + TEXTSPACE, CHAR_HEIGHT); + fb_post_region(iconbuf, + colstart[(s/NROW)] + BORDER, + FROW + (RHEIGHT * (s % NROW)) + BORDER, + ICON_WH, ICON_WH); + s++; + } else { + printf("n %20s\n", "next page"); + memset(textbuf, 0, sizeof(textbuf)); + fb_render_text("next page", 2, white, black, + textbuf, TEXTSPACE, CHAR_HEIGHT); + fb_post_region(textbuf, + colstart[(s/NROW)]+TEXT_OFFSET, + FROW + (RHEIGHT * (s % NROW)) + BORDER, + TEXTSPACE, CHAR_HEIGHT); + fb_post_region(iconbuf, + colstart[(s/NROW)] + BORDER, + FROW + (RHEIGHT * (s % NROW)) + BORDER, + ICON_WH, ICON_WH); + } + } + } + +prompt: + printf("select a file or directory by number :\n"); + if (fgets(line, sizeof(line), stdin) == NULL) { + if (feof(stdin)) + return (-1); + else + errx(1, "fgets(): %s", strerror(ferror(stdin))); + } + printf("line '%s'\n", line); + f = 0; /* XXX: gcc warning*/ + switch (line[0]) { + case '\n': + case 'n': + /* This leaks an internal struct associted with curloc/ */ + if (nextloc != 0) { + i += s; + curloc = nextloc; + } + goto start; + case 'p': + i -= s; + // XXX previous page + break; + case 'q': + return(-1); + default: + if (!isnumber(line[0])) { + printf("invalid file %s\n", line); + goto prompt; + } + f = atoi(line); + if (f < 0 || f >= nlines) { + printf("invalid file %s\n", line); + goto prompt; + } + } + + /* Take action on the specified file */ + seekdir(dirp, curloc); + curloc = telldir(dirp); + j = 0; + while((entry = readdir(dirp)) != NULL) { + printf("%s\n", entry->d_name); + if (j++ != f) + continue; + if (entry->d_type == DT_DIR) { + if ((dfd = openat(dfd, entry->d_name, + O_RDONLY|O_DIRECTORY)) == -1) + err(1, "open(%s)", entry->d_name); + if (closedir(dirp) == -1) + err(1, "closedir()"); + return (dfd); + } else { + printf ("opening non-directory not supported\n"); + goto start; + } } + + if (closedir(dirp) == -1) + err(1, "closedir()"); + + return (-1); } int main(int argc, char *argv[]) { - int tty; - char *devpath; + int ch, dfd; + int ttyflag = 1; - syslog(LOG_ALERT, "starting up"); - if (argc != 2) - usage(); - - if (argv[1][0] != '/') - asprintf(&devpath, "/dev/%s", argv[1]); - else - devpath = argv[1]; - if ((tty = open(devpath, O_RDWR)) < 0) { - syslog(LOG_ALERT, "open failed with %s", strerror(errno)); - err(1, "open(%s)", devpath); + while ((ch = getopt(argc, argv, "T")) != -1) { + switch (ch) { + case 'T': + ttyflag = 0; + break; + default: + usage(); + } } + argc -= optind; + argv += optind; - if (login_tty(tty) < 0) { - syslog(LOG_ALERT, "login_tty failed: %s", strerror(errno)); - err(1, "login_tty()"); - } - syslog(LOG_ALERT, "tty set up"); + if (argc <= 0 && argc > 2) + usage(); + if (argc == 2) + init_tty(argv[1]); + init_magic(); fb_init(); + fb_load_syscons_font(NULL, "/usr/share/syscons/fonts/iso-8x16.fnt"); - image = malloc(sizeof(u_int32_t) * fb_height * fb_width); - if (image == NULL) + bgimage = malloc(sizeof(u_int32_t) * fb_height * fb_width); + if (bgimage == NULL) err(1, "malloc"); - read_png_file(BASEIMG, image, fb_width, fb_height); + read_png_file(BASEIMG, bgimage, fb_width, fb_height); syslog(LOG_ALERT, "tty set up"); - fb_post(image); + fb_post(bgimage); //fb_fade2on(); fb_fade2text(127); fb_text_cursor(255, 255); update_sandbox(SB_NONE); - event_loop(); + if ((dfd = open(argv[0], O_RDONLY|O_DIRECTORY)) == -1) + err(1, "open(%s)", argv[1]); + + while (dfd != -1) + dfd = browsedir(dfd); return (0); }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201207061824.q66IO4c9073215>