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.