Back to index

lightning-sunbird  0.9+nobinonly
lterm.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is lineterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *
00023  * Alternatively, the contents of this file may be used under the terms of
00024  * either the GNU General Public License Version 2 or later (the "GPL"), or
00025  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00026  * in which case the provisions of the GPL or the LGPL are applicable instead
00027  * of those above. If you wish to allow use of your version of this file only
00028  * under the terms of either the GPL or the LGPL, and not to allow others to
00029  * use your version of this file under the terms of the MPL, indicate your
00030  * decision by deleting the provisions above and replace them with the notice
00031  * and other provisions required by the GPL or the LGPL. If you do not delete
00032  * the provisions above, a recipient may use your version of this file under
00033  * the terms of any one of the MPL, the GPL or the LGPL.
00034  *
00035  * ***** END LICENSE BLOCK ***** */
00036 
00037 /* lterm.c: Test driver for LINETERM
00038  * CPP options:
00039  *   USE_NCURSES:           Enable NCURSES as a screen display option
00040  *   NCURSES_MOUSE_VERSION: Enable NCURSES mouse operations
00041  *   LINUX:                 for Linux2.0/glibc
00042  *   SOLARIS:               for Solaris2.6
00043  */
00044 
00045 #include <stdio.h>
00046 #include <signal.h>
00047 
00048 #include <sys/types.h>
00049 #include <fcntl.h>
00050 #include <unistd.h>
00051 #include <termios.h>
00052 
00053 #include <assert.h>
00054 
00055 #ifdef USE_NCURSES
00056 #include <ncurses.h>
00057 #endif
00058 
00059 #ifndef _REENTRANT
00060 #define _REENTRANT
00061 #endif /* !_REENTRANT */
00062 
00063 #include <pthread.h>
00064 
00065 #ifdef SOLARIS
00066 #include <stropts.h>
00067 #include <poll.h>
00068 #endif
00069 
00070 #ifdef LINUX
00071 #include <sys/ioctl.h>
00072 #include <sys/poll.h>
00073 #endif
00074 
00075 #include "lineterm.h"
00076 #include "tracelog.h"
00077 
00078 #define MAXPROMPT 256          /* Maximum length of prompt regexp */
00079 #define MAXCOL 4096            /* Maximum columns in line buffer */
00080 
00081 /* (0,0) is upper lefthand corner of window */
00082 
00083 /* Character attributes
00084         A_NORMAL        Normal display (no highlight)
00085         A_STANDOUT      Best highlighting mode of the terminal.
00086         A_UNDERLINE     Underlining
00087         A_REVERSE       Reverse video
00088         A_BLINK         Blinking
00089         A_DIM           Half bright
00090         A_BOLD          Extra bright or bold
00091         A_PROTECT       Protected mode
00092         A_INVIS         Invisible or blank mode
00093         A_ALTCHARSET    Alternate character set
00094         A_CHARTEXT      Bit-mask to extract a character
00095         COLOR_PAIR(n)   Color-pair number n
00096 */
00097 
00098 /* GLOBAL VARIABLES */
00099 static int ncursesFlag = 0;
00100 static int ptyFlag = 1;
00101 static int debugFlag = 0;
00102 static int ltermNumber = -1;
00103 static char *debugFunction;
00104 static char *ttyDevice;
00105 static char *errDevice;
00106 
00107 static int screenMode = 0;
00108 static int topScrollRow, botScrollRow;
00109 
00110 static struct termios tios;    /* TERMIOS structure */
00111 
00112 static void finish(int sig);
00113 static pthread_t output_handler_thread_ID;
00114 
00115 static void *output_handler(void *arg);
00116 
00117 static void input_handler(int *plterm);
00118 
00119 #ifdef USE_NCURSES
00120 static SCREEN  *termScreen = NULL;
00121 #endif
00122 
00123 int main(int argc, char *argv[]) {
00124   FILE *inFile, *outFile;
00125   UNICHAR uregexp[MAXPROMPT+1];
00126   int argNo, options, processType, retValue;
00127   int remaining, decoded;
00128   int messageLevel;
00129   char *promptStr;
00130   char **commandArgs;
00131   char *defaultCommand[] = {(char *)getenv("SHELL"), "-i", NULL};
00132 
00133   /* Process command line arguments */
00134   ncursesFlag = 0;
00135   ptyFlag = 1;
00136   debugFlag = 0;
00137   processType = LTERM_DETERMINE_PROCESS;
00138   debugFunction = NULL;
00139   ttyDevice = NULL;
00140   errDevice = NULL;
00141   promptStr = "#$%>?";  /* JUST A LIST OF DELIMITERS AT PRESENT */
00142 
00143   argNo = 1;
00144   while (argNo < argc) {
00145 
00146     if ((strcmp(argv[argNo],"-h") == 0)||(strcmp(argv[argNo],"-help") == 0)) {
00147       fprintf(stderr, "Usage: %s [-help] [-ncurses] [-nopty] [-debug] [-tcsh / -bash] [-function debug_fun] [-tty /dev/ttyname] [-err /dev/ttyname] [-prompt <prompt>] <command> ...\n", argv[0]);
00148       exit(0);
00149 
00150     } else if (strcmp(argv[argNo],"-ncurses") == 0) {
00151       ncursesFlag = 1;
00152       argNo++;
00153 
00154     } else if (strcmp(argv[argNo],"-nopty") == 0) {
00155       ptyFlag = 0;
00156       argNo++;
00157 
00158     } else if (strcmp(argv[argNo],"-debug") == 0) {
00159       debugFlag = 1;
00160       argNo++;
00161 
00162     } else if (strcmp(argv[argNo],"-bash") == 0) {
00163       processType = LTERM_BASH_PROCESS;
00164       argNo++;
00165 
00166     } else if (strcmp(argv[argNo],"-tcsh") == 0) {
00167       processType = LTERM_TCSH_PROCESS;
00168       argNo++;
00169 
00170     } else if (strcmp(argv[argNo],"-function") == 0) {
00171       argNo++;
00172       if (argNo < argc) {
00173         debugFunction = argv[argNo++];
00174       }
00175 
00176     } else if (strcmp(argv[argNo],"-tty") == 0) {
00177       argNo++;
00178       if (argNo < argc) {
00179         ttyDevice = argv[argNo++];
00180       }
00181 
00182     } else if (strcmp(argv[argNo],"-err") == 0) {
00183       argNo++;
00184       if (argNo < argc) {
00185         errDevice = argv[argNo++];
00186       }
00187 
00188     } else if (strcmp(argv[argNo],"-prompt") == 0) {
00189       argNo++;
00190       if (argNo < argc) {
00191         promptStr = argv[argNo++];
00192       }
00193 
00194     } else
00195       break;
00196   }
00197 
00198   if (argNo < argc) {
00199     /* Execute specified command */
00200     commandArgs = argv + argNo;
00201   } else {
00202     /* Execute default shell */
00203     commandArgs = defaultCommand;
00204   }
00205 
00206   /* Convert prompt string to Unicode */
00207   retValue = utf8toucs(promptStr, strlen(promptStr), uregexp, MAXPROMPT,
00208                        0, &remaining, &decoded);
00209   if ((retValue < 0) || (remaining > 0)) {
00210     fprintf(stderr, "lterm: Error in decoding prompt string\n");
00211     exit(1);
00212   }
00213 
00214   assert(decoded <= MAXPROMPT);
00215   uregexp[decoded] = U_NUL;
00216 
00217   if (debugFlag) {
00218     messageLevel = 98;
00219   } else {
00220     messageLevel = 1;
00221   }
00222 
00223   if (errDevice != NULL) {
00224     /* Redirect debug STDERR output to specified device */
00225     int errfd = -1;
00226     if ( (errfd = open(errDevice, O_WRONLY)) == -1)
00227         perror("lterm");
00228 
00229     if (dup2(errfd, 2) == -1) {
00230       fprintf(stderr, "lterm: Failed dup2 for specified stderr\n");
00231       exit(-1);
00232     }
00233 
00234     fprintf(stderr, "\n\nlterm: Echoing %s output to %s\n",
00235             argv[0], errDevice);
00236   }
00237 
00238   signal(SIGINT, finish); /* Interrupt handler */
00239 
00240   if (ncursesFlag) {
00241     /* NCURSES mode */
00242 
00243 #ifdef USE_NCURSES
00244     if (ttyDevice == NULL) {
00245       /* Initialize screen on controlling TTY */
00246       initscr();
00247 
00248     } else {
00249       /* Initialize screen on specified TTY */
00250       if (errDevice != NULL)
00251         fprintf(stderr, "lterm-00: Opening xterm %s\n", ttyDevice);
00252       inFile = fopen( ttyDevice, "r");
00253       outFile = fopen( ttyDevice, "w");
00254       termScreen = newterm("xterm", outFile, inFile);
00255       set_term(termScreen);
00256     }
00257 
00258     /* NCURSES screen settings */
00259     cbreak();                 /* set terminal to raw (non-canonical) mode */
00260     noecho();                 /* Disable terminal echo */
00261     nonl();                   /* Do not translate newline */
00262     intrflush(stdscr, FALSE); /* Flush input on interrupt */
00263     keypad(stdscr, TRUE);     /* Enable user keypad */
00264 
00265 #ifdef NCURSES_MOUSE_VERSION
00266     mousemask(BUTTON1_CLICKED, NULL); /* Capture Button1 click events */
00267 #endif
00268 
00269     clear(); /* Clear screen */
00270 #endif  /* USE_NCURSES */
00271 
00272   } else {
00273     /* XTERM mode */
00274 
00275     /* Get terminal attributes */
00276     if (tcgetattr(0, &tios) == -1) {
00277       fprintf(stderr, "lterm: Failed to get TTY attributes\n");
00278       exit(-1);
00279     }
00280 
00281     /* Disable signals, canonical mode processing, and echo  */
00282     tios.c_lflag &= ~(ISIG | ICANON | ECHO );
00283 
00284     /* set MIN=1 and TIME=0 */
00285     tios.c_cc[VMIN] = 1;
00286     tios.c_cc[VTIME] = 0;
00287 
00288     /* Set terminal attributes */
00289     if (tcsetattr(0, TCSAFLUSH, &tios) == -1) {
00290       fprintf(stderr, "lterm: Failed to set TTY attributes\n");
00291       exit(-1);
00292     }
00293 
00294   }
00295 
00296   /* Initialize LTERM operations */
00297   lterm_init(0);
00298 
00299   if (errDevice != NULL) {
00300     tlog_message("lterm-00: Testing tlog_message\n");
00301     tlog_warning("lterm-00: Testing tlog_warning\n");
00302     fprintf(stderr, "lterm-00: ");
00303     tlog_unichar(uregexp, ucslen(uregexp));
00304     tlog_set_level(LTERM_TLOG_MODULE, messageLevel, debugFunction);
00305   }
00306 
00307   if (errDevice != NULL)
00308     fprintf(stderr, "lintest-00: Opening LTERM to execute %s\n", commandArgs[0]);
00309 
00310   options = 0;
00311   if (!ptyFlag) options |= LTERM_NOPTY_FLAG;
00312 
00313   ltermNumber = lterm_new();
00314   retValue = lterm_open(ltermNumber, commandArgs, NULL, NULL, uregexp,
00315                         options, processType,
00316                         24, 80, 0, 0,
00317                         NULL, NULL);
00318   if (retValue < 0) {
00319     fprintf(stderr, "lterm: Error %d in opening LTERM\n", retValue);
00320     exit(1);
00321   }
00322 
00323   /* Create output handler thread */
00324   retValue = pthread_create(&output_handler_thread_ID,  NULL,
00325                             output_handler, (void *) &ltermNumber);
00326   if (retValue != 0) {
00327     fprintf(stderr, "lterm: Error %d in creating OUTPUT_HANDLER thread\n",
00328                      retValue);
00329     finish(0);
00330   }
00331 
00332   if (errDevice != NULL)
00333     fprintf(stderr, "lterm-00: Created OUTPUT_HANDLER thread\n");
00334 
00335   /* Process input */
00336   input_handler(&ltermNumber);
00337 
00338   /* Join output handler thread */
00339   if (errDevice != NULL)
00340     fprintf(stderr, "lterm-00: Joining OUTPUT_HANDLER thread\n");
00341 
00342   retValue = pthread_join(output_handler_thread_ID,  NULL);
00343   if (retValue != 0) {
00344     fprintf(stderr, "lterm: Error %d in joining OUTPUT_HANDLER thread\n",
00345                      retValue);
00346     finish(0);
00347   }
00348 
00349   finish(0);
00350 }
00351 
00352 void finish(int sig)
00353 {
00354   if (ncursesFlag) {
00355 #ifdef USE_NCURSES
00356     endwin(); /* Close window */
00357     if (termScreen != NULL)
00358       delscreen(termScreen);
00359 #endif
00360   }
00361 
00362   if (ltermNumber >= 0) {
00363     /* Close and delete LTERM */
00364     lterm_delete(ltermNumber);
00365   }
00366 
00367   if (errDevice != NULL)
00368     fprintf(stderr, "finished-00: Finished\n");
00369 
00370   exit(0);
00371 }
00372 
00376 void writeUnicode(int fd, const UNICHAR *buf, int count)
00377 {
00378   char str[MAXCOL];
00379   int j, k;
00380 
00381   k = 0;
00382   for (j=0; j<count; j++) {
00383 
00384     if (k >= MAXCOL-4) {
00385       if (MAXCOL >= 4) {
00386         str[MAXCOL-4] = '.';
00387         str[MAXCOL-3] = '.';
00388         str[MAXCOL-2] = '.';
00389       }
00390       k = MAXCOL-1;
00391       break;
00392     }
00393 
00394     /* TEMPORARY IMPLEMENTATION: just truncate Unicode to byte characters */
00395     str[k++] = buf[j];
00396   }
00397 
00398   if (k == 0) return;
00399 
00400   if (fd >= 0) {
00401     if (write(fd, str, k) != k) {
00402       fprintf(stderr, "writeUnicode: Error in writing to FD %d\n", fd);
00403       exit(-1);
00404     }
00405   } else {
00406 #ifdef USE_NCURSES
00407     addnstr(str, k);
00408 #endif
00409   }
00410 }
00411 
00412 
00417 void printUnicode(FILE *outStream, const UNICHAR *buf, int count, int noControl)
00418 {
00419   char str[MAXCOL];
00420   int j, k;
00421 
00422   k = 0;
00423   for (j=0; j<count; j++) {
00424 
00425     if (k >= MAXCOL-4) {
00426       if (MAXCOL >= 4) {
00427         str[MAXCOL-4] = '.';
00428         str[MAXCOL-3] = '.';
00429         str[MAXCOL-2] = '.';
00430       }
00431       k = MAXCOL-1;
00432       break;
00433     }
00434 
00435     if (!noControl && ((buf[j] < U_SPACE) || (buf[j] == U_DEL)) ) {
00436       /* Control character */
00437       str[k++] = U_CARET;
00438       str[k++] = buf[j]+U_ATSIGN;
00439     } else {
00440       /* Printable character */
00441       /* TEMPORARY IMPLEMENTATION: just truncate Unicode to byte characters */
00442       str[k++] = buf[j];
00443     }
00444   }
00445 
00446   /* Insert terminating null character and display string */
00447   str[k++] = '\0';
00448   fprintf(outStream, "%s\n", str);
00449 }
00450 
00451 
00452 void input_handler(int *plterm)
00453 {
00454   char ch;
00455   UNICHAR uch;
00456   int n_written;
00457 
00458   for (;;) {
00459     /* Read a character from TTY (raw mode) */
00460     if (ncursesFlag) {
00461 #ifdef USE_NCURSES
00462       ch = getch();
00463       if (ch == '\r')
00464         ch = '\n';
00465 #endif
00466     } else {
00467       ch = getchar();
00468     }
00469 
00470     /* fprintf(stderr, "input_handler-00: ch=%d\n", ch); */
00471 
00472     if (ch == 0x1D) {
00473       fprintf(stderr, "input_handler-00: C-] character read; terminating\n");
00474       break;
00475     }
00476 
00477     uch = (UNICHAR) ch;
00478     n_written = lterm_write(*plterm, &uch, 1, LTERM_WRITE_PLAIN_INPUT);
00479 
00480     /* Exit loop if TTY has been closed */
00481     if (n_written == -2) {
00482       if (errDevice != NULL)
00483         fprintf(stderr, "input_handler-00: pseudo-TTY has been closed\n", *plterm);
00484       break;
00485     }
00486 
00487     if (n_written < 0) {
00488       fprintf(stderr, "input_handler: Error %d return from lterm_write\n",
00489               n_written);
00490       return;
00491     }
00492   }
00493 
00494   /* Close LTERM */
00495   if (errDevice != NULL)
00496     fprintf(stderr, "input_handler-00: Closing LTERM %d\n", *plterm);
00497 
00498   /* Close and delete LTERM */
00499   lterm_delete(*plterm);
00500   *plterm = -1;
00501 }
00502 
00503 void *output_handler(void *arg)
00504 {
00505   int *plterm = (int *) arg;
00506   int timeout = -1;
00507   UNICHAR buf[MAXCOL];
00508   UNISTYLE style[MAXCOL];
00509   int n_read, opcodes, opvals, buf_row, buf_col, cursor_row, cursor_col;
00510   int xmax, ymax, x, y, c;
00511 #ifdef USE_NCURSES
00512   MEVENT mev;
00513 #endif
00514 
00515   if (errDevice != NULL)
00516     fprintf(stderr, "output_handler-00: thread ID = %d, LTERM=%d\n",
00517                     pthread_self(), *plterm);
00518 
00519   /* Get screen size */
00520   if (ncursesFlag) {
00521 #ifdef USE_NCURSES
00522     getmaxyx(stdscr, ymax, xmax);
00523 #endif
00524 
00525   } else {
00526     ymax = 24;
00527     xmax = 80;
00528   }
00529 
00530   if (errDevice != NULL)
00531     fprintf(stderr, "output_handler-00: screen xmax = %d, ymax = %d\n",
00532             xmax,ymax);
00533 
00534   for (;;) {
00535     n_read = lterm_read(*plterm, timeout, buf, MAXCOL,
00536                         style, &opcodes, &opvals,
00537                         &buf_row, &buf_col, &cursor_row, &cursor_col);
00538 
00539     if (n_read == -1) {
00540       fprintf(stderr, "output_handler: Error %d return from lterm_read\n",
00541                       n_read);
00542       return NULL;
00543     }
00544 
00545     /* Exit loop if TTY has been closed;
00546      * leave it to input handler to close the LTERM.
00547      */
00548     if (n_read == -2) {
00549       if (errDevice != NULL)
00550         fprintf(stderr, "output_handler: pseudo-TTY has been closed\n");
00551       break;
00552     }
00553 
00554     if (debugFlag) {
00555       fprintf(stderr, "output_handler-00: n_read=%d, opcodes=%x, opvals=%d, buf_row/col=%d/%d, cursor_row/col=%d/%d\n",
00556             n_read, opcodes, opvals, buf_row, buf_col, cursor_row, cursor_col);
00557       fprintf(stderr, "output_handler-00: U(%d): ", n_read);
00558       printUnicode(stderr, buf, n_read, 1);
00559       fprintf(stderr, "\n");
00560     }
00561 
00562     if (opcodes & LTERM_STREAMDATA_CODE) {
00563       /* Stream data */
00564       if (debugFlag)
00565         fprintf(stderr, "output_handler-00: STREAMDATA\n");
00566 
00567 
00568     } else if (opcodes & LTERM_SCREENDATA_CODE) {
00569       /* Screen data */
00570 
00571       if (!screenMode) {
00572         screenMode = 1;
00573         topScrollRow = ymax-1;
00574         botScrollRow = 0;
00575       }
00576 
00577       if (debugFlag)
00578         fprintf(stderr, "output_handler-00: SCREENDATA, topScrollRow=%d, botScrollRow=%d\n", topScrollRow, botScrollRow);
00579 
00580       if (ncursesFlag) {
00581         /* NCURSES mode */
00582 
00583 #ifdef USE_NCURSES
00584         if (opcodes & LTERM_CLEAR_CODE) {
00585           clear();
00586 
00587         } else if (opcodes & LTERM_INSERT_CODE) {
00588           if ((botScrollRow > 0) && (opvals > 0)) {
00589             move(ymax-botScrollRow-opvals, 0);
00590             insdelln(-opvals);
00591           }
00592 
00593           move(ymax-1-buf_row, 0);
00594           insdelln(opvals);
00595 
00596         } else if (opcodes & LTERM_DELETE_CODE) {
00597 
00598           move(ymax-1-buf_row, 0);
00599           insdelln(-opvals);
00600 
00601           if ((botScrollRow > 0) && (opvals > 0)) {
00602             move(ymax-botScrollRow-opvals, 0);
00603             insdelln(opvals);
00604           }
00605 
00606         } else if (opcodes & LTERM_SCROLL_CODE) {
00607           topScrollRow = opvals;
00608           botScrollRow = buf_row;
00609 
00610         } else if (opcodes & LTERM_OUTPUT_CODE) {
00611           /* Data available for display */
00612           move(ymax-1-buf_row, buf_col);
00613           clrtoeol();
00614 
00615           if (n_read > 0) {
00616             if (style[0] != LTERM_STDOUT_STYLE)
00617               attr_on(A_REVERSE, NULL);
00618 
00619             writeUnicode(-1, buf, n_read);
00620 
00621             if (style[0] != LTERM_STDOUT_STYLE)
00622               attr_off(A_REVERSE, NULL);
00623           }
00624         }
00625 
00626         /* Position cursor */
00627         move(ymax-1-cursor_row, cursor_col);
00628 
00629         refresh();
00630 #endif  /* USE_NCURSES */
00631 
00632       } else {
00633         /* XTERM MODE */
00634         char esc_seq[21];
00635 
00636         if (opcodes & LTERM_CLEAR_CODE) {
00637           /* Clear screen */
00638           write(1, "\033[H\033[2J", 7);
00639 
00640         } else if (opcodes & LTERM_INSERT_CODE) {
00641           /* Insert lines */
00642           sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
00643           write(1, esc_seq, strlen(esc_seq));
00644 
00645           sprintf(esc_seq, "\033[%dL", opvals);
00646           write(1, esc_seq, strlen(esc_seq));
00647 
00648         } else if (opcodes & LTERM_DELETE_CODE) {
00649           /* Delete lines */
00650           sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
00651           write(1, esc_seq, strlen(esc_seq));
00652 
00653           sprintf(esc_seq, "\033[%dM", opvals);
00654           write(1, esc_seq, strlen(esc_seq));
00655 
00656         } else if (opcodes & LTERM_SCROLL_CODE) {
00657           /* Set scrolling region */
00658           sprintf(esc_seq, "\033[%d;%dr", ymax-opvals, ymax-buf_row);
00659           write(1, esc_seq, strlen(esc_seq));
00660 
00661         } else if (opcodes & LTERM_OUTPUT_CODE) {
00662           /* Data available for display */
00663           sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
00664           write(1, esc_seq, strlen(esc_seq));
00665 
00666           if (n_read > 0) {
00667             if (style[0] != LTERM_STDOUT_STYLE)
00668               write(1, "\033[7m", 4);
00669 
00670             writeUnicode(1, buf, n_read);
00671 
00672             if (style[0] != LTERM_STDOUT_STYLE)
00673               write(1, "\033[27m", 5);
00674           }
00675         }
00676 
00677         sprintf(esc_seq, "\033[%d;%dH", ymax-cursor_row, cursor_col+1);
00678         write(1, esc_seq, strlen(esc_seq));
00679       }
00680 
00681     } else if (opcodes & LTERM_LINEDATA_CODE) {
00682       /* Line data */
00683       if (debugFlag)
00684         fprintf(stderr, "output_handler-00: LINEDATA\n");
00685 
00686       if (screenMode)
00687         screenMode = 0;
00688 
00689       if (ncursesFlag) {
00690         /* NCURSES mode */
00691 
00692 #ifdef USE_NCURSES
00693         /* Move cursor to bottom of screen, clear line and display line */
00694         move(ymax-1,0);
00695         clrtoeol();
00696         if (n_read > 0)
00697           writeUnicode(-1, buf, n_read);
00698         move(ymax-1,cursor_col);
00699 
00700         if (opcodes & LTERM_NEWLINE_CODE) {
00701           move(0,0);
00702           insdelln(-1);
00703           move(ymax-1,0);
00704         }
00705 
00706         refresh();
00707 #endif  /* USE_NCURSES */
00708 
00709       } else {
00710         /* Screen mode */
00711         int j;
00712 
00713         /* Clear line */
00714         write(1, "\033[2K", 4);
00715         write(1, "\r", 1);
00716 
00717         if (opcodes & LTERM_META_CODE)
00718           write(1, "META", 4);
00719 
00720         if (n_read > 0)
00721           writeUnicode(1, buf, n_read);
00722 
00723         for (j=0; j< (n_read-cursor_col); j++)
00724           write(1, "\033[D", 3);
00725 
00726         if (opcodes & LTERM_BELL_CODE)
00727           write(1, "\007", 1);
00728 
00729         if (opcodes & LTERM_CLEAR_CODE)
00730           write(1, "\033[H\033[2J", 7);
00731 
00732         if (opcodes & LTERM_NEWLINE_CODE)
00733           write(1, "\n", 1);
00734       }
00735 
00736     } else if (opcodes != 0) {
00737       fprintf(stderr, "output_handler: invalid opcodes %x\n", opcodes);
00738     }
00739   }
00740 
00741   return NULL;
00742 }