diff --git a/qse/include/qse/utl/sed.h b/qse/include/qse/utl/sed.h index 952e5410..9e7f7d38 100644 --- a/qse/include/qse/utl/sed.h +++ b/qse/include/qse/utl/sed.h @@ -151,7 +151,11 @@ struct qse_sed_t } in; } eio; - qse_lda_t text_appended; + struct + { + qse_lda_t appended; + qse_str_t held; + } text; }; diff --git a/qse/lib/utl/sed.c b/qse/lib/utl/sed.c index 106168ae..9ba43080 100644 --- a/qse/lib/utl/sed.c +++ b/qse/lib/utl/sed.c @@ -19,6 +19,7 @@ #include "sed.h" #include "../cmn/mem.h" #include +#include /* TODO: delete stdio.h */ #include @@ -91,7 +92,7 @@ qse_sed_t* qse_sed_init (qse_sed_t* sed, qse_mmgr_t* mmgr) sed->cmd.cur = sed->cmd.buf; sed->cmd.end = sed->cmd.buf + 1000 - 1; - if (qse_lda_init (&sed->text_appended, mmgr, 32) == QSE_NULL) + if (qse_lda_init (&sed->text.appended, mmgr, 32) == QSE_NULL) { QSE_MMGR_FREE (sed->mmgr, sed->cmd.buf); qse_map_fini (&sed->labs); @@ -99,12 +100,23 @@ qse_sed_t* qse_sed_init (qse_sed_t* sed, qse_mmgr_t* mmgr) return QSE_NULL; } + if (qse_str_init (&sed->text.held, mmgr, 256) == QSE_NULL) + { + qse_lda_fini (&sed->text.appended); + QSE_MMGR_FREE (sed->mmgr, sed->cmd.buf); + qse_map_fini (&sed->labs); + qse_str_fini (&sed->rexbuf); + return QSE_NULL; + + } + return sed; } void qse_sed_fini (qse_sed_t* sed) { - qse_lda_fini (&sed->text_appended); + qse_str_fini (&sed->text.held); + qse_lda_fini (&sed->text.appended); /* TODO: use different data sturect -> look at qse_sed_init */ qse_sed_cmd_t* c; @@ -1058,13 +1070,6 @@ qse_printf (QSE_T("command %c\n"), cmd->type); /* get_text() starts from the next line */ if (get_text (sed, cmd) <= -1) return -1; -/* -{ -qse_char_t ttt[1000]; -qse_fgets (ttt, QSE_COUNTOF(ttt), QSE_STDIN); -qse_printf (QSE_T("%s%s"), ttt, cmd->u.text.ptr); -} -*/ break; } @@ -1077,20 +1082,22 @@ qse_printf (QSE_T("%s%s"), ttt, cmd->u.text.ptr); } case QSE_T('p'): case QSE_T('P'): + case QSE_T('l'): + case QSE_T('d'): case QSE_T('D'): + case QSE_T('h'): case QSE_T('H'): case QSE_T('g'): case QSE_T('G'): - case QSE_T('l'): + case QSE_T('x'): + case QSE_T('n'): case QSE_T('N'): - case QSE_T('x'): cmd->type = c; ADVSCP (sed); if (terminate_command (sed) <= -1) return -1; -qse_printf (QSE_T("command %c\n"), cmd->type); break; case QSE_T('b'): @@ -1098,15 +1105,6 @@ qse_printf (QSE_T("command %c\n"), cmd->type); cmd->type = c; ADVSCP (sed); if (get_branch_target (sed, cmd) <= -1) return -1; -if (cmd->u.branch.label.ptr != NULL) -{ -qse_printf (QSE_T("cmd->u.branch.label = [%.*s]\n"), - cmd->u.branch.label.len, cmd->u.branch.label.ptr); -} -else -{ -qse_printf (QSE_T("cmd->u.branch.target = [%p]\n"), cmd->u.branch.target); -} break; case QSE_T('r'): @@ -1116,8 +1114,6 @@ qse_printf (QSE_T("cmd->u.branch.target = [%p]\n"), cmd->u.branch.target); cmd->type = c; ADVSCP (sed); if (get_file (sed, &cmd->u.file) <= -1) return -1; - -qse_printf (QSE_T("cmd->u.file= [%.*s]\n"), (int)cmd->u.file.len, cmd->u.file.ptr); break; @@ -1409,30 +1405,40 @@ static int write_str (qse_sed_t* sed, const qse_char_t* str, qse_size_t len) return 0; } -static int write_num (qse_sed_t* sed, qse_size_t x) +static int write_num (qse_sed_t* sed, qse_size_t x, int base, int width) { - qse_size_t last = x % 10; + qse_size_t last = x % base; qse_size_t y = 0, dig = 0; + QSE_ASSERT (base >= 2 && base <= 10); + if (x < 0) { if (write_char (sed, QSE_T('-')) <= -1) return -1; } - x = x / 10; + x = x / base; if (x < 0) x = -x; while (x > 0) { - y = y * 10 + (x % 10); - x = x / 10; + y = y * base + (x % base); + x = x / base; dig++; } + if (width > 0) + { + while (--width > dig) + { + if (write_char (sed, QSE_T('0')) <= -1) return -1; + } + } + while (y > 0) { - if (write_char (sed, (y % 10) + QSE_T('0')) <= -1) return -1; - y = y / 10; + if (write_char (sed, (y % base) + QSE_T('0')) <= -1) return -1; + y = y / base; dig--; } @@ -1447,6 +1453,76 @@ static int write_num (qse_sed_t* sed, qse_size_t x) return 0; } +#define WRITE_CHAR(sed,c) \ + do { if (write_char(sed,c) <= -1) return -1; } while (0) +#define WRITE_STR(sed,str,len) \ + do { if (write_str(sed,str,len) <= -1) return -1; } while (0) +#define WRITE_NUM(sed,num,base,width) \ + do { if (write_num(sed,num,base,width) <= -1) return -1; } while (0) + +static int write_str_clearly ( + qse_sed_t* sed, const qse_char_t* str, qse_size_t len) +{ + const qse_char_t* p = str; + const qse_char_t* end = str + len; + +/* TODO: break down long lines.... */ + while (p < end) + { + qse_char_t c = *p++; + + switch (c) + { + case QSE_T('\\'): + WRITE_STR (sed, QSE_T("\\\\"), 2); + break; + /*case QSE_T('\0'): + WRITE_STR (sed, QSE_T("\\0"), 2); + break;*/ + case QSE_T('\n'): + WRITE_STR (sed, QSE_T("$\n"), 2); + break; + case QSE_T('\a'): + WRITE_STR (sed, QSE_T("\\a"), 2); + break; + case QSE_T('\b'): + WRITE_STR (sed, QSE_T("\\b"), 2); + break; + case QSE_T('\f'): + WRITE_STR (sed, QSE_T("\\f"), 2); + break; + case QSE_T('\r'): + WRITE_STR (sed, QSE_T("\\r"), 2); + break; + case QSE_T('\t'): + WRITE_STR (sed, QSE_T("\\t"), 2); + break; + case QSE_T('\v'): + WRITE_STR (sed, QSE_T("\\v"), 2); + break; + default: + { + if (QSE_ISPRINT(c)) WRITE_CHAR (sed, c); + else + { + qse_size_t i; + qse_byte_t* b = (qse_byte_t*)&c; + WRITE_CHAR (sed, QSE_T('\\')); + for (i = 0; i < QSE_SIZEOF(c)/QSE_SIZEOF(*b); i++) + { + WRITE_NUM (sed, b[i], 8, 3); + } + } + } + } + } + + if (len > 1 && end[-1] != QSE_T('\n')) + WRITE_STR (sed, QSE_T("$\n"), 2); + + return 0; +} + static int match_a (qse_sed_t* sed, qse_sed_a_t* a) { switch (a->type) @@ -1614,11 +1690,10 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) jumpto = sed->cmd.cur + 1; break; - case QSE_SED_CMD_APPEND: if (qse_lda_insert ( - &sed->text_appended, - QSE_LDA_SIZE(&sed->text_appended), + &sed->text.appended, + QSE_LDA_SIZE(&sed->text.appended), &cmd->u.text, 0) == (qse_size_t)-1) { sed->errnum = QSE_SED_ENOMEM; @@ -1669,17 +1744,72 @@ static qse_sed_cmd_t* exec_cmd (qse_sed_t* sed, qse_sed_cmd_t* cmd) break; case QSE_SED_CMD_PRINT_LNUM: - if (write_num (sed, sed->eio.in.num) <= -1) return QSE_NULL; + if (write_num (sed, sed->eio.in.num, 10, 0) <= -1) return QSE_NULL; if (write_char (sed, QSE_T('\n')) <= -1) return QSE_NULL; break; case QSE_SED_CMD_PRINT: - n = write_str (sed, + n = write_str ( + sed, QSE_STR_PTR(&sed->eio.in.line), - QSE_STR_LEN(&sed->eio.in.line)); + QSE_STR_LEN(&sed->eio.in.line) + ); if (n <= -1) return QSE_NULL; break; + case QSE_SED_CMD_PRINT_CLEARLY: + n = write_str_clearly ( + sed, + QSE_STR_PTR(&sed->eio.in.line), + QSE_STR_LEN(&sed->eio.in.line) + ); + if (n <= -1) return QSE_NULL; + break; + + case QSE_SED_CMD_HOLD: + if (qse_str_ncpy (&sed->text.held, + QSE_STR_PTR(&sed->eio.in.line), + QSE_STR_LEN(&sed->eio.in.line)) == (qse_size_t)-1) + { + sed->errnum = QSE_SED_ENOMEM; + return QSE_NULL; + } + break; + + case QSE_SED_CMD_HOLD_APPEND: + if (qse_str_ncat (&sed->text.held, + QSE_STR_PTR(&sed->eio.in.line), + QSE_STR_LEN(&sed->eio.in.line)) == (qse_size_t)-1) + { + sed->errnum = QSE_SED_ENOMEM; + return QSE_NULL; + } + break; + + case QSE_SED_CMD_RELEASE: + if (qse_str_ncpy (&sed->eio.in.line, + QSE_STR_PTR(&sed->text.held), + QSE_STR_LEN(&sed->text.held)) == (qse_size_t)-1) + { + sed->errnum = QSE_SED_ENOMEM; + return QSE_NULL; + } + break; + + case QSE_SED_CMD_EXCHANGE: + qse_str_swap (&sed->eio.in.line, &sed->text.held); + break; + + case QSE_SED_CMD_RELEASE_APPEND: + if (qse_str_ncat (&sed->eio.in.line, + QSE_STR_PTR(&sed->text.held), + QSE_STR_LEN(&sed->text.held)) == (qse_size_t)-1) + { + sed->errnum = QSE_SED_ENOMEM; + return QSE_NULL; + } + break; + case QSE_SED_CMD_BRANCH: if (cmd->u.branch.target == QSE_NULL) { @@ -1712,6 +1842,14 @@ int qse_sed_execute (qse_sed_t* sed, qse_sed_iof_t inf, qse_sed_iof_t outf) qse_ssize_t n; int ret = 0; + qse_lda_clear (&sed->text.appended); + qse_str_clear (&sed->text.held); + if (qse_str_ccat (&sed->text.held, QSE_T('\n')) == (qse_size_t)-1) + { + sed->errnum = QSE_SED_ENOMEM; + return -1; + } + sed->eio.out.f = outf; sed->eio.out.eof = 0; sed->eio.out.len = 0; @@ -1766,7 +1904,7 @@ int qse_sed_execute (qse_sed_t* sed, qse_sed_iof_t inf, qse_sed_iof_t outf) if (n <= -1) { ret = -1; goto done; } if (n == 0) goto done; - qse_lda_clear (&sed->text_appended); + qse_lda_clear (&sed->text.appended); c = sed->cmd.buf; while (c < sed->cmd.cur) @@ -1802,9 +1940,9 @@ int qse_sed_execute (qse_sed_t* sed, qse_sed_iof_t inf, qse_sed_iof_t outf) if (n <= -1) { ret = -1; goto done; } } - for (i = 0; i < QSE_LDA_SIZE(&sed->text_appended); i++) + for (i = 0; i < QSE_LDA_SIZE(&sed->text.appended); i++) { - qse_xstr_t* t = QSE_LDA_DPTR(&sed->text_appended, i); + qse_xstr_t* t = QSE_LDA_DPTR(&sed->text.appended, i); n = write_str (sed, t->ptr, t->len); if (n <= -1) { ret = -1; goto done; } } diff --git a/qse/lib/utl/sed.h b/qse/lib/utl/sed.h index fd5af299..d37aad46 100644 --- a/qse/lib/utl/sed.h +++ b/qse/lib/utl/sed.h @@ -48,14 +48,9 @@ struct qse_sed_cmd_t { enum { - QSE_SED_CMD_PRINT_LNUM = QSE_T('='), QSE_SED_CMD_QUIT = QSE_T('q'), QSE_SED_CMD_QUIT_QUIET = QSE_T('Q'), - /* delete pattern space */ - QSE_SED_CMD_DELETE = QSE_T('d'), - QSE_SED_CMD_DD = QSE_T('D'), - /* a \<\n> text - append text */ QSE_SED_CMD_APPEND = QSE_T('a'), /* i \<\n> text - insert text */ @@ -63,18 +58,23 @@ struct qse_sed_cmd_t /* c \<\n> text - change text */ QSE_SED_CMD_CHANGE = QSE_T('c'), - QSE_SED_CMD_H = QSE_T('h'), - QSE_SED_CMD_HH = QSE_T('H'), - QSE_SED_CMD_G = QSE_T('g'), - QSE_SED_CMD_GG = QSE_T('G'), - /* list out current line */ - QSE_SED_CMD_L = QSE_T('l'), + /* delete pattern space */ + QSE_SED_CMD_DELETE = QSE_T('d'), + QSE_SED_CMD_DD = QSE_T('D'), + + QSE_SED_CMD_PRINT_LNUM = QSE_T('='), + QSE_SED_CMD_PRINT = QSE_T('p'), + QSE_SED_CMD_PP = QSE_T('P'), + QSE_SED_CMD_PRINT_CLEARLY = QSE_T('l'), + + QSE_SED_CMD_HOLD = QSE_T('h'), + QSE_SED_CMD_HOLD_APPEND = QSE_T('H'), + QSE_SED_CMD_RELEASE = QSE_T('g'), + QSE_SED_CMD_RELEASE_APPEND = QSE_T('G'), + QSE_SED_CMD_EXCHANGE = QSE_T('x'), + QSE_SED_CMD_N = QSE_T('n'), QSE_SED_CMD_NN = QSE_T('N'), - QSE_SED_CMD_PRINT = QSE_T('p'), - QSE_SED_CMD_PP = QSE_T('P'), - /* exchange hold space and pattern space */ - QSE_SED_CMD_X = QSE_T('x'), /* branch */ QSE_SED_CMD_BRANCH = QSE_T('b'),