git.y1.nz

fbui

Framebuffer-based graphical environment
download: https://git.y1.nz/archives/fbui.tar.gz
README | Files | Log | Refs

libfbui/Term/fbterm.c

      1 
      2 #define VERSION "0.1"
      3 #include "fbterm.h"
      4 
      5 /* External functions and variables */
      6 
      7 int HandleEscapeSequences (unsigned char **, size_t *, unsigned char*, size_t*);
      8 void MoveCursor (int, int);
      9 
     10 void fbtermNextPos ();
     11 int FBUIWriteChar (wchar_t);
     12 int FBUIInit_graphicsmode (int,short,short,short,short);
     13 void HandleFBUIEvents (unsigned char *, size_t *);
     14 void FBUIExit (void);
     15 void fbtermBlinkCursor (int);
     16 #ifdef DEBUG
     17 void ShowGrid (void);
     18 #endif /* DEBUG */
     19 
     20 
     21 extern int vis_w, vis_h;
     22 extern int cursor_x, cursor_y, cursor_x0, cursor_y0, cell_w, cell_h;
     23 extern int altcharset_mode;
     24 extern int region_top, region_bottom;
     25 
     26 extern char **environ;
     27 
     28 /* Global variables */
     29 int terminal_width, terminal_height;
     30 int quit = 0;
     31 #ifdef DEBUG
     32 int debuglevel = 0;
     33 #endif /* DEBUG */
     34 wchar_t last_char;
     35 char result[SHELLOUTPUT_SIZE*4+1];
     36 char *tabstops;
     37 
     38 
     39 int (*fbtermWriteChar) (wchar_t charcode);
     40 int (*fbtermGetShellChar) (wchar_t *charcode, unsigned char **inputbuf,
     41 			   size_t *inputsize);
     42 int (*fbtermPutShellChar) (unsigned char *buffer,
     43 			   size_t *index, wchar_t charcode);
     44 
     45 
     46 int
     47 DefaultGetShellChar (wchar_t *charcode, unsigned char **inputbuf,
     48 		    size_t *inputsize)
     49 {
     50 #ifdef MULTIBYTE
     51 	size_t bytes;
     52 	
     53 	if (altcharset_mode)
     54 	{
     55 		/* we bypass the multibyte handling */
     56 		*charcode = (*inputbuf)[0];
     57 		(*inputsize)--;
     58 		(*inputbuf)++;
     59 		return 0;
     60 	}
     61 	bytes = mbtowc (charcode, (char*) *inputbuf, *inputsize);
     62 	switch (bytes)
     63 	{
     64 		case -1:
     65 			/* invalid character encountered */
     66 			debug (DEBUG_INFO,
     67 				       "Invalid byte, skipping it");
     68 			(*inputsize)--;
     69 			(*inputbuf)++;
     70 			return 1;
     71 		case -2:
     72 			/* incomplete input */
     73 			debug (DEBUG_INFO,
     74 			       "Incomplete input");
     75 			return 2;
     76 		default:
     77 			(*inputsize) -= bytes;
     78 			(*inputbuf) += bytes;
     79 			return 0;
     80 	}
     81 #else
     82 	*charcode = (*inputbuf)[0];
     83 	(*inputsize)--;
     84 	(*inputbuf)++;
     85 	return 0;
     86 #endif
     87 }
     88 
     89 int
     90 DefaultPutShellChar (unsigned char *buffer, size_t *index, wchar_t charcode)
     91 {
     92 # ifdef MULTIBYTE
     93 	(*index) += wctomb ((char*) buffer, charcode);
     94 # else
     95 	buffer[*index] = (unsigned char)(charcode & 0xFF);
     96 	(*index)++;
     97 # endif
     98 	return 0;
     99 }
    100 
    101 void
    102 fbtermUsage (void)
    103 {
    104 	fprintf (stderr,
    105 		 "\n"
    106 		 "fbterm v%s by Z. Smith\n"
    107 		 "Based on ggiterm v0.6.2 by A. Reynaud\n"
    108 		 "\n"
    109 		 "Usage: fbterm [OPTIONS...]\n"
    110 		 "Where option is one or more of:\n"
    111 		 "	--help\n", VERSION);
    112 	fprintf (stderr,
    113 		"	--debuglevel n           (%d:none, %d:info, %d:detailed, %d:total, default:%d)\n",
    114 		DEBUG_NONE, DEBUG_INFO, DEBUG_DETAIL, DEBUG_TOTAL, DEBUG_NONE);
    115 	fprintf (stderr,
    116 		"	--font <font file>\n"
    117 		"	--font-size n            (default: %d)\n\n", DEFAULT_FONTSIZE);
    118 }
    119 
    120 void
    121 child_died ()
    122 {
    123 	quit = 2;
    124 }
    125 
    126 
    127 #ifdef DEBUG
    128 char* BinaryToPrintable (unsigned char* buffer, size_t size)
    129 {
    130 	int i, index=0;
    131 	
    132 	for (i=0; i<size; i++)
    133 	{
    134 		if (buffer[i]>=32 && buffer[i]<=126)
    135 		{
    136 			sprintf (result+index, "%c", buffer[i]);
    137 			index++;
    138 		}
    139 		else
    140 		{
    141 			sprintf (result+index, "\\%03o", buffer[i]);
    142 			index += 4;
    143 		}
    144 	}
    145 	result[index] = '\0';
    146 	return result;
    147 }
    148 #endif /* DEBUG */
    149 
    150 void
    151 HandleShellOutput (unsigned char *shelloutput, size_t *shelloutput_size, unsigned char *shellinput, size_t *shellinput_size)
    152 {
    153 	int err;
    154 	size_t buffer_size;
    155 	unsigned char *buffer;
    156 	wchar_t charcode;
    157 
    158 	buffer = shelloutput;
    159 	buffer_size = *shelloutput_size;
    160 	do
    161 	{
    162 		debug (DEBUG_DETAIL, "Parsing shell output: %s", BinaryToPrintable (buffer, buffer_size));
    163 		do
    164 		{
    165 			err = HandleEscapeSequences (&buffer, &buffer_size, shellinput, shellinput_size);
    166 			debug (DEBUG_DETAIL, "HandleEscapeSequences returned %d", err);
    167 		}
    168 		while (!err && buffer_size > 0);
    169 		if (err == 1 && buffer_size > 0)
    170 		{
    171 			err = fbtermGetShellChar (&charcode, &buffer, &buffer_size);
    172 			if (!err)
    173 			{
    174 #ifdef MULTIBYTE
    175 				if (iswprint ((wint_t)charcode))
    176 				{
    177 					debug (DEBUG_DETAIL,
    178 					       "Character code = 0x%08lX (%09ld)\t\"%lc\"",
    179 					       (unsigned long)charcode, (unsigned long)charcode, (wint_t)charcode);
    180 #else
    181 				if (isprint (charcode))
    182 				{
    183 					debug (DEBUG_DETAIL,
    184 					       "Character code = 0x%08lX (%09ld)\t\"%c\"",
    185 					       (unsigned long)charcode, (unsigned long)charcode, (int)charcode);
    186 #endif
    187 				}
    188 				else
    189 				{
    190 					debug (DEBUG_DETAIL,
    191 					       "Character code = 0x%08lX (%09ld)\t\"?\" (unprintable)",
    192 					       (unsigned long)charcode, (unsigned long)charcode);
    193 				}
    194 				fbtermWriteChar (charcode);
    195 				last_char = charcode;
    196 				fbtermNextPos ();
    197 			}
    198 		}
    199 	}
    200 	while (buffer_size > 0 && err != 2);
    201 	// ggiFlush (vis);
    202 	memmove (shelloutput, buffer, buffer_size);
    203 	*shelloutput_size = buffer_size;
    204 }
    205 
    206 
    207 extern int fbui_parse_geom (char *s1, short *w, short *h, short *xr, short *yr);
    208 
    209 int master_fd;
    210 struct winsize ws;
    211 
    212 int
    213 /*main (int argc, char **argv, char **envp)*/
    214 main (int argc, char **argv)
    215 {
    216 	int err, using_ft=0;
    217 	pid_t shell_pid;
    218 	unsigned char shelloutput[SHELLOUTPUT_SIZE];
    219 	size_t shelloutput_size = 0;
    220 	unsigned char shellinput[SHELLINPUT_SIZE];
    221 	size_t shellinput_size = 0;
    222 	char buf[128];
    223 	struct timeval tv;
    224 	fd_set rfds, wfds;
    225 	char *shell = "/bin/sh";
    226 
    227 	int vc = -1;
    228 	short cols = 80; 
    229 	short rows = 33;
    230 	short xrel = 0;
    231 	short yrel = 10;
    232 
    233 	argv++;
    234 	argc--;
    235 	int i=0;
    236 	while (i < argc) {
    237 		if (!strncmp (argv[i], "-c",2)) {
    238 			vc = atoi (argv[i]+2);
    239 		}
    240 		else if (!strncmp (argv[i], "-geo",4)) {
    241 			short n1,n2,n3,n4;
    242 			if (fbui_parse_geom (argv[i]+4,&n1,&n2,&n3,&n4)) {
    243 				cols = n1;
    244 				rows = n2;
    245 				xrel = n3;
    246 				yrel = n4;
    247 			}
    248 		}
    249 		else if (!strcmp (argv[i], "--help")) {
    250 			fbtermUsage ();
    251 			return 0;
    252 		}
    253 		else if (!strcmp (argv[i], "--encoding")) {
    254 			fbtermError ("The --encoding option is obsolete. Codesets are now handled automatically.");
    255 			argc -= 2;
    256 			argv += 2;
    257 			continue;
    258 		}
    259 		else
    260 		if (!strcmp (argv[i], "--debuglevel"))
    261 		{
    262 #ifdef DEBUG
    263 			debuglevel = strtol (argv[1], NULL, 10);
    264 			if (errno == ERANGE)
    265 			{
    266 				perror ("fbterm: strtol");
    267 				return 1;
    268 			}
    269 			argc -= 2;
    270 			argv += 2;
    271 			continue;
    272 #else
    273 			fbtermError ("Debug support not compiled in\n");
    274 			return 1;
    275 #endif /* DEBUG */
    276 		} else {
    277 			fbtermError ("Unknown option %s\n", argv[i]);
    278 			return 1;
    279 		}
    280 		i++;
    281 	}
    282 	
    283 	/* Get current locale */
    284 #ifdef MULTIBYTE
    285 	setlocale (LC_CTYPE, "");
    286 # ifdef HAVE_NL_LANGINFO
    287 	debug (DEBUG_INFO, "Current codeset is %s", nl_langinfo (CODESET));
    288 # else
    289 	debug (DEBUG_INFO, "Current codeset is unknown - nl_langinfo() undefined");
    290 # endif
    291 	debug (DEBUG_INFO, "Maximum character length is %d", MB_CUR_MAX);
    292 #endif /* MULTIBYTE */
    293 
    294 	debug (DEBUG_INFO, "Setting up default handlers:");
    295 	fbtermGetShellChar = &DefaultGetShellChar;
    296 	debug (DEBUG_INFO, "       fbtermGetShellChar -> DefaultGetShellChar");
    297 	fbtermPutShellChar = &DefaultPutShellChar;
    298 	debug (DEBUG_INFO, "       fbtermPutShellChar -> DefaultPutShellChar");
    299 	fbtermWriteChar = &FBUIWriteChar;
    300 	debug (DEBUG_INFO, "       fbtermWriteChar   -> FBUIWriteChar");
    301 	
    302 	err = FBUIInit_graphicsmode (vc,cols,rows,xrel,yrel);
    303 	if (!err)
    304 	{
    305 		debug (DEBUG_INFO, "Using FBUI in graphics mode.");
    306 	}
    307 	else
    308 	{
    309 		fbtermError ("Cannot complete FBUI setup. Aborting.");
    310 		FBUIExit ();
    311 		return 1;
    312 	}
    313 	
    314 	region_top = 0;
    315 	region_bottom = terminal_height;
    316 	MoveCursor (cursor_x0, cursor_y0);
    317 	debug (DEBUG_INFO, "Terminal is %d x %d characters",
    318 	       terminal_width, terminal_height);
    319 	debug (DEBUG_INFO, "Characters are %d x %d pixels", cell_w,
    320 	       cell_h);
    321 	/* Allocate and populate the array for tab stops */
    322 	tabstops = malloc (terminal_width * sizeof(char));
    323 	for (err=0; err<terminal_width; err++)
    324 	{
    325 		tabstops[err] = (err%8 ? 0 : 1);
    326 	}
    327 
    328 	if (getenv ("SHELL") != NULL)
    329 	{
    330 		shell = getenv ("SHELL");
    331 	}
    332 	signal (SIGCHLD, child_died);
    333 
    334 	ws.ws_col = terminal_width;
    335 	ws.ws_row = terminal_height;
    336 	ws.ws_xpixel = vis_w;
    337 	ws.ws_ypixel = vis_h;
    338 
    339 	/* in the following, buf should be set to NULL because of buffer overflow
    340 	 * risk, but is left so for debugging purposes */
    341 	shell_pid = forkpty (&master_fd, buf, NULL, &ws);
    342 	if (shell_pid < 0)
    343 	{
    344 		perror ("fbterm: Couldn't fork. Exiting.\n");
    345 		exit (1);
    346 	}
    347 	if (shell_pid == 0)
    348 	{
    349 		char *argv[] = { shell, NULL };
    350 #ifdef HAVE_PUTENV
    351 		putenv ("TERM=fbterm");
    352 #else
    353 		setenv ("TERM", "fbterm", 1);
    354 #endif /* HAVE_PUTENV */
    355 		debug (DEBUG_DETAIL,
    356 			 "This is the forked process (PID %d, child of PID %d)\n",
    357 			 (int)getpid (), (int)getppid ());
    358 		debug (DEBUG_DETAIL,
    359 			 "Sample UTF-8 output: Caractères français");
    360 		debug (DEBUG_DETAIL,
    361 			 "Sample LATIN1 output: Caractères français");
    362 		debug (DEBUG_DETAIL, "Now exec-ing %s", shell);
    363 		execve (argv[0], argv, environ);
    364 		exit (1);
    365 	}
    366 	debug (DEBUG_INFO, "Child forked (PID %d), pseudo tty is %s",
    367 	       (int)shell_pid, buf);
    368 	debug (DEBUG_INFO, "Waiting for its death...");
    369 
    370 	while (!quit)
    371 	{
    372 		fbtermBlinkCursor (CURSOR_AUTO);
    373 		
    374 		/* do we have pending FBUI events?
    375 		 * (non blocking)
    376 		 */
    377 		HandleFBUIEvents (shellinput, &shellinput_size);
    378 
    379 		tv.tv_sec = 0;
    380 		tv.tv_usec = 20000;
    381 		FD_ZERO (&rfds);
    382 		FD_ZERO (&wfds);
    383 		FD_SET (master_fd, &rfds);
    384 		if (shellinput_size)
    385 			FD_SET (master_fd, &wfds);
    386 
    387 		err = select (master_fd + 1, &rfds, &wfds, NULL, &tv);
    388 		if (err < 0 && errno != EINTR)
    389 		{
    390 			perror ("fbterm: select");
    391 			continue;
    392 		}
    393 		if (quit) break;
    394 		if (err) debug (DEBUG_DETAIL, "%d file descriptors updated", err);
    395 
    396 		if (FD_ISSET (master_fd, &wfds))
    397 		{
    398 			debug (DEBUG_DETAIL, "master_fd is ready for writing");
    399 			/* if we have anything pending, then write it */
    400 			if (shellinput_size)
    401 			{
    402 				do err = write (master_fd, shellinput, shellinput_size);
    403 				while (err < 0 && errno == EINTR && !quit);
    404 				if (err < 0)
    405 				{
    406 					perror ("fbterm: write");
    407 					continue;
    408 				}
    409 				if (quit) break;
    410 				debug (DEBUG_DETAIL,
    411 				       "Written %d bytes out of %d to master_fd", err,
    412 				       (int)shellinput_size);
    413 				memmove (shellinput, shellinput+err, shellinput_size - err);
    414 				shellinput_size -= err;
    415 			}
    416 		}
    417 
    418 		if (FD_ISSET (master_fd, &rfds))
    419 		{
    420 			debug (DEBUG_DETAIL, "master_fd is set\nmain: Reading:");
    421 			debug (DEBUG_DETAIL, "Buffer index is %d", (int)shelloutput_size);
    422 			do err = read (master_fd, shelloutput + shelloutput_size, SHELLOUTPUT_SIZE - shelloutput_size);
    423 			while (err < 0 && errno == EINTR && !quit);
    424 			if (err < 0)
    425 			{
    426 				perror ("fbterm: read");
    427 				continue;
    428 			}
    429 			if (err == 0) quit = 1;
    430 			if (quit) break;
    431 			if (err > 0)
    432 			{
    433 				debug (DEBUG_DETAIL, "Read %d bytes from master_fd", err);
    434 				shelloutput_size += err;
    435 				debug (DEBUG_DETAIL,
    436 				       "Buffer index is now %d",
    437 				       (int)shelloutput_size);
    438 				fbtermBlinkCursor (CURSOR_HIDE);
    439 				HandleShellOutput (shelloutput, &shelloutput_size, shellinput, &shellinput_size);
    440 				fbtermBlinkCursor (CURSOR_SHOW);
    441 			}
    442 			debug (DEBUG_DETAIL, "Finished reading");
    443 		}
    444 	}
    445 
    446 	switch (quit)
    447 	{
    448 	case 1:
    449 		debug (DEBUG_INFO, "Exiting: EOF condition");
    450 		break;
    451 	case 2:
    452 		debug (DEBUG_INFO, "Exiting: Child process has died");
    453 		break;
    454 	case 3:
    455 		debug (DEBUG_INFO, "Exiting: Pipe error");
    456 		break;
    457 	}
    458 	fbtermBlinkCursor (1);
    459 	FBUIExit ();
    460 	free (tabstops);
    461 	close (master_fd);
    462 	
    463 	return (0);
    464 }

This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.