Ejemplo n.º 1
0
static void do_tex_insert_quote(EditState *s)
{
    int offset_bol, len, offset1;
    unsigned int buf[MAX_BUF_SIZE];
    int p;

    offset_bol = eb_goto_bol(s->b, s->offset);
    offset1 = offset_bol;
    len = eb_get_line(s->b, buf, MAX_BUF_SIZE - 1, &offset1);
    p = s->offset - offset_bol;

    if(p >= 1 && buf[p-1] == '\"') {
        eb_insert(s->b, s->offset, (unsigned char *)"\"", 1);
        s->offset++;
    } else if(p >= 2 && (buf[p-1] == '`' || buf[p-1] == '\'') &&
              buf[p-1] == buf[p-2])
    {
        eb_delete(s->b, s->offset - 2, 2);
        eb_insert(s->b, s->offset, (unsigned char *)"\"", 1);
        s->offset++;
    } else {
        if(p == 0 || buf[p-1] == ' ') {
            eb_insert(s->b, s->offset, (unsigned char *)"``", 2);
            s->offset += 2;
        } else {
            eb_insert(s->b, s->offset, (unsigned char *)"''", 2);
            s->offset += 2;
        }
    }
}
Ejemplo n.º 2
0
static void rectangle_cut(EditState *s)
{
	int line, col, start_line, i, loff;
	eb_get_pos(s->b, &start_line, &col, s->b->mark);
	eb_get_pos(s->b, &line, &col, s->offset);

	for (i = start_line; i <= line; i++) {
		loff = eb_goto_pos(s->b, i, 0);
		if (eb_is_empty_line(s->b, loff))
			continue;
		eb_delete(s->b, loff, col);
	}
	s->region_style = 0;
	put_status(s, "Rectangle cut done on line %d to line %d\n",
		   start_line, line);
}
Ejemplo n.º 3
0
static void do_org_insert_heading(EditState *s, int flags)
{
    int offset, offset0, offset1, level = 1;

    if (check_read_only(s))
        return;

    offset = org_find_heading(s, s->offset, &level, 1);
    offset0 = eb_goto_bol(s->b, s->offset);
    offset1 = eb_goto_eol(s->b, s->offset);

    /* if at beginning of heading line, insert sibling heading before,
     * if in the middle of a heading line, split the heading,
     * otherwise, make the current line a heading line at current level.
     */
    if (flags & 2) {
        /* respect-content: insert heading at end of subtree */
        offset = org_next_heading(s, offset, level, NULL);
        eb_insert_uchar(s->b, offset, '\n');
        eb_insert_uchar(s->b, offset, '\n');
    } else
    if (s->offset <= offset + level + 1) {
        eb_insert_uchar(s->b, offset, '\n');
    } else
    if (offset == offset0 || offset == offset1) {
        offset = s->offset;
        offset += eb_insert_uchar(s->b, offset, '\n');
    } else {
        offset = offset0;
    }        
    offset1 = offset;
    while (eb_match_uchar(s->b, offset1, ' ', &offset1))
        continue;
    eb_delete(s->b, offset, offset1 - offset);

    while (level-- > 0) {
        offset += eb_insert_uchar(s->b, offset, '*');
    }
    offset += eb_insert_uchar(s->b, offset, ' ');
    s->offset = eb_goto_eol(s->b, offset);
    if (flags & 1) {
        /* insert-todo-heading */
        do_org_todo(s);
    }
}
Ejemplo n.º 4
0
static void do_org_move_subtree(EditState *s, int dir)
{
    int offset, offset1, offset2, level, level1, level2, size;
    EditBuffer *b1;

    if (check_read_only(s))
        return;

    if (!org_is_header_line(s, s->offset)) {
        put_status(s, "Not on header line");
        return;
    }

    offset = org_find_heading(s, s->offset, &level, 0);
    if (offset < 0)
        return;

    offset1 = org_next_heading(s, offset, level, &level1);
    size = offset1 - offset;

    if (dir < 0) {
        offset2 = org_prev_heading(s, offset, level, &level2);
        if (level2 < level) {
            put_status(s, "Cannot move substree");
            return;
        }
    } else {
        if (offset1 == s->b->total_size || level1 < level) {
            put_status(s, "Cannot move substree");
            return;
        }
        offset2 = org_next_heading(s, offset1, level, &level2);
    }
    b1 = eb_new("*tmp*", BF_SYSTEM | (s->b->flags & BF_STYLES));
    eb_set_charset(b1, s->b->charset, s->b->eol_type);
    eb_insert_buffer_convert(b1, 0, s->b, offset, size);
    eb_delete(s->b, offset, size);
    if (offset2 > offset)
        offset2 -= size;
    eb_insert_buffer_convert(s->b, offset2, b1, 0, b1->total_size);
    eb_free(&b1);
    s->offset = offset2;
}
Ejemplo n.º 5
0
Archivo: shell.c Proyecto: kjk/qemacs
/* modify the color according to the current one (may be incorrect if
   we are editing because we should write default color) */
static void shell_color_callback(EditBuffer *b,
                                 void *opaque,
                                 enum LogOperation op,
                                 int offset,
                                 int size)
{
    ShellState *s = opaque;
    unsigned char buf[32];
    int len;

    switch (op) {
    case LOGOP_WRITE:
        while (size > 0) {
            len = size;
            if (len > (int)sizeof(buf))
                len = (int)sizeof(buf);
            memset(buf, s->color, len);
            eb_write(s->b_color, offset, buf, len);
            size -= len;
            offset += len;
        }
        break;
    case LOGOP_INSERT:
        while (size > 0) {
            len = size;
            if (len > (int)sizeof(buf))
                len = (int)sizeof(buf);
            memset(buf, s->color, len);
            eb_insert(s->b_color, offset, buf, len);
            size -= len;
        }
        break;
    case LOGOP_DELETE:
        eb_delete(s->b_color, offset, size);
        break;
    default:
        break;
    }
}
Ejemplo n.º 6
0
void eb_free(EditBuffer *b)
{
    QEmacsState *qs = &qe_state;
    EditBuffer **pb;
    EditBufferCallbackList *l, *l1;

    /* call user defined close */
    if (b->close)
        b->close(b);

    /* free each callback */
    for (l = b->first_callback; l != NULL;) {
        l1 = l->next;
        free(l);
        l = l1;
    }
    b->first_callback = NULL;

    b->save_log = 0;
    eb_delete(b, 0, b->total_size);
    log_reset(b);

    /* suppress mmap file handle */
    if (b->file_handle > 0) {
        close(b->file_handle);
    }

    /* suppress from buffer list */
    pb = &qs->first_buffer;
    while (*pb != NULL) {
        if (*pb == b)
            break;
        pb = &(*pb)->next;
    }
    *pb = (*pb)->next;

    free(b);
}
Ejemplo n.º 7
0
static void build_bufed_list(EditState *s)
{
    QEmacsState *qs = s->qe_state;
    EditBuffer *b;
    BufedState *hs;
    int i;

    hs = s->mode_data;

    free_strings(&hs->items);
    for(b = qs->first_buffer; b != NULL; b = b->next) {
        if (!(b->flags & BF_SYSTEM))
            add_string(&hs->items, b->name);
    }
    
    /* build buffer */
    b = s->b;
    eb_delete(b, 0, b->total_size);
    for(i=0;i<hs->items.nb_items;i++) {
        eb_printf(b, " %s", hs->items.items[i]->str);
        if (i != hs->items.nb_items - 1)
            eb_printf(b, "\n");
    }
}
Ejemplo n.º 8
0
Archivo: shell.c Proyecto: kjk/qemacs
static void tty_emulate(ShellState *s, int c)
{
    int i, offset, offset1, offset2, n;
    char buf1[10];
    
#define ESC2(c1,c2)  (((c1)<<8)|((unsigned char)c2))
    /* some bytes are state independent */
    switch (c) {
    case 0x18:
    case 0x1A:
        s->state = TTY_STATE_NORM;
        return;
    case 0x1B:
        s->state = TTY_STATE_ESC;
        return;
#if 0
    case 0x9B:
        goto csi_entry;
#endif
    }

    switch (s->state) {
    case TTY_STATE_NORM:
        switch (c) {
            /* BEL            Bell (Ctrl-G) */
            /* FF             Form Feed or New Page (NP) (Ctrl-L) same as LF */
            /* TAB            Horizontal Tab (HT) (Ctrl-I) */
            /* VT             Vertical Tab (Ctrl-K) same as LF */

        case 8:         /* ^H  BS = backspace */
            {
                int c1;
                c1 = eb_prevc(s->b, s->cur_offset, &offset);
                if (c1 != '\n')
                    s->cur_offset = offset;
            }
            break;
        case 10:        /* ^J  NL = line feed */
            /* go to next line */
            /* CG: should check if column should be kept */
            offset = s->cur_offset;
            for (;;) {
                if (offset == s->b->total_size) {
                    /* add a new line */
                    buf1[0] = '\n';
                    eb_insert(s->b, offset, buf1, 1);
                    offset = s->b->total_size;
                    break;
                }
                c = eb_nextc(s->b, offset, &offset);
                if (c == '\n')
                    break;
            }
            s->cur_offset = offset;
            break;
        case 13:        /* ^M  CR = carriage return */
            /* move to bol */
            for (;;) {
                c = eb_prevc(s->b, s->cur_offset, &offset1);
                if (c == '\n')
                    break;
                s->cur_offset = offset1;
            }
            break;
        case 14:        /* ^N  SO = shift out */
            s->shifted = 1;
            break;
        case 15:        /* ^O  SI = shift in */
            s->shifted = 0;
            break;
        default:
            if (c >= 32 || c == 9) {
                int c1, cur_len, len;
                /* CG: assuming ISO-8859-1 characters */
                /* CG: horrible kludge for alternate charset support */
                if (s->shifted && c >= 96 && c < 128)
                    c += 32;
                /* write char (should factorize with do_char() code */
                len = unicode_to_charset(buf1, c, s->b->charset);
                c1 = eb_nextc(s->b, s->cur_offset, &offset);
                /* XXX: handle tab case */
                if (c1 == '\n') {
                    /* insert */
                    eb_insert(s->b, s->cur_offset, buf1, len);
                } else {
                    cur_len = offset - s->cur_offset;
                    if (cur_len == len) {
                        eb_write(s->b, s->cur_offset, buf1, len);
                    } else {
                        eb_delete(s->b, s->cur_offset, cur_len);
                        eb_insert(s->b, s->cur_offset, buf1, len);
                    }
                }
                s->cur_offset += len;
            }
            break;
        }
        break;
    case TTY_STATE_ESC:
        if (c == '[') {
            for (i = 0; i < MAX_ESC_PARAMS; i++) {
                s->esc_params[i] = 0;
                s->has_params[i] = 0;
            }
            s->nb_esc_params = 0;
            s->esc1 = 0;
            s->state = TTY_STATE_CSI;
        } else {
            /* CG: should deal with other sequences:
             * ansi: hts=\EH, s0ds=\E(B, s1ds=\E)B, s2ds=\E*B, s3ds=\E+B,
             * linux: hts=\EH, rc=\E8, ri=\EM, rs1=\Ec\E]R, sc=\E7,
             * vt100: enacs=\E(B\E)0, hts=\EH, rc=\E8, ri=\EM$<5>,
             *        rmkx=\E[?1l\E>,
             *        rs2=\E>\E[?3l\E[?4l\E[?5l\E[?7h\E[?8h, sc=\E7, 
             *        smkx=\E[?1h\E=,
             * xterm: enacs=\E(B\E)0, hts=\EH, is2=\E[!p\E[?3;4l\E[4l\E>,
             *        rc=\E8, ri=\EM, rmkx=\E[?1l\E>, rs1=\Ec,
             *        rs2=\E[!p\E[?3;4l\E[4l\E>, sc=\E7, smkx=\E[?1h\E=,
             */
            switch (c) {
            case '(':
            case ')':
            case '*':
            case '+':
            case ']':
                s->esc1 = c;
                s->state = TTY_STATE_ESC2;
                break;
            case 'H':   // hts
            case '7':   // sc
            case '8':   // rc
            case 'M':   // ri
            case 'c':   // rs1
            case '>':   // rmkx, is2, rs2
            case '=':   // smkx
                // XXX: do these
            default:
                s->state = TTY_STATE_NORM;
                break;
            }
        }
        break;
    case TTY_STATE_ESC2:
        s->state = TTY_STATE_NORM;
        switch (ESC2(s->esc1, c)) {
        case ESC2('(','B'):
        case ESC2(')','B'):
        case ESC2('(','0'):
        case ESC2(')','0'):
        case ESC2('*','B'):
        case ESC2('+','B'):
        case ESC2(']','R'):
            /* XXX: ??? */
            break;
        }
        break;
    case TTY_STATE_CSI:
        if (c == '?') {
            s->esc1 = c;
            break;
        }
        if (c >= '0' && c <= '9') {
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
                s->esc_params[s->nb_esc_params] = 
                    s->esc_params[s->nb_esc_params] * 10 + c - '0';
                s->has_params[s->nb_esc_params] = 1;
            }
        } else {
            s->nb_esc_params++;
            if (c == ';')
                break;
            s->state = TTY_STATE_NORM;
            switch (ESC2(s->esc1,c)) {
            case ESC2('?','h'): /* set terminal mode */
                /* 1047, 1048 -> cup mode:
                 * xterm 1049 private mode,
                 * should grab all keys while active!
                 */
                if (s->esc_params[0] == 1047 ||
                    s->esc_params[0] == 1048 ||
                    s->esc_params[0] == 1049) {
                    s->grab_keys = 1;
                    qe_grab_keys(shell_key, s);
                    /* Should also clear screen */
                }
                break;
            case ESC2('?','l'): /* reset terminal mode */
                if (s->esc_params[0] == 1047 ||
                    s->esc_params[0] == 1048 ||
                    s->esc_params[0] == 1049) {
                    qe_ungrab_keys();
                    s->grab_keys = 0;
                }
                break;
            case 'A':
                /* move relative up */
                tty_gotoxy(s, 0, -(s->esc_params[0] + 1 - s->has_params[0]), 1);
                break;
            case 'B':
                /* move relative down */
                tty_gotoxy(s, 0, (s->esc_params[0] + 1 - s->has_params[0]), 1);
                break;
            case 'C':
                /* move relative forward */
                tty_gotoxy(s, (s->esc_params[0] + 1 - s->has_params[0]), 0, 1);
                break;
            case 'D':
                /* move relative backward */
                tty_gotoxy(s, -(s->esc_params[0] + 1 - s->has_params[0]), 0, 1);
                break;
            case 'H':
                /* goto xy */
                tty_gotoxy(s, s->esc_params[1] - s->has_params[1],
                           s->esc_params[0] - s->has_params[0], 0);
                break;
            case 'J':   /* clear to end of screen */
            case 'L':   /* insert lines */
            case 'M':   /* delete lines */
            case 'S':   /* scroll forward P lines */
            case 'T':   /* scroll back P lines */
            case 'X':   /* erase P characters */
                break;
            case 'K':   /* clear eol (parm=1 -> bol) */
                offset1 = s->cur_offset;
                for (;;) {
                    c = eb_nextc(s->b, offset1, &offset2);
                    if (c == '\n')
                        break;
                    offset1 = offset2;
                }
                eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset);
                break;
            case 'P':
                /* delete chars */
                n = s->esc_params[0];
                if (n <= 0)
                    n = 1;
                offset1 = s->cur_offset;
                for (; n > 0; n--) {
                    c = eb_nextc(s->b, offset1, &offset2);
                    if (c == '\n')
                        break;
                    offset1 = offset2;
                }
                eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset);
                break;
            case '@':
                /* insert chars */
                n = s->esc_params[0];
                if (n <= 0)
                    n = 1;
                buf1[0] = ' ';
                for (; n > 0; n--) {
                    eb_insert(s->b, s->cur_offset, buf1, 1);
                }
                break;
            case 'm':
                /* colors */
                n = s->nb_esc_params;
                if (n == 0)
                    n = 1;
                for (i = 0; i < n; i++)
                    tty_csi_m(s, s->esc_params[i]);
                break;
            case 'n':
                if (s->esc_params[0] == 6) {
                    /* XXX: send cursor position, just to be able to
                       launch qemacs in qemacs (in 8859-1) ! */
                    char buf2[20];
                    snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1);
                    tty_write(s, buf2, -1);
                }
                break;
            default:
                break;
            }
        }
        break;
    }
#undef ESC2
    tty_update_cursor(s);
}
Ejemplo n.º 9
0
void do_undo(EditState *s)
{
    EditBuffer *b = s->b;
    int log_index, saved, size_trailer;
    LogBuffer lb;

    if (!b->log_buffer)
        return;

    if (s->qe_state->last_cmd_func != do_undo)
        b->log_current = 0;

    if (b->log_current == 0) {
        log_index = b->log_new_index;
    } else {
        log_index = b->log_current - 1;
    }
    if (log_index == 0) {
        put_status(s, "No futher undo information");
        return;
    } else {
        put_status(s, "Undo!");
    }
    /* go backward */
    log_index -= sizeof(int);
    eb_read(b->log_buffer, log_index, (unsigned char *)&size_trailer, sizeof(int));
    log_index -= size_trailer + sizeof(LogBuffer);
    
    /* log_current is 1 + index to have zero as default value */
    b->log_current = log_index + 1;

    /* play the log entry */
    eb_read(b->log_buffer, log_index, (unsigned char *)&lb, sizeof(LogBuffer));
    log_index += sizeof(LogBuffer);

    switch (lb.op) {
    case LOGOP_WRITE:
        /* we must disable the log because we want to record a single
           write (we should have the single operation: eb_write_buffer) */
        saved = b->save_log;
        b->save_log = 0;
        eb_delete(b, lb.offset, lb.size);
        eb_insert_buffer(b, lb.offset, b->log_buffer, log_index, lb.size);
        b->save_log = saved;
        eb_addlog(b, LOGOP_WRITE, lb.offset, lb.size);
        s->offset = lb.offset + lb.size;
        break;
    case LOGOP_DELETE:
        /* we must also disable the log there because the log buffer
           would be modified BEFORE we insert it by the implicit
           eb_addlog */
        saved = b->save_log;
        b->save_log = 0;
        eb_insert_buffer(b, lb.offset, b->log_buffer, log_index, lb.size);
        b->save_log = saved;
        eb_addlog(b, LOGOP_INSERT, lb.offset, lb.size);
        s->offset = lb.offset + lb.size;
        break;
    case LOGOP_INSERT:
        eb_delete(b, lb.offset, lb.size);
        s->offset = lb.offset;
        break;
    default:
        abort();
    }
    
    b->modified = lb.was_modified;
}
Ejemplo n.º 10
0
static void eb_addlog(EditBuffer *b, enum LogOperation op, 
                      int offset, int size)
{
    int was_modified, len, size_trailer;
    LogBuffer lb;
    EditBufferCallbackList *l;

    /* call each callback */
    for (l = b->first_callback; l != NULL; l = l->next) {
        l->callback(b, l->opaque, op, offset, size);
    }

    was_modified = b->modified;
    b->modified = 1;
    if (!b->save_log)
        return;
    if (!b->log_buffer) {
        char buf[256];
        snprintf(buf, sizeof(buf), "*log <%s>*", b->name);
        b->log_buffer = eb_new(buf, BF_SYSTEM);
        if (!b->log_buffer)
            return;
    }
    /* XXX: better test to limit size */
    if (b->nb_logs >= (NB_LOGS_MAX-1)) {
        /* no free space, delete least recent entry */
        eb_read(b->log_buffer, 0, (unsigned char *)&lb, sizeof(LogBuffer));
        len = lb.size;
        if (lb.op == LOGOP_INSERT)
            len = 0;
        len += sizeof(LogBuffer) + sizeof(int);
        eb_delete(b->log_buffer, 0, len);
        b->log_new_index -= len;
        if (b->log_current > 1)
            b->log_current -= len;
        b->nb_logs--;
    }

    /* header */
    lb.op = op;
    lb.offset = offset;
    lb.size = size;
    lb.was_modified = was_modified;
    eb_write(b->log_buffer, b->log_new_index, 
             (unsigned char *) &lb, sizeof(LogBuffer));
    b->log_new_index += sizeof(LogBuffer);

    /* data */
    switch (op) {
    case LOGOP_DELETE:
    case LOGOP_WRITE:
        eb_insert_buffer(b->log_buffer, b->log_new_index, b, offset, size);
        b->log_new_index += size;
        size_trailer = size;
        break;
    default:
        size_trailer = 0;
        break;
    }
    /* trailer */
    eb_write(b->log_buffer, b->log_new_index, 
             (unsigned char *)&size_trailer, sizeof(int));
    b->log_new_index += sizeof(int);

    b->nb_logs++;
}
Ejemplo n.º 11
0
/* invalidate buffer raw data */
void eb_invalidate_raw_data(EditBuffer *b)
{
    b->save_log = 0;
    eb_delete(b, 0, b->total_size);
    log_reset(b);
}
Ejemplo n.º 12
0
void hex_write_char(EditState *s, int key)
{
    unsigned int cur_ch, ch;
    int hsize, shift, cur_len, len, h;
    char buf[10];

    if (s->hex_mode) {
        if (s->unihex_mode)
            hsize = 4;
        else
            hsize = 2;
        h = to_hex(key);
        if (h < 0)
            return;
        if (s->insert && s->hex_nibble == 0) {
            ch = h << ((hsize - 1) * 4);
            if (s->unihex_mode) {
                len = unicode_to_charset(buf, ch, s->b->charset);
            } else {
                len = 1;
                buf[0] = ch;
            }
            eb_insert(s->b, s->offset, buf, len);
        } else {
            if (s->unihex_mode) {
                cur_ch = eb_nextc(s->b, s->offset, &cur_len);
                cur_len -= s->offset;
            } else {
                eb_read(s->b, s->offset, buf, 1);
                cur_ch = buf[0];
                cur_len = 1;
            }

            shift = (hsize - s->hex_nibble - 1) * 4;
            ch = (cur_ch & ~(0xf << shift)) | (h << shift);

            if (s->unihex_mode) {
                len = unicode_to_charset(buf, ch, s->b->charset);
            } else {
                len = 1;
                buf[0] = ch;
            }
#if 1
            eb_replace(s->b, s->offset, cur_len, buf, len);
#else
            if (cur_len == len) {
                eb_write(s->b, s->offset, buf, len);
            } else {
                eb_delete(s->b, s->offset, cur_len);
                eb_insert(s->b, s->offset, buf, len);
            }
#endif
        }
        if (++s->hex_nibble == hsize) {
            s->hex_nibble = 0;
            if (s->offset < s->b->total_size)
                s->offset += len;
        }
    } else {
        text_write_char(s, key);
    }
}
Ejemplo n.º 13
0
static void tty_emulate(ShellState *s, int c)
{
    int i, offset, offset1, offset2, n;
    unsigned char buf1[10];
    
    switch(s->state) {
    case TTY_STATE_NORM:
        switch(c) {
        case 8:
            {
                int c1;
                c1 = eb_prevc(s->b, s->cur_offset, &offset);
                if (c1 != '\n')
                    s->cur_offset = offset;
            }
            break;
        case 10:
            /* go to next line */
            offset = s->cur_offset;
            for(;;) {
                if (offset == s->b->total_size) {
                    /* add a new line */
                    buf1[0] = '\n';
                    eb_insert(s->b, offset, buf1, 1);
                    offset = s->b->total_size;
                    break;
                }
                c = eb_nextc(s->b, offset, &offset);
                if (c == '\n')
                    break;
            }
            s->cur_offset = offset;
            break;
        case 13:
            /* move to bol */
            for(;;) {
                c = eb_prevc(s->b, s->cur_offset, &offset1);
                if (c == '\n')
                    break;
                s->cur_offset = offset1;
            }
            break;
        case 27:
            s->state = TTY_STATE_ESC;
            break;
        default:
            if (c >= 32 || c == 9) {
                int c1, cur_len, len;
                /* write char (should factorize with do_char() code */
                len = unicode_to_charset(buf1, c, s->b->charset);
                c1 = eb_nextc(s->b, s->cur_offset, &offset);
                /* XXX: handle tab case */
                if (c1 == '\n') {
                    /* insert */
                    eb_insert(s->b, s->cur_offset, buf1, len);
                } else {
                    cur_len = offset - s->cur_offset;
                    if (cur_len == len) {
                        eb_write(s->b, s->cur_offset, buf1, len);
                    } else {
                        eb_delete(s->b, s->cur_offset, cur_len);
                        eb_insert(s->b, s->cur_offset, buf1, len);
                    }
                }
                s->cur_offset += len;
            }
            break;
        }
        break;
    case TTY_STATE_ESC:
        if (c == '[') {
            for(i=0;i<MAX_ESC_PARAMS;i++)
                s->esc_params[i] = 0;
            s->nb_esc_params = 0;
            s->state = TTY_STATE_CSI;
        } else {
            s->state = TTY_STATE_NORM;
        }
        break;
    case TTY_STATE_CSI:
        if (c >= '0' && c <= '9') {
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
                s->esc_params[s->nb_esc_params] = 
                    s->esc_params[s->nb_esc_params] * 10 + c - '0';
            }
        } else {
            s->nb_esc_params++;
            if (c == ';')
                break;
            s->state = TTY_STATE_NORM;
            switch(c) {
            case 'H':
                /* goto xy */
                {
                    int x, y;
                    y = s->esc_params[0] - 1;
                    x = s->esc_params[1] - 1;
                    if (y < 0)
                        y = 0;
                    else if (y >= TTY_YSIZE)
                        y = TTY_YSIZE - 1;
                    if (x < 0)
                        x = 0;
                    tty_gotoxy(s, x, y);
                }
                break;
            case 'K':
                /* clear to eol */
                offset1 = s->cur_offset;
                for(;;) {
                    c = eb_nextc(s->b, offset1, &offset2);
                    if (c == '\n')
                        break;
                    offset1 = offset2;
                }
                eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset);
                break;
            case 'P':
                /* delete chars */
                n = s->esc_params[0];
                if (n <= 0)
                    n = 1;
                offset1 = s->cur_offset;
                for(;n > 0;n--) {
                    c = eb_nextc(s->b, offset1, &offset2);
                    if (c == '\n')
                        break;
                    offset1 = offset2;
                }
                eb_delete(s->b, s->cur_offset, offset1 - s->cur_offset);
                break;
            case '@':
                /* insert chars */
                n = s->esc_params[0];
                if (n <= 0)
                    n = 1;
                buf1[0] = ' ';
                for(;n > 0;n--) {
                    eb_insert(s->b, s->cur_offset, buf1, 1);
                }
                break;
            case 'm':
                /* colors */
                n = s->nb_esc_params;
                if (n == 0)
                    n = 1;
                for(i=0;i<n;i++)
                    tty_csi_m(s, s->esc_params[i]);
                break;
            case 'n':
                if (s->esc_params[0] == 6) {
                    /* XXX: send cursor position, just to be able to
                       launch qemacs in qemacs ! */
                    char buf2[20];
                    snprintf(buf2, sizeof(buf2), "\033[%d;%dR", 1, 1);
                    tty_write(s, buf2, -1);
                }
                break;
            default:
                break;
            }
        }
        break;
    }
    tty_update_cursor(s);
}