Logo Search packages:      
Sourcecode: ncurses version File versions

output.c

/*
** Copyright (C) 1991, 1997 Free Software Foundation, Inc.
** 
** This file is part of TACK.
** 
** TACK is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2, or (at your option)
** any later version.
** 
** TACK is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
** 
** You should have received a copy of the GNU General Public License
** along with TACK; see the file COPYING.  If not, write to
** the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
** Boston, MA 02111-1307, USA.
*/
/* screen formatting and I/O utility functions */

#include <tack.h>
#include <time.h>

MODULE_ID("$Id: output.c,v 1.8 2003/10/25 20:43:43 tom Exp $")

/* globals */
long char_sent;               /* number of characters sent */
int char_count;               /* counts characters */
int line_count;               /* counts line feeds */
int expand_chars;       /* length of expand() string */
int replace_mode;       /* used to output replace mode padding */
int can_go_home;        /* TRUE if we can fashion a home command */
int can_clear_screen;         /* TRUE if we can somehow clear the screen */
int raw_characters_sent;      /* Total output characters */
int log_count;                /* Number of characters on a log line */

/* translate mode default strings */
#define TM_carriage_return    TM_string[0].value
#define TM_cursor_down        TM_string[1].value
#define TM_scroll_forward     TM_string[2].value
#define TM_newline            TM_string[3].value
#define TM_cursor_left        TM_string[4].value
#define TM_bell               TM_string[5].value
#define TM_form_feed          TM_string[6].value
#define TM_tab                TM_string[7].value

struct default_string_list TM_string[TM_last] = {
      {"cr", "\r", 0},
      {"cud1", "\n", 0},
      {"ind", "\n", 0},
      {"nel", "\r\n", 0},
      {"cub1", "\b", 0},
      {"bel", "\007", 0},
      {"ff", "\f", 0},
      {"ht", "\t", 0}
};

static const char *c0[32] = {
      "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK",
      "BEL", "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
      "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
      "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US"
};

static const char *c1[32] = {
      "", "", "", "", "IND", "NEL", "SSA", "ESA",
      "HTS", "HTJ", "VTS", "PLD", "PLU", "RI", "SS2", "SS3",
      "DCS", "PU1", "PU2", "STS", "CCH", "MW", "SPA", "EPA",
      "", "", "", "CSI", "ST", "OSC", "PM", "APC"
};

int
getnext(int mask)
{                       /* get the next character without scan mode
                           conversion */
      int ch;
      unsigned char buf;

      tc_putp(req_for_input);
      fflush(stdout);
      if (nodelay_read)
            while (1) {
                  ch = read(fileno(stdin), &buf, 1);
                  if (ch == -1)
                        return EOF;
                  if (ch == 1)
                        return buf;
            }
      ch = getchar();
      if (ch == EOF)
            return EOF;
      return ch & mask;
}


int
getchp(int mask)
{                       /* read a character with scan mode conversion */
      if (scan_mode) {
            tc_putp(req_for_input);
            fflush(stdout);
            return scan_key();
      } else
            return getnext(mask);
}

/*
**    tc_putch(c)
**
**    Output one character
*/
int
tc_putch(int c)
{
      char_sent++;
      raw_characters_sent++;
      putchar(c);
      if ((raw_characters_sent & 31) == 31) {
            fflush(stdout);
      }
      if (log_fp) {
            /* terminal output logging */
            c = UChar(c);
            if (c < 32) {
                  fprintf(log_fp, "<%s>", c0[c]);
                  log_count += 5;
            } else
            if (c < 127) {
                  fprintf(log_fp, "%c", c);
                  log_count += 1;
            } else {
                  fprintf(log_fp, "<%02x>", c);
                  log_count += 4;
            }
            if (c == '\n' || log_count >= 80) {
                  fprintf(log_fp, "\n");
                  log_count = 0;
            }
      }
      return (c);
}

/*
**    tt_tputs(string, reps)
**
**    Output a string with tputs() translation.
**    Use this function inside timing tests.
*/
void
tt_tputs(const char *string, int reps)
{
      int i;

      if (string) {
            for (i = 0; i < TT_MAX; i++) {
                  if (i >= ttp) {
                        tt_cap[i] = string;
                        tt_affected[i] = reps;
                        tt_count[i] = 1;
                        tt_delay[i] = msec_cost(string, reps);
                        ttp++;
                        break;
                  }
                  if (string == tt_cap[i] && reps == tt_affected[i]) {
                        tt_count[i]++;
                        tt_delay_used += tt_delay[i];
                        break;
                  }
            }
            (void) tputs(string, reps, tc_putch);
      }
}

/*
**    tt_putp(string)
**
**    Output a string with tputs() translation.
**    Use this function inside timing tests.
*/
void
tt_putp(const char *string)
{
      tt_tputs(string, 1);
}

/*
**    tt_putparm(string, reps, arg1, arg2)
**
**    Send tt_tputs(tparm(string, args1, arg2), reps)
**    Use this function inside timing tests.
*/
void
tt_putparm(
      NCURSES_CONST char *string,
      int reps,
      int arg1,
      int arg2)
{
      int i;

      if (string) {
            for (i = 0; i < TT_MAX; i++) {
                  if (i >= ttp) {
                        tt_cap[i] = string;
                        tt_affected[i] = reps;
                        tt_count[i] = 1;
                        tt_delay[i] = msec_cost(string, reps);
                        ttp++;
                        break;
                  }
                  if (string == tt_cap[i] && reps == tt_affected[i]) {
                        tt_count[i]++;
                        tt_delay_used += tt_delay[i];
                        break;
                  }
            }
            (void) tputs(tparm((NCURSES_CONST char *)string, arg1, arg2), reps, tc_putch);
      }
}

/*
**    tc_putp(string)
**
**    Output a string with tputs() translation.
**    Use this function instead of putp() so we can track
**    the actual number of characters sent.
*/
int
tc_putp(const char *string)
{
      return tputs(string, 1, tc_putch);
}


void
put_this(int c)
{                       /* output one character (with padding) */
      tc_putch(c);
      if (char_padding && replace_mode)
            tt_putp(char_padding);
}


void
put_cr(void)
{
      if (translate_mode && carriage_return) {
            tt_putp(carriage_return);
      } else {
            tt_putp(TM_carriage_return);
      }
      char_count = 0;
}


void
put_lf(void)
{                       /* send a linefeed (only works in RAW or
                           CBREAK mode) */
      if (translate_mode && cursor_down) {
            tt_putp(cursor_down);
      } else {
            tt_putp(TM_cursor_down);
      }
      line_count++;
}


void
put_ind(void)
{                       /* scroll forward (only works in RAW or
                           CBREAK mode) */
      if (translate_mode && scroll_forward) {
            tt_putp(scroll_forward);
      } else {
            tt_putp(TM_scroll_forward);
      }
      line_count++;
}

/*
**    put_crlf()
**
**    Send (nel)  or <cr> <lf>
*/
void
put_crlf(void)
{
      if (translate_mode && newline) {
            tt_putp(newline);
      } else {
            tt_putp(TM_newline);
      }
      char_count = 0;
      line_count++;
}

/*
**    put_new_lines(count)
**
**    Send a number of newlines. (nel)
*/
void
put_newlines(int n)
{
      while (n-- > 0) {
            put_crlf();
      }
}

/*
**    putchp(character)
**
**    Send one character to the terminal.
**    This function does translation of control characters.
*/
void
putchp(int c)
{
      switch (c) {
      case '\b':
            if (translate_mode && cursor_left) {
                  tt_putp(cursor_left);
            } else {
                  tt_putp(TM_cursor_left);
            }
            char_count--;
            break;
      case 7:
            if (translate_mode && bell) {
                  tt_putp(bell);
            } else {
                  tt_putp(TM_bell);
            }
            break;
      case '\f':
            if (translate_mode && form_feed) {
                  tt_putp(form_feed);
            } else {
                  tt_putp(TM_form_feed);
            }
            char_count = 0;
            line_count++;
            break;
      case '\n':
            put_crlf();
            break;
      case '\r':
            put_cr();
            break;
      case '\t':
            if (translate_mode && tab) {
                  tt_putp(tab);
            } else {
                  tt_putp(TM_tab);
            }
            char_count = ((char_count / 8) + 1) * 8;
            break;
      default:
            put_this(c);
            char_count++;
            break;
      }
}


void
put_str(const char *s)
{                       /* send the string to the terminal */
      for (; *s; putchp(*s++));
}


void
putln(const char *s)
{                       /* output a string followed by a CR LF */
      for (; *s; putchp(*s++));
      put_crlf();
}


void
put_columns(const char *s, int len, int w)
{                       /* put out s in column format */
      int l;

      if (char_count + w > columns) {
            put_crlf();
      }
      l = char_count % w;
      if (l) {
            while (l < w) {
                  putchp(' ');
                  l++;
            }
      }
      if (char_count && char_count + len >= columns) {
            put_crlf();
      }
      l = char_count;
      put_str(s);
      char_count = l + len;
}


/*
**    ptext(string)
**
**    Output a string but do not assume the terminal will wrap to a
**    new line.  Break the line at a word boundary then send a CR LF.
**    This is more esthetic on 40 column terminals.
*/
void
ptext(const char *s)
{
      const char *t;

      while (*s) {
            for (t = s + 1; *t > ' '; t++);
            if ((char_count != 0) && ((t - s) + char_count >= columns)) {
                  put_crlf();
                  while (*s == ' ')
                        s++;
            }
            while (s < t) {
                  putchp(*s++);
            }
      }
}


void
put_dec(char *f, int i)
{                       /* print a line with a decimal number in it */
      char tm[128];

      sprintf(tm, f, i / 10, i % 10);
      ptext(tm);
}


void
three_digit(char *tx, int i)
{                       /* convert the decimal number to a string of
                           at least 3 digits */
      if (i < 1000)
            sprintf(tx, "%d.%d", i / 10, i % 10);
      else
            sprintf(tx, "%d", i / 10);
}


void
ptextln(const char *s)
{                       /* print the text using ptext() then add a CR
                           LF */
      ptext(s);
      put_crlf();
}


static void
expand_one(int ch, char **v)
{                       /* expand one character */
      char *t = *v;

      if (ch & 0x80) {  /* dump it in octal (yuck) */
            *t++ = '\\';
            *t++ = '0' + ((ch >> 6) & 3);
            *t++ = '0' + ((ch >> 3) & 7);
            *t++ = '0' + (ch & 7);
            expand_chars += 4;
      } else if (ch == 127) { /* DEL */
            *t++ = '^';
            *t++ = '?';
            expand_chars += 2;
      } else if (ch >= ' ') {
            *t++ = ch;
            expand_chars++;
      } else {    /* control characters */
            *t++ = '^';
            *t++ = ch + '@';
            expand_chars += 2;
      }
      *v = t;
}


char *
expand(const char *s)
{                       /* convert the string to printable form */
      static char buf[4096];
      char *t, *v;
      int ch;

      if (magic_cookie_glitch <= 0 && exit_attribute_mode) {
            v = enter_reverse_mode;
      } else {
            v = NULL;
      }
      expand_chars = 0;
      t = buf;
      if (s) {
            for (; (ch = *s); s++) {
                  if ((ch & 0x80) && v) { /* print it in reverse video
                                       mode */
                        strcpy(t, liberated(tparm(v)));
                        for (; *t; t++);
                        expand_one(ch & 0x7f, &t);
                        strcpy(t, liberated(tparm(exit_attribute_mode)));
                        for (; *t; t++);
                  } else {
                        expand_one(ch, &t);
                  }
            }
      }
      *t = '\0';
      return buf;
}


char *
print_expand(char *s)
{                       /* convert the string to 7-bit printable form */
      static char buf[4096];
      char *t;
      int ch;

      expand_chars = 0;
      t = buf;
      if (s) {
            for (; (ch = *s); s++) {
                  expand_one(ch, &t);
            }
      }
      *t = '\0';
      return buf;
}


char *
expand_to(char *s, int l)
{                       /* expand s to length l */
      char *t;

      for (s = t = expand(s); *t; t++);
      for (; expand_chars < l; expand_chars++) {
            *t++ = ' ';
      }
      *t = '\0';
      return s;
}


char *
hex_expand_to(char *s, int l)
{                       /* expand s to length l in hex */
      static char buf[4096];
      char *t;

      for (t = buf; *s; s++) {
            sprintf(t, "%02X ", UChar(*s));
            t += 3;
            if (t - buf > (int) sizeof(buf) - 4) {
                  break;
            }
      }
      for (; t - buf < l;) {
            *t++ = ' ';
      }
      *t = '\0';
      expand_chars = t - buf;
      return buf;
}


char *
expand_command(const char *c)
{                       /* expand an ANSI escape sequence */
      static char buf[256];
      int i, j, ch;
      char *s;

      s = buf;
      for (i = FALSE; (ch = UChar(*c)) != 0; c++) {
            if (i) {
                  *s++ = ' ';
            }
            i = TRUE;
            if (ch < 32) {
                  j = UChar(c[1]);
                  if (ch == '\033' && j >= '@' && j <= '_') {
                        ch = j - '@';
                        c++;
                        for (j = 0; (*s = c1[ch][j++]); s++);
                  } else
                        for (j = 0; (*s = c0[ch][j++]); s++);
            } else {
                  *s++ = ch;
                  j = UChar(c[1]);
                  if (ch >= '0' && ch <= '9' &&
                        j >= '0' && j <= '9') {
                        i = FALSE;
                  }
            }
      }
      *s = '\0';
      return buf;
}

/*
**    go_home()
**
**    Move the cursor to the home position
*/
void
go_home(void)
{
      int i;

      if (cursor_home)
            tt_putp(cursor_home);
      else if (cursor_address)
            tt_putparm(cursor_address, lines, 0, 0);
      else if (row_address) { /* use (vpa) */
            put_cr();
            tt_putparm(row_address, 1, 0, 0);
      } else if (cursor_up && cursor_to_ll) {
            tt_putp(cursor_to_ll);
            for (i = 1; i < lines; i++) {
                  tt_putp(cursor_up);
            }
      } else {
            can_go_home = FALSE;
            return;
      }
      char_count = line_count = 0;
      can_go_home = TRUE;
}


void
home_down(void)
{                       /* move the cursor to the lower left hand
                           corner */
      int i;

      if (cursor_to_ll)
            tt_putp(cursor_to_ll);
      else if (cursor_address)
            tt_putparm(cursor_address, lines, lines - 1, 0);
      else if (row_address) { /* use (vpa) */
            put_cr();
            tt_putparm(row_address, 1, lines - 1, 0);
      } else if (cursor_down && cursor_home) {
            tt_putp(cursor_home);
            for (i = 1; i < lines; i++)
                  tt_putp(cursor_down);
      } else
            return;
      char_count = 0;
      line_count = lines - 1;
}


void
put_clear(void)
{                       /* clear the screen */
      int i;

      if (clear_screen)
            tt_tputs(clear_screen, lines);
      else if (clr_eos && can_go_home) {
            go_home();
            tt_tputs(clr_eos, lines);
      } else if (scroll_forward && !over_strike && (can_go_home || cursor_up)) {
            /* clear the screen by scrolling */
            put_cr();
            if (cursor_to_ll) {
                  tt_putp(cursor_to_ll);
            } else if (cursor_address) {
                  tt_putparm(cursor_address, lines, lines - 1, 0);
            } else if (row_address) {
                  tt_putparm(row_address, 1, lines - 1, 0);
            } else {
                  for (i = 1; i < lines; i++) {
                        tt_putp(scroll_forward);
                  }
            }
            for (i = 1; i < lines; i++) {
                  tt_putp(scroll_forward);
            }
            if (can_go_home) {
                  go_home();
            } else {
                  for (i = 1; i < lines; i++) {
                        tt_putp(cursor_up);
                  }
            }
      } else {
            can_clear_screen = FALSE;
            return;
      }
      char_count = line_count = 0;
      can_clear_screen = TRUE;
}

/*
**    wait_here()
**
**    read one character from the input stream
**    If the terminal is not in RAW mode then this function will
**    wait for a <cr> or <lf>.
*/
int
wait_here(void)
{
      char ch, cc[64];
      char message[16];
      int i, j;

      for (i = 0; i < (int) sizeof(cc); i++) {
            cc[i] = ch = getchp(STRIP_PARITY);
            if (ch == '\r' || ch == '\n') {
                  put_crlf();
                  char_sent = 0;
                  return cc[i ? i - 1 : 0];
            }
            if (ch >= ' ') {
                  if (stty_query(TTY_CHAR_MODE)) {
                        put_crlf();
                        char_sent = 0;
                        return ch;
                  }
                  continue;
            }
            if (ch == 023) {  /* Control S */
                  /* ignore control S, but tell me about it */
                  while (ch == 023 || ch == 021) {
                        ch = getchp(STRIP_PARITY);
                        if (i < (int) sizeof(cc))
                              cc[++i] = ch;
                  }
                  put_str("\nThe terminal sent a ^S -");
                  for (j = 0; j <= i; j++) {
                        sprintf(message, " %02X", cc[j] & 0xFF);
                        put_str(message);
                  }
                  put_crlf();
                  i = -1;
            } else if (ch != 021) { /* Not Control Q */
                  /* could be abort character */
                  spin_flush();
                  if (tty_can_sync == SYNC_TESTED) {
                        (void) tty_sync_error();
                  } else {
                        put_str("\n? ");
                  }
            }
      }
      return '?';
}


/*
**    read_string(buffer, length)
**
**    Read a string of characters from the input stream.
*/
void
read_string(
      char *buf,
      int length)
{
      int ch, i;

      for (i = 0; i < length - 1; ) {
            ch = getchp(STRIP_PARITY);
            if (ch == '\r' || ch == '\n') {
                  break;
            }
            if (ch == '\b' || ch == 127) {
                  if (i) {
                        putchp('\b');
                        putchp(' ');
                        putchp('\b');
                        i--;
                  }
            } else {
                  buf[i++] = ch;
                  putchp(ch);
            }
      }
      buf[i] = '\0';
      put_crlf();
      char_sent = 0;
}

/*
**    maybe_wait(lines)
**
**    wait if near the end of the screen, then clear screen
*/
void 
maybe_wait(int n)
{
      if (line_count + n >= lines) {
            if (char_sent != 0) {
                  ptext("Go? ");
                  (void) wait_here();
            }
            put_clear();
      } else {
            put_crlf();
      }
}

Generated by  Doxygen 1.6.0   Back to index