Back to index

lightning-sunbird  0.9+nobinonly
Defines | Functions | Variables
lterm.c File Reference
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <assert.h>
#include <pthread.h>
#include "lineterm.h"
#include "tracelog.h"

Go to the source code of this file.

Defines

#define _REENTRANT
#define MAXPROMPT   256 /* Maximum length of prompt regexp */
#define MAXCOL   4096 /* Maximum columns in line buffer */

Functions

static void finish (int sig)
static voidoutput_handler (void *arg)
static void input_handler (int *plterm)
int main (int argc, char *argv[])
void writeUnicode (int fd, const UNICHAR *buf, int count)
 Output an Unicode message to specified file descriptor or to NCURSES window if fd == -1;.
void printUnicode (FILE *outStream, const UNICHAR *buf, int count, int noControl)
 Output an Unicode message to specified output stream if NOCONTROL is true, control characters are converted to printable characters before output.

Variables

static int ncursesFlag = 0
static int ptyFlag = 1
static int debugFlag = 0
static int ltermNumber = -1
static char * debugFunction
static char * ttyDevice
static char * errDevice
static int screenMode = 0
static int topScrollRow
static int botScrollRow
static struct termios
static pthread_t output_handler_thread_ID

Define Documentation

Definition at line 60 of file lterm.c.

#define MAXCOL   4096 /* Maximum columns in line buffer */

Definition at line 79 of file lterm.c.

#define MAXPROMPT   256 /* Maximum length of prompt regexp */

Definition at line 78 of file lterm.c.


Function Documentation

void finish ( int  sig) [static]

Definition at line 352 of file lterm.c.

{
  if (ncursesFlag) {
#ifdef USE_NCURSES
    endwin(); /* Close window */
    if (termScreen != NULL)
      delscreen(termScreen);
#endif
  }

  if (ltermNumber >= 0) {
    /* Close and delete LTERM */
    lterm_delete(ltermNumber);
  }

  if (errDevice != NULL)
    fprintf(stderr, "finished-00: Finished\n");

  exit(0);
}

Here is the call graph for this function:

void input_handler ( int plterm) [static]

Definition at line 452 of file lterm.c.

{
  char ch;
  UNICHAR uch;
  int n_written;

  for (;;) {
    /* Read a character from TTY (raw mode) */
    if (ncursesFlag) {
#ifdef USE_NCURSES
      ch = getch();
      if (ch == '\r')
        ch = '\n';
#endif
    } else {
      ch = getchar();
    }

    /* fprintf(stderr, "input_handler-00: ch=%d\n", ch); */

    if (ch == 0x1D) {
      fprintf(stderr, "input_handler-00: C-] character read; terminating\n");
      break;
    }

    uch = (UNICHAR) ch;
    n_written = lterm_write(*plterm, &uch, 1, LTERM_WRITE_PLAIN_INPUT);

    /* Exit loop if TTY has been closed */
    if (n_written == -2) {
      if (errDevice != NULL)
        fprintf(stderr, "input_handler-00: pseudo-TTY has been closed\n", *plterm);
      break;
    }

    if (n_written < 0) {
      fprintf(stderr, "input_handler: Error %d return from lterm_write\n",
              n_written);
      return;
    }
  }

  /* Close LTERM */
  if (errDevice != NULL)
    fprintf(stderr, "input_handler-00: Closing LTERM %d\n", *plterm);

  /* Close and delete LTERM */
  lterm_delete(*plterm);
  *plterm = -1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int main ( int  argc,
char *  argv[] 
)

Definition at line 123 of file lterm.c.

                                 {
  FILE *inFile, *outFile;
  UNICHAR uregexp[MAXPROMPT+1];
  int argNo, options, processType, retValue;
  int remaining, decoded;
  int messageLevel;
  char *promptStr;
  char **commandArgs;
  char *defaultCommand[] = {(char *)getenv("SHELL"), "-i", NULL};

  /* Process command line arguments */
  ncursesFlag = 0;
  ptyFlag = 1;
  debugFlag = 0;
  processType = LTERM_DETERMINE_PROCESS;
  debugFunction = NULL;
  ttyDevice = NULL;
  errDevice = NULL;
  promptStr = "#$%>?";  /* JUST A LIST OF DELIMITERS AT PRESENT */

  argNo = 1;
  while (argNo < argc) {

    if ((strcmp(argv[argNo],"-h") == 0)||(strcmp(argv[argNo],"-help") == 0)) {
      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]);
      exit(0);

    } else if (strcmp(argv[argNo],"-ncurses") == 0) {
      ncursesFlag = 1;
      argNo++;

    } else if (strcmp(argv[argNo],"-nopty") == 0) {
      ptyFlag = 0;
      argNo++;

    } else if (strcmp(argv[argNo],"-debug") == 0) {
      debugFlag = 1;
      argNo++;

    } else if (strcmp(argv[argNo],"-bash") == 0) {
      processType = LTERM_BASH_PROCESS;
      argNo++;

    } else if (strcmp(argv[argNo],"-tcsh") == 0) {
      processType = LTERM_TCSH_PROCESS;
      argNo++;

    } else if (strcmp(argv[argNo],"-function") == 0) {
      argNo++;
      if (argNo < argc) {
        debugFunction = argv[argNo++];
      }

    } else if (strcmp(argv[argNo],"-tty") == 0) {
      argNo++;
      if (argNo < argc) {
        ttyDevice = argv[argNo++];
      }

    } else if (strcmp(argv[argNo],"-err") == 0) {
      argNo++;
      if (argNo < argc) {
        errDevice = argv[argNo++];
      }

    } else if (strcmp(argv[argNo],"-prompt") == 0) {
      argNo++;
      if (argNo < argc) {
        promptStr = argv[argNo++];
      }

    } else
      break;
  }

  if (argNo < argc) {
    /* Execute specified command */
    commandArgs = argv + argNo;
  } else {
    /* Execute default shell */
    commandArgs = defaultCommand;
  }

  /* Convert prompt string to Unicode */
  retValue = utf8toucs(promptStr, strlen(promptStr), uregexp, MAXPROMPT,
                       0, &remaining, &decoded);
  if ((retValue < 0) || (remaining > 0)) {
    fprintf(stderr, "lterm: Error in decoding prompt string\n");
    exit(1);
  }

  assert(decoded <= MAXPROMPT);
  uregexp[decoded] = U_NUL;

  if (debugFlag) {
    messageLevel = 98;
  } else {
    messageLevel = 1;
  }

  if (errDevice != NULL) {
    /* Redirect debug STDERR output to specified device */
    int errfd = -1;
    if ( (errfd = open(errDevice, O_WRONLY)) == -1)
        perror("lterm");

    if (dup2(errfd, 2) == -1) {
      fprintf(stderr, "lterm: Failed dup2 for specified stderr\n");
      exit(-1);
    }

    fprintf(stderr, "\n\nlterm: Echoing %s output to %s\n",
            argv[0], errDevice);
  }

  signal(SIGINT, finish); /* Interrupt handler */

  if (ncursesFlag) {
    /* NCURSES mode */

#ifdef USE_NCURSES
    if (ttyDevice == NULL) {
      /* Initialize screen on controlling TTY */
      initscr();

    } else {
      /* Initialize screen on specified TTY */
      if (errDevice != NULL)
        fprintf(stderr, "lterm-00: Opening xterm %s\n", ttyDevice);
      inFile = fopen( ttyDevice, "r");
      outFile = fopen( ttyDevice, "w");
      termScreen = newterm("xterm", outFile, inFile);
      set_term(termScreen);
    }

    /* NCURSES screen settings */
    cbreak();                 /* set terminal to raw (non-canonical) mode */
    noecho();                 /* Disable terminal echo */
    nonl();                   /* Do not translate newline */
    intrflush(stdscr, FALSE); /* Flush input on interrupt */
    keypad(stdscr, TRUE);     /* Enable user keypad */

#ifdef NCURSES_MOUSE_VERSION
    mousemask(BUTTON1_CLICKED, NULL); /* Capture Button1 click events */
#endif

    clear(); /* Clear screen */
#endif  /* USE_NCURSES */

  } else {
    /* XTERM mode */

    /* Get terminal attributes */
    if (tcgetattr(0, &tios) == -1) {
      fprintf(stderr, "lterm: Failed to get TTY attributes\n");
      exit(-1);
    }

    /* Disable signals, canonical mode processing, and echo  */
    tios.c_lflag &= ~(ISIG | ICANON | ECHO );

    /* set MIN=1 and TIME=0 */
    tios.c_cc[VMIN] = 1;
    tios.c_cc[VTIME] = 0;

    /* Set terminal attributes */
    if (tcsetattr(0, TCSAFLUSH, &tios) == -1) {
      fprintf(stderr, "lterm: Failed to set TTY attributes\n");
      exit(-1);
    }

  }

  /* Initialize LTERM operations */
  lterm_init(0);

  if (errDevice != NULL) {
    tlog_message("lterm-00: Testing tlog_message\n");
    tlog_warning("lterm-00: Testing tlog_warning\n");
    fprintf(stderr, "lterm-00: ");
    tlog_unichar(uregexp, ucslen(uregexp));
    tlog_set_level(LTERM_TLOG_MODULE, messageLevel, debugFunction);
  }

  if (errDevice != NULL)
    fprintf(stderr, "lintest-00: Opening LTERM to execute %s\n", commandArgs[0]);

  options = 0;
  if (!ptyFlag) options |= LTERM_NOPTY_FLAG;

  ltermNumber = lterm_new();
  retValue = lterm_open(ltermNumber, commandArgs, NULL, NULL, uregexp,
                        options, processType,
                        24, 80, 0, 0,
                        NULL, NULL);
  if (retValue < 0) {
    fprintf(stderr, "lterm: Error %d in opening LTERM\n", retValue);
    exit(1);
  }

  /* Create output handler thread */
  retValue = pthread_create(&output_handler_thread_ID,  NULL,
                            output_handler, (void *) &ltermNumber);
  if (retValue != 0) {
    fprintf(stderr, "lterm: Error %d in creating OUTPUT_HANDLER thread\n",
                     retValue);
    finish(0);
  }

  if (errDevice != NULL)
    fprintf(stderr, "lterm-00: Created OUTPUT_HANDLER thread\n");

  /* Process input */
  input_handler(&ltermNumber);

  /* Join output handler thread */
  if (errDevice != NULL)
    fprintf(stderr, "lterm-00: Joining OUTPUT_HANDLER thread\n");

  retValue = pthread_join(output_handler_thread_ID,  NULL);
  if (retValue != 0) {
    fprintf(stderr, "lterm: Error %d in joining OUTPUT_HANDLER thread\n",
                     retValue);
    finish(0);
  }

  finish(0);
}

Here is the call graph for this function:

void * output_handler ( void arg) [static]

Definition at line 503 of file lterm.c.

{
  int *plterm = (int *) arg;
  int timeout = -1;
  UNICHAR buf[MAXCOL];
  UNISTYLE style[MAXCOL];
  int n_read, opcodes, opvals, buf_row, buf_col, cursor_row, cursor_col;
  int xmax, ymax, x, y, c;
#ifdef USE_NCURSES
  MEVENT mev;
#endif

  if (errDevice != NULL)
    fprintf(stderr, "output_handler-00: thread ID = %d, LTERM=%d\n",
                    pthread_self(), *plterm);

  /* Get screen size */
  if (ncursesFlag) {
#ifdef USE_NCURSES
    getmaxyx(stdscr, ymax, xmax);
#endif

  } else {
    ymax = 24;
    xmax = 80;
  }

  if (errDevice != NULL)
    fprintf(stderr, "output_handler-00: screen xmax = %d, ymax = %d\n",
            xmax,ymax);

  for (;;) {
    n_read = lterm_read(*plterm, timeout, buf, MAXCOL,
                        style, &opcodes, &opvals,
                        &buf_row, &buf_col, &cursor_row, &cursor_col);

    if (n_read == -1) {
      fprintf(stderr, "output_handler: Error %d return from lterm_read\n",
                      n_read);
      return NULL;
    }

    /* Exit loop if TTY has been closed;
     * leave it to input handler to close the LTERM.
     */
    if (n_read == -2) {
      if (errDevice != NULL)
        fprintf(stderr, "output_handler: pseudo-TTY has been closed\n");
      break;
    }

    if (debugFlag) {
      fprintf(stderr, "output_handler-00: n_read=%d, opcodes=%x, opvals=%d, buf_row/col=%d/%d, cursor_row/col=%d/%d\n",
            n_read, opcodes, opvals, buf_row, buf_col, cursor_row, cursor_col);
      fprintf(stderr, "output_handler-00: U(%d): ", n_read);
      printUnicode(stderr, buf, n_read, 1);
      fprintf(stderr, "\n");
    }

    if (opcodes & LTERM_STREAMDATA_CODE) {
      /* Stream data */
      if (debugFlag)
        fprintf(stderr, "output_handler-00: STREAMDATA\n");


    } else if (opcodes & LTERM_SCREENDATA_CODE) {
      /* Screen data */

      if (!screenMode) {
        screenMode = 1;
        topScrollRow = ymax-1;
        botScrollRow = 0;
      }

      if (debugFlag)
        fprintf(stderr, "output_handler-00: SCREENDATA, topScrollRow=%d, botScrollRow=%d\n", topScrollRow, botScrollRow);

      if (ncursesFlag) {
        /* NCURSES mode */

#ifdef USE_NCURSES
        if (opcodes & LTERM_CLEAR_CODE) {
          clear();

        } else if (opcodes & LTERM_INSERT_CODE) {
          if ((botScrollRow > 0) && (opvals > 0)) {
            move(ymax-botScrollRow-opvals, 0);
            insdelln(-opvals);
          }

          move(ymax-1-buf_row, 0);
          insdelln(opvals);

        } else if (opcodes & LTERM_DELETE_CODE) {

          move(ymax-1-buf_row, 0);
          insdelln(-opvals);

          if ((botScrollRow > 0) && (opvals > 0)) {
            move(ymax-botScrollRow-opvals, 0);
            insdelln(opvals);
          }

        } else if (opcodes & LTERM_SCROLL_CODE) {
          topScrollRow = opvals;
          botScrollRow = buf_row;

        } else if (opcodes & LTERM_OUTPUT_CODE) {
          /* Data available for display */
          move(ymax-1-buf_row, buf_col);
          clrtoeol();

          if (n_read > 0) {
            if (style[0] != LTERM_STDOUT_STYLE)
              attr_on(A_REVERSE, NULL);

            writeUnicode(-1, buf, n_read);

            if (style[0] != LTERM_STDOUT_STYLE)
              attr_off(A_REVERSE, NULL);
          }
        }

        /* Position cursor */
        move(ymax-1-cursor_row, cursor_col);

        refresh();
#endif  /* USE_NCURSES */

      } else {
        /* XTERM MODE */
        char esc_seq[21];

        if (opcodes & LTERM_CLEAR_CODE) {
          /* Clear screen */
          write(1, "\033[H\033[2J", 7);

        } else if (opcodes & LTERM_INSERT_CODE) {
          /* Insert lines */
          sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
          write(1, esc_seq, strlen(esc_seq));

          sprintf(esc_seq, "\033[%dL", opvals);
          write(1, esc_seq, strlen(esc_seq));

        } else if (opcodes & LTERM_DELETE_CODE) {
          /* Delete lines */
          sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
          write(1, esc_seq, strlen(esc_seq));

          sprintf(esc_seq, "\033[%dM", opvals);
          write(1, esc_seq, strlen(esc_seq));

        } else if (opcodes & LTERM_SCROLL_CODE) {
          /* Set scrolling region */
          sprintf(esc_seq, "\033[%d;%dr", ymax-opvals, ymax-buf_row);
          write(1, esc_seq, strlen(esc_seq));

        } else if (opcodes & LTERM_OUTPUT_CODE) {
          /* Data available for display */
          sprintf(esc_seq, "\033[%d;%dH", ymax-buf_row, buf_col+1);
          write(1, esc_seq, strlen(esc_seq));

          if (n_read > 0) {
            if (style[0] != LTERM_STDOUT_STYLE)
              write(1, "\033[7m", 4);

            writeUnicode(1, buf, n_read);

            if (style[0] != LTERM_STDOUT_STYLE)
              write(1, "\033[27m", 5);
          }
        }

        sprintf(esc_seq, "\033[%d;%dH", ymax-cursor_row, cursor_col+1);
        write(1, esc_seq, strlen(esc_seq));
      }

    } else if (opcodes & LTERM_LINEDATA_CODE) {
      /* Line data */
      if (debugFlag)
        fprintf(stderr, "output_handler-00: LINEDATA\n");

      if (screenMode)
        screenMode = 0;

      if (ncursesFlag) {
        /* NCURSES mode */

#ifdef USE_NCURSES
        /* Move cursor to bottom of screen, clear line and display line */
        move(ymax-1,0);
        clrtoeol();
        if (n_read > 0)
          writeUnicode(-1, buf, n_read);
        move(ymax-1,cursor_col);

        if (opcodes & LTERM_NEWLINE_CODE) {
          move(0,0);
          insdelln(-1);
          move(ymax-1,0);
        }

        refresh();
#endif  /* USE_NCURSES */

      } else {
        /* Screen mode */
        int j;

        /* Clear line */
        write(1, "\033[2K", 4);
        write(1, "\r", 1);

        if (opcodes & LTERM_META_CODE)
          write(1, "META", 4);

        if (n_read > 0)
          writeUnicode(1, buf, n_read);

        for (j=0; j< (n_read-cursor_col); j++)
          write(1, "\033[D", 3);

        if (opcodes & LTERM_BELL_CODE)
          write(1, "\007", 1);

        if (opcodes & LTERM_CLEAR_CODE)
          write(1, "\033[H\033[2J", 7);

        if (opcodes & LTERM_NEWLINE_CODE)
          write(1, "\n", 1);
      }

    } else if (opcodes != 0) {
      fprintf(stderr, "output_handler: invalid opcodes %x\n", opcodes);
    }
  }

  return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void printUnicode ( FILE outStream,
const UNICHAR buf,
int  count,
int  noControl 
)

Output an Unicode message to specified output stream if NOCONTROL is true, control characters are converted to printable characters before output.

Definition at line 417 of file lterm.c.

{
  char str[MAXCOL];
  int j, k;

  k = 0;
  for (j=0; j<count; j++) {

    if (k >= MAXCOL-4) {
      if (MAXCOL >= 4) {
        str[MAXCOL-4] = '.';
        str[MAXCOL-3] = '.';
        str[MAXCOL-2] = '.';
      }
      k = MAXCOL-1;
      break;
    }

    if (!noControl && ((buf[j] < U_SPACE) || (buf[j] == U_DEL)) ) {
      /* Control character */
      str[k++] = U_CARET;
      str[k++] = buf[j]+U_ATSIGN;
    } else {
      /* Printable character */
      /* TEMPORARY IMPLEMENTATION: just truncate Unicode to byte characters */
      str[k++] = buf[j];
    }
  }

  /* Insert terminating null character and display string */
  str[k++] = '\0';
  fprintf(outStream, "%s\n", str);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void writeUnicode ( int  fd,
const UNICHAR buf,
int  count 
)

Output an Unicode message to specified file descriptor or to NCURSES window if fd == -1;.

Definition at line 376 of file lterm.c.

{
  char str[MAXCOL];
  int j, k;

  k = 0;
  for (j=0; j<count; j++) {

    if (k >= MAXCOL-4) {
      if (MAXCOL >= 4) {
        str[MAXCOL-4] = '.';
        str[MAXCOL-3] = '.';
        str[MAXCOL-2] = '.';
      }
      k = MAXCOL-1;
      break;
    }

    /* TEMPORARY IMPLEMENTATION: just truncate Unicode to byte characters */
    str[k++] = buf[j];
  }

  if (k == 0) return;

  if (fd >= 0) {
    if (write(fd, str, k) != k) {
      fprintf(stderr, "writeUnicode: Error in writing to FD %d\n", fd);
      exit(-1);
    }
  } else {
#ifdef USE_NCURSES
    addnstr(str, k);
#endif
  }
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

int botScrollRow [static]

Definition at line 108 of file lterm.c.

int debugFlag = 0 [static]

Definition at line 101 of file lterm.c.

char* debugFunction [static]

Definition at line 103 of file lterm.c.

char* errDevice [static]

Definition at line 105 of file lterm.c.

int ltermNumber = -1 [static]

Definition at line 102 of file lterm.c.

int ncursesFlag = 0 [static]

Definition at line 99 of file lterm.c.

Definition at line 113 of file lterm.c.

int ptyFlag = 1 [static]

Definition at line 100 of file lterm.c.

int screenMode = 0 [static]

Definition at line 107 of file lterm.c.

struct termios [static]

Definition at line 110 of file lterm.c.

int topScrollRow [static]

Definition at line 108 of file lterm.c.

char* ttyDevice [static]

Definition at line 104 of file lterm.c.