1 /* This file is part of the Project Athena Zephyr Notification System.
2 * It is one of the source files comprising zwgc, the Zephyr WindowGram
5 * Created by: Marc Horowitz <marc@athena.mit.edu>
7 * $Id: tty_filter.c,v 1.21 2002/04/18 18:28:17 rbasch Exp $
9 * Copyright (c) 1989 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, see the file
16 #if (!defined(lint) && !defined(SABER))
17 static const char rcsid_tty_filter_c[] = "$Id: tty_filter.c,v 1.21 2002/04/18 18:28:17 rbasch Exp $";
20 #include <zephyr/mit-copyright.h>
22 /****************************************************************************/
24 /* The tty & plain filters: */
26 /****************************************************************************/
28 #include "new_memory.h"
29 #include "new_string.h"
30 #include "string_dictionary_aux.h"
31 #include "formatter.h"
35 /***************************************************************************/
38 extern char *tgetstr(),*getenv();
44 /* Dictionary naming convention:
46 B.xxx is the termcap sequence to begin environment xxx.
47 E.xxx is the termcap sequence to end environment xxx.
51 static string_dictionary termcap_dict;
52 static char code_buf[10240], *code_buf_pos = code_buf, *code;
54 /* Define the following commands:
56 (Hopefully) shared with all devices:
60 @em Emphasis. User underline if available, else reverse video.
61 @bold Bold letters. If not available, reverse video, else underline.
62 @beep "bl" termcap entry, else "^G"
66 @blink "mb"/"me" termcap entry, else nothing.
67 @rv "so"/"se" termcap entry.
68 @u "us"/"ue" termcap entry.
71 #define TD_SET(k,v) (string_dictionary_Define(termcap_dict, (k), &ex)->value \
73 #define EXPAND(k) (code = code_buf_pos, tputs(tmp, 1, tty_outc), \
74 *code_buf_pos++ = 0, TD_SET(k, code))
85 int tty_filter_init(drivername, notfirst, pargc, argv)
91 static char st_buf[128];
92 char tc_buf[1024], *p = st_buf, *tmp, *term;
94 string_dictionary_binding *b;
95 int isrealtty = string_Eq(drivername, "tty");
100 ospeed = (tcgetattr(STDIN_FILENO, &tbuf) == 0) ? cfgetospeed(&tbuf) : 2400;
102 struct sgttyb sgttyb;
104 ospeed = (ioctl(0, TIOCGETP, &sgttyb) == 0) ? sgttyb.sg_ospeed : 2400;
108 if (termcap_dict == (string_dictionary) NULL)
109 termcap_dict = string_dictionary_Create(7);
111 if (!(term = getenv("TERM"))) { /* Only use termcap if $TERM. */
112 if (isrealtty && !notfirst)
113 /* only complain if initializing tty mode, and would be first
115 ERROR("$TERM not set. tty mode will be plain.\n");
119 * This is a temporary KLUDGE to get around the problem where some people
120 * might start zwgc in their ~/.startup.X and it hangs on the RISC/6000.
121 * Apparently, the call to tgetent() with the Athena console window causes
122 * the process to get stopped on tty access. Since the terminal type is
123 * "dumb" (set by tcsh), we can pretty much assume there isn't anything
124 * to setup from the termcap information.
126 else if (!strcmp(term, "dumb")) { }
129 tgetent(tc_buf, term);
131 /* Step 1: get all of {rv,bold,u,bell,blink} that are available. */
133 /* We cheat here, and ignore the padding (if any) specified for
134 the mode-change strings (it's a real pain to do "right") */
137 tmp = tgetstr("pc", &p);
138 PC = (tmp) ? *tmp : 0;
140 if (tmp = tgetstr("md",&p)) { /* bold ? */
142 tmp = tgetstr("me",&p);
145 if (tmp = tgetstr("mr",&p)) { /* reverse video? */
147 tmp = tgetstr("me",&p);
150 if (tmp = tgetstr("bl",&p)) { /* Bell ? */
152 TD_SET("E.bell", NULL);
154 if (tmp = tgetstr("mb",&p)) { /* Blink ? */
156 tmp = tgetstr("me",&p);
159 if (tmp = tgetstr("us",&p)) { /* Underline ? */
161 tmp = tgetstr("ue",&p);
164 if (tmp = tgetstr("so",&p)) { /* Standout ? */
166 tmp = tgetstr("se",&p);
170 /* Step 2: alias others to the nearest substitute */
172 /* Bold = so, else rv, else ul */
173 if (NULL == string_dictionary_Lookup(termcap_dict,"B.bold")) {
174 if(b = string_dictionary_Lookup(termcap_dict,"B.so")) {
175 TD_SET("B.bold",b->value);
177 string_dictionary_Lookup(termcap_dict,"E.so")->value);
178 } else if (b = string_dictionary_Lookup(termcap_dict,"B.rv")) {
179 TD_SET("B.bold",b->value);
181 string_dictionary_Lookup(termcap_dict,"E.rv")->value);
182 } else if (b = string_dictionary_Lookup(termcap_dict,"B.u")) {
183 TD_SET("B.bold",b->value);
185 string_dictionary_Lookup(termcap_dict,"E.u")->value);
190 if (NULL == string_dictionary_Lookup(termcap_dict,"B.bell")) {
191 TD_SET("B.bell","\007");
192 TD_SET("E.bell",NULL);
195 /* Underline -> nothing */
196 /* Blink -> nothing */
201 /***************************************************************************/
206 static int fixed_string_eq(pattern, text, text_length)
211 while (*pattern && text_length>0 && *pattern == *text) {
217 return(!*pattern && !text_length);
220 typedef struct _tty_str_info {
221 struct _tty_str_info *next;
226 char alignment; /* 'l', 'c', 'r', or ' ' to indicate newline */
227 unsigned int bold_p : 1;
228 unsigned int italic_p : 1;
229 unsigned int bell_p : 1;
230 unsigned int ignore: 1;
233 static void free_info(info)
236 tty_str_info *next_info;
239 next_info = info->next;
245 static int do_mode_change(current_mode_p, text, text_length)
246 tty_str_info *current_mode_p;
250 /* alignment commands: */
251 if (fixed_string_eq("left", text, text_length) ||
252 fixed_string_eq("l", text, text_length))
253 current_mode_p->alignment = 'l';
254 else if (fixed_string_eq("center", text, text_length) ||
255 fixed_string_eq("c", text, text_length))
256 current_mode_p->alignment = 'c';
257 else if (fixed_string_eq("right", text, text_length) ||
258 fixed_string_eq("r", text, text_length))
259 current_mode_p->alignment = 'r';
262 else if (fixed_string_eq("bold", text, text_length) ||
263 fixed_string_eq("b", text, text_length))
264 current_mode_p->bold_p = 1;
265 else if (fixed_string_eq("italic", text, text_length) ||
266 fixed_string_eq("i", text, text_length))
267 current_mode_p->italic_p = 1;
268 else if (fixed_string_eq("roman", text, text_length)) {
269 current_mode_p->bold_p = 0;
270 current_mode_p->italic_p = 0;
271 } else if (fixed_string_eq("beep", text, text_length)) {
272 current_mode_p->bell_p = 1;
276 /* commands ignored in tty mode: */
277 else if (fixed_string_eq("color", text, text_length) ||
278 fixed_string_eq("font", text, text_length)) {
279 current_mode_p->ignore = 1;
284 static tty_str_info *convert_desc_to_tty_str_info(desc)
288 tty_str_info *result = NULL;
289 tty_str_info *last_result_block = NULL;
290 int isbeep, did_beep = 0;
292 #if !defined(SABER) && defined(__STDC__)
293 tty_str_info current_mode = { NULL, "", 0, 'l', 0 , 0, 0, 0};
295 /* This is needed due to a bug in saber, and lack of pre-ANSI support. */
296 tty_str_info current_mode;
298 current_mode.next = NULL;
299 current_mode.str = "";
300 current_mode.len = 0;
301 current_mode.alignment = 'l';
302 current_mode.bold_p = 0;
303 current_mode.italic_p = 0;
304 current_mode.bell_p = 0;
305 current_mode.ignore = 0;
308 for (; desc->code!=DT_EOF; desc=desc->next) {
310 /* Handle environments: */
311 if (desc->code == DT_ENV) {
313 temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info));
314 *temp = current_mode;
315 current_mode.next = temp;
317 isbeep = do_mode_change(¤t_mode, desc->str, desc->len);
318 if (!isbeep || did_beep)
319 continue; /* process one beep, ignore other envs */
320 } else if (desc->code == DT_END) {
322 temp = current_mode.next;
323 current_mode = *temp;
328 /* Add new block (call it temp) to result: */
329 temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info));
330 *temp = current_mode;
331 if (last_result_block) {
332 last_result_block->next = temp;
333 last_result_block = temp;
336 last_result_block = temp;
340 /* special processing: need to insert a bell */
341 string_dictionary_binding *b;
342 b = string_dictionary_Lookup(termcap_dict,"B.bell");
344 temp->str = b->value;
345 temp->len = string_Length(temp->str);
347 /* shouldn't get here! */
352 if (desc->code == DT_STR) {
353 /* just combine string info with current mode: */
354 temp->str = desc->str;
355 temp->len = desc->len;
356 } else if (desc->code == DT_NL) {
357 /* make the new block a ' ' alignment block with an empty string */
358 temp->alignment = ' ';
364 if (last_result_block)
365 last_result_block->next = NULL;
370 #define max(a,b) ((a)>(b)?(a):(b))
372 static int line_width(left_width, center_width, right_width)
377 if (center_width>0) {
378 if (left_width==0 && right_width==0)
379 return(center_width);
380 return(center_width+2+max(left_width,right_width)*2);
382 if (left_width && right_width)
383 return(1+left_width+right_width);
385 return(left_width+right_width);
389 static int calc_max_line_width(info)
392 int max_line_width = 0;
397 for (; info; info=info->next) {
400 switch (info->alignment) {
416 printf("width: %d %d %d = %d\n", left, center, right,
417 line_width(left, center, right));
419 max_line_width = max(max_line_width,
420 line_width(left, center, right));
421 left = center = right = 0;
428 printf("width: %d %d %d = %d\n", left, center, right,
429 line_width(left, center, right));
431 max_line_width = max(max_line_width,
432 line_width(left, center, right));
434 return(max_line_width);
437 string tty_filter(text, use_fonts)
441 string text_copy = string_Copy(text);
442 string result_so_far = string_Copy("");
446 tty_str_info *info, *info_head;
449 desc = disp_get_cmds(text_copy, &number_of_strs, &number_of_lines);
450 info_head = info = convert_desc_to_tty_str_info(desc);
456 for (ptr=info; ptr; ptr=ptr->next) {
457 printf("%c: %s %s %s <%s>\n", ptr->alignment,
458 ptr->bold_p ? "(bold)" : "",
459 ptr->italic_p ? "(italic)" : "",
460 ptr->bell_p ? "(bell)" : "",
461 string_CreateFromData(ptr->str, ptr->len));
466 max_line_width = calc_max_line_width(info);
467 dprintf1("max width = %d\n", max_line_width);
470 string left, center, right;
471 int left_width, center_width, right_width;
474 left_width = center_width = right_width = 0;
475 left = string_Copy("");
476 center = string_Copy("");
477 right = string_Copy("");
479 for (; info && info->alignment!=' '; info=info->next) {
485 item = string_Copy("");
487 if (info->bold_p && use_fonts) {
488 if (temp = string_dictionary_Fetch(termcap_dict, "B.bold"))
489 item = string_Concat2(item, temp);
490 } else if (info->italic_p && use_fonts) {
491 if (temp = string_dictionary_Fetch(termcap_dict, "B.u"))
492 item = string_Concat2(item, temp);
494 temp = string_CreateFromData(info->str, info->len);
495 item = string_Concat2(item, temp);
498 if (info->bold_p && use_fonts) {
499 if (temp = string_dictionary_Fetch(termcap_dict, "E.bold"))
500 item = string_Concat2(item, temp);
501 } else if (info->italic_p && use_fonts) {
502 if (temp = string_dictionary_Fetch(termcap_dict, "E.u"))
503 item = string_Concat2(item, temp);
506 switch (info->alignment) {
509 left = string_Concat2(left, item);
510 left_width += info->len;
514 center = string_Concat2(center, item);
515 center_width += info->len;
519 right = string_Concat2(right, item);
520 right_width += info->len;
526 result_so_far = string_Concat2(result_so_far, left);
528 while (left_width < (max_line_width-center_width)/2 ) {
529 result_so_far = string_Concat2(result_so_far, " ");
532 result_so_far = string_Concat2(result_so_far, center);
533 left_width += center_width;
536 while (left_width<max_line_width-right_width) {
537 result_so_far = string_Concat2(result_so_far, " ");
540 result_so_far = string_Concat2(result_so_far, right);
541 free(left); free(center); free(right);
543 if (info && info->alignment == ' ') {
545 result_so_far = string_Concat2(result_so_far, "\r\n");
549 free_info(info_head);
551 if (number_of_lines &&
552 (result_so_far[string_Length(result_so_far)-1] != '\n'))
553 /* CRLF-terminate all results */
554 result_so_far = string_Concat2(result_so_far, "\r\n");
555 return(result_so_far);