Skip site navigation (1)Skip section navigation (2)
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>