Changeset 3232 in MondoRescue for branches/3.2/mindi-busybox/editors


Ignore:
Timestamp:
Jan 1, 2014, 12:47:38 AM (10 years ago)
Author:
Bruno Cornec
Message:
  • Update mindi-busybox to 1.21.1
Location:
branches/3.2/mindi-busybox/editors
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • branches/3.2/mindi-busybox/editors/Config.src

    r2725 r3232  
    6868      or input from a pipeline.
    6969
    70 config VI
    71     bool "vi"
    72     default y
    73     help
    74       'vi' is a text editor. More specifically, it is the One True
    75       text editor <grin>. It does, however, have a rather steep
    76       learning curve. If you are not already comfortable with 'vi'
    77       you may wish to use something else.
    78 
    79 config FEATURE_VI_MAX_LEN
    80     int "Maximum screen width in vi"
    81     range 256 16384
    82     default 4096
    83     depends on VI
    84     help
    85       Contrary to what you may think, this is not eating much.
    86       Make it smaller than 4k only if you are very limited on memory.
    87 
    88 config FEATURE_VI_8BIT
    89     bool "Allow vi to display 8-bit chars (otherwise shows dots)"
    90     default n
    91     depends on VI
    92     help
    93       If your terminal can display characters with high bit set,
    94       you may want to enable this. Note: vi is not Unicode-capable.
    95       If your terminal combines several 8-bit bytes into one character
    96       (as in Unicode mode), this will not work properly.
    97 
    98 config FEATURE_VI_COLON
    99     bool "Enable \":\" colon commands (no \"ex\" mode)"
    100     default y
    101     depends on VI
    102     help
    103       Enable a limited set of colon commands for vi. This does not
    104       provide an "ex" mode.
    105 
    106 config FEATURE_VI_YANKMARK
    107     bool "Enable yank/put commands and mark cmds"
    108     default y
    109     depends on VI
    110     help
    111       This will enable you to use yank and put, as well as mark in
    112       busybox vi.
    113 
    114 config FEATURE_VI_SEARCH
    115     bool "Enable search and replace cmds"
    116     default y
    117     depends on VI
    118     help
    119       Select this if you wish to be able to do search and replace in
    120       busybox vi.
    121 
    122 config FEATURE_VI_USE_SIGNALS
    123     bool "Catch signals"
    124     default y
    125     depends on VI
    126     help
    127       Selecting this option will make busybox vi signal aware. This will
    128       make busybox vi support SIGWINCH to deal with Window Changes, catch
    129       Ctrl-Z and Ctrl-C and alarms.
    130 
    131 config FEATURE_VI_DOT_CMD
    132     bool "Remember previous cmd and \".\" cmd"
    133     default y
    134     depends on VI
    135     help
    136       Make busybox vi remember the last command and be able to repeat it.
    137 
    138 config FEATURE_VI_READONLY
    139     bool "Enable -R option and \"view\" mode"
    140     default y
    141     depends on VI
    142     help
    143       Enable the read-only command line option, which allows the user to
    144       open a file in read-only mode.
    145 
    146 config FEATURE_VI_SETOPTS
    147     bool "Enable set-able options, ai ic showmatch"
    148     default y
    149     depends on VI
    150     help
    151       Enable the editor to set some (ai, ic, showmatch) options.
    152 
    153 config FEATURE_VI_SET
    154     bool "Support for :set"
    155     default y
    156     depends on VI
    157     help
    158       Support for ":set".
    159 
    160 config FEATURE_VI_WIN_RESIZE
    161     bool "Handle window resize"
    162     default y
    163     depends on VI
    164     help
    165       Make busybox vi behave nicely with terminals that get resized.
    166 
    167 config FEATURE_VI_ASK_TERMINAL
    168     bool "Use 'tell me cursor position' ESC sequence to measure window"
    169     default y
    170     depends on VI
    171     help
    172       If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
    173       this option makes vi perform a last-ditch effort to find it:
    174       vi positions cursor to 999,999 and asks terminal to report real
    175       cursor position using "ESC [ 6 n" escape sequence, then reads stdin.
    176 
    177       This is not clean but helps a lot on serial lines and such.
    178 
    179 config FEATURE_VI_OPTIMIZE_CURSOR
    180     bool "Optimize cursor movement"
    181     default y
    182     depends on VI
    183     help
    184       This will make the cursor movement faster, but requires more memory
    185       and it makes the applet a tiny bit larger.
    186 
    18770config FEATURE_ALLOW_EXEC
    18871    bool "Allow vi and awk to execute shell commands"
  • branches/3.2/mindi-busybox/editors/Kbuild.src

    r2725 r3232  
    1313lib-$(CONFIG_ED)        += ed.o
    1414lib-$(CONFIG_SED)       += sed.o
    15 lib-$(CONFIG_VI)        += vi.o
  • branches/3.2/mindi-busybox/editors/awk.c

    r2725 r3232  
    88 */
    99
     10//usage:#define awk_trivial_usage
     11//usage:       "[OPTIONS] [AWK_PROGRAM] [FILE]..."
     12//usage:#define awk_full_usage "\n\n"
     13//usage:       "    -v VAR=VAL  Set variable"
     14//usage:     "\n    -F SEP      Use SEP as field separator"
     15//usage:     "\n    -f FILE     Read program from FILE"
     16
    1017#include "libbb.h"
    1118#include "xregex.h"
     
    1926#define debug_printf_walker(...)  do {} while (0)
    2027#define debug_printf_eval(...)  do {} while (0)
     28#define debug_printf_parse(...)  do {} while (0)
    2129
    2230#ifndef debug_printf_walker
     
    2533#ifndef debug_printf_eval
    2634# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__))
     35#endif
     36#ifndef debug_printf_parse
     37# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__))
    2738#endif
    2839
     
    145156/* simple token classes */
    146157/* Order and hex values are very important!!!  See next_token() */
    147 #define TC_SEQSTART  1              /* ( */
     158#define TC_SEQSTART 1           /* ( */
    148159#define TC_SEQTERM  (1 << 1)        /* ) */
    149160#define TC_REGEXP   (1 << 2)        /* /.../ */
     
    232243 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
    233244 */
     245#undef P
     246#undef PRIMASK
     247#undef PRIMASK2
    234248#define P(x)      (x << 24)
    235249#define PRIMASK   0x7F000000
     
    426440    smallint nextfile;
    427441    smallint is_f0_split;
     442    smallint t_rollback;
    428443};
    429444struct globals2 {
     
    432447    char *t_string;
    433448    int t_lineno;
    434     int t_rollback;
    435449
    436450    var *intvar[NUM_INTERNAL_VARS]; /* often used */
     
    490504#define nextfile     (G1.nextfile    )
    491505#define is_f0_split  (G1.is_f0_split )
     506#define t_rollback   (G1.t_rollback  )
    492507#define t_info       (G.t_info      )
    493508#define t_tclass     (G.t_tclass    )
    494509#define t_string     (G.t_string    )
    495510#define t_lineno     (G.t_lineno    )
    496 #define t_rollback   (G.t_rollback  )
    497511#define intvar       (G.intvar      )
    498512#define fsplitter    (G.fsplitter   )
     
    683697    if (c == '\\')
    684698        c = bb_process_escape_sequence((const char**)s);
     699    /* Example awk statement:
     700     * s = "abc\"def"
     701     * we must treat \" as "
     702     */
    685703    if (c == '\\' && *s == pps) { /* unrecognized \z? */
    686704        c = *(*s); /* yes, fetch z */
     
    689707    }
    690708    return c;
     709}
     710
     711/* TODO: merge with strcpy_and_process_escape_sequences()?
     712 */
     713static void unescape_string_in_place(char *s1)
     714{
     715    char *s = s1;
     716    while ((*s1 = nextchar(&s)) != '\0')
     717        s1++;
    691718}
    692719
     
    10021029        if (*p == '\0') {
    10031030            tc = TC_EOF;
     1031            debug_printf_parse("%s: token found: TC_EOF\n", __func__);
    10041032
    10051033        } else if (*p == '\"') {
     
    10171045            *s = '\0';
    10181046            tc = TC_STRING;
     1047            debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string);
    10191048
    10201049        } else if ((expected & TC_REGEXP) && *p == '/') {
     
    10391068            *s = '\0';
    10401069            tc = TC_REGEXP;
     1070            debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string);
    10411071
    10421072        } else if (*p == '.' || isdigit(*p)) {
     
    10481078                syntax_error(EMSG_UNEXP_TOKEN);
    10491079            tc = TC_NUMBER;
     1080            debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double);
    10501081
    10511082        } else {
     
    10701101                    /* then this is what we are looking for */
    10711102                    t_info = *ti;
     1103                    debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info);
    10721104                    p += l;
    10731105                    goto token_found;
     
    10931125            if (*p == '(') {
    10941126                tc = TC_FUNCTION;
     1127                debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string);
    10951128            } else {
    10961129                if (*p == '[') {
    10971130                    p++;
    10981131                    tc = TC_ARRAY;
    1099                 }
    1100             }
    1101  token_found: ;
    1102         }
     1132                    debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string);
     1133                } else
     1134                    debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string);
     1135            }
     1136        }
     1137 token_found:
    11031138        g_pos = p;
    11041139
     
    11721207    var *v;
    11731208
     1209    debug_printf_parse("%s(%x)\n", __func__, iexp);
     1210
    11741211    sn.info = PRIMASK;
    11751212    sn.r.n = glptr = NULL;
     
    11801217        if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
    11811218            /* input redirection (<) attached to glptr node */
     1219            debug_printf_parse("%s: input redir\n", __func__);
    11821220            cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
    11831221            cn->a.n = glptr;
     
    11861224
    11871225        } else if (tc & (TC_BINOP | TC_UOPPOST)) {
     1226            debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__);
    11881227            /* for binary and postfix-unary operators, jump back over
    11891228             * previous operators with higher priority */
     
    12151254
    12161255        } else {
     1256            debug_printf_parse("%s: other\n", __func__);
    12171257            /* for operands and prefix-unary operators, attach them
    12181258             * to last node */
     
    12221262            xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
    12231263            if (tc & (TC_OPERAND | TC_REGEXP)) {
     1264                debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__);
    12241265                xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp;
    12251266                /* one should be very careful with switch on tclass -
     
    12281269                case TC_VARIABLE:
    12291270                case TC_ARRAY:
     1271                    debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__);
    12301272                    cn->info = OC_VAR;
    12311273                    v = hash_search(ahash, t_string);
     
    12441286                case TC_NUMBER:
    12451287                case TC_STRING:
     1288                    debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__);
    12461289                    cn->info = OC_VAR;
    12471290                    v = cn->l.v = xzalloc(sizeof(var));
     
    12531296
    12541297                case TC_REGEXP:
     1298                    debug_printf_parse("%s: TC_REGEXP\n", __func__);
    12551299                    mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
    12561300                    break;
    12571301
    12581302                case TC_FUNCTION:
     1303                    debug_printf_parse("%s: TC_FUNCTION\n", __func__);
    12591304                    cn->info = OC_FUNC;
    12601305                    cn->r.f = newfunc(t_string);
     
    12631308
    12641309                case TC_SEQSTART:
     1310                    debug_printf_parse("%s: TC_SEQSTART\n", __func__);
    12651311                    cn = vn->r.n = parse_expr(TC_SEQTERM);
     1312                    if (!cn)
     1313                        syntax_error("Empty sequence");
    12661314                    cn->a.n = vn;
    12671315                    break;
    12681316
    12691317                case TC_GETLINE:
     1318                    debug_printf_parse("%s: TC_GETLINE\n", __func__);
    12701319                    glptr = cn;
    12711320                    xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
     
    12731322
    12741323                case TC_BUILTIN:
     1324                    debug_printf_parse("%s: TC_BUILTIN\n", __func__);
    12751325                    cn->l.n = condition();
    12761326                    break;
     
    12791329        }
    12801330    }
     1331
     1332    debug_printf_parse("%s() returns %p\n", __func__, sn.r.n);
    12811333    return sn.r.n;
    12821334}
     
    13471399
    13481400    if (c & TC_GRPSTART) {
     1401        debug_printf_parse("%s: TC_GRPSTART\n", __func__);
    13491402        while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
     1403            debug_printf_parse("%s: !TC_GRPTERM\n", __func__);
    13501404            if (t_tclass & TC_NEWLINE)
    13511405                continue;
     
    13531407            chain_group();
    13541408        }
     1409        debug_printf_parse("%s: TC_GRPTERM\n", __func__);
    13551410    } else if (c & (TC_OPSEQ | TC_OPTERM)) {
     1411        debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__);
    13561412        rollback_token();
    13571413        chain_expr(OC_EXEC | Vx);
    1358     } else {                        /* TC_STATEMNT */
     1414    } else {
     1415        /* TC_STATEMNT */
     1416        debug_printf_parse("%s: TC_STATEMNT(?)\n", __func__);
    13591417        switch (t_info & OPCLSMASK) {
    13601418        case ST_IF:
     1419            debug_printf_parse("%s: ST_IF\n", __func__);
    13611420            n = chain_node(OC_BR | Vx);
    13621421            n->l.n = condition();
     
    13731432
    13741433        case ST_WHILE:
     1434            debug_printf_parse("%s: ST_WHILE\n", __func__);
    13751435            n2 = condition();
    13761436            n = chain_loop(NULL);
     
    13791439
    13801440        case ST_DO:
     1441            debug_printf_parse("%s: ST_DO\n", __func__);
    13811442            n2 = chain_node(OC_EXEC);
    13821443            n = chain_loop(NULL);
     
    13871448
    13881449        case ST_FOR:
     1450            debug_printf_parse("%s: ST_FOR\n", __func__);
    13891451            next_token(TC_SEQSTART);
    13901452            n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
     
    14121474        case OC_PRINT:
    14131475        case OC_PRINTF:
     1476            debug_printf_parse("%s: OC_PRINT[F]\n", __func__);
    14141477            n = chain_node(t_info);
    14151478            n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
     
    14231486
    14241487        case OC_BREAK:
     1488            debug_printf_parse("%s: OC_BREAK\n", __func__);
    14251489            n = chain_node(OC_EXEC);
    14261490            n->a.n = break_ptr;
     
    14281492
    14291493        case OC_CONTINUE:
     1494            debug_printf_parse("%s: OC_CONTINUE\n", __func__);
    14301495            n = chain_node(OC_EXEC);
    14311496            n->a.n = continue_ptr;
     
    14341499        /* delete, next, nextfile, return, exit */
    14351500        default:
     1501            debug_printf_parse("%s: default\n", __func__);
    14361502            chain_expr(t_info);
    14371503        }
     
    14511517            TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
    14521518
    1453         if (tclass & TC_OPTERM)
     1519        if (tclass & TC_OPTERM) {
     1520            debug_printf_parse("%s: TC_OPTERM\n", __func__);
    14541521            continue;
     1522        }
    14551523
    14561524        seq = &mainseq;
    14571525        if (tclass & TC_BEGIN) {
     1526            debug_printf_parse("%s: TC_BEGIN\n", __func__);
    14581527            seq = &beginseq;
    14591528            chain_group();
    14601529
    14611530        } else if (tclass & TC_END) {
     1531            debug_printf_parse("%s: TC_END\n", __func__);
    14621532            seq = &endseq;
    14631533            chain_group();
    14641534
    14651535        } else if (tclass & TC_FUNCDECL) {
     1536            debug_printf_parse("%s: TC_FUNCDECL\n", __func__);
    14661537            next_token(TC_FUNCTION);
    14671538            g_pos++;
     
    14811552
    14821553        } else if (tclass & TC_OPSEQ) {
     1554            debug_printf_parse("%s: TC_OPSEQ\n", __func__);
    14831555            rollback_token();
    14841556            cn = chain_node(OC_TEST);
    14851557            cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
    14861558            if (t_tclass & TC_GRPSTART) {
     1559                debug_printf_parse("%s: TC_GRPSTART\n", __func__);
    14871560                rollback_token();
    14881561                chain_group();
    14891562            } else {
     1563                debug_printf_parse("%s: !TC_GRPSTART\n", __func__);
    14901564                chain_node(OC_PRINT);
    14911565            }
     
    14931567
    14941568        } else /* if (tclass & TC_GRPSTART) */ {
     1569            debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__);
    14951570            rollback_token();
    14961571            chain_group();
    14971572        }
    14981573    }
     1574    debug_printf_parse("%s: TC_EOF\n", __func__);
    14991575}
    15001576
     
    17371813
    17381814    } else if (v == intvar[FS]) {
     1815        /*
     1816         * The POSIX-2008 standard says that changing FS should have no effect on the
     1817         * current input line, but only on the next one. The language is:
     1818         *
     1819         * > Before the first reference to a field in the record is evaluated, the record
     1820         * > shall be split into fields, according to the rules in Regular Expressions,
     1821         * > using the value of FS that was current at the time the record was read.
     1822         *
     1823         * So, split up current line before assignment to FS:
     1824         */
     1825        split_f0();
     1826
    17391827        mk_splitter(getvar_s(v), &fsplitter);
    17401828
     
    26212709            }
    26222710
    2623             if (!rsm->F) {
     2711            if (!rsm || !rsm->F) {
    26242712                setvar_i(intvar[ERRNO], errno);
    26252713                setvar_i(res, -1);
     
    29303018static int is_assignment(const char *expr)
    29313019{
    2932     char *exprc, *val, *s, *s1;
     3020    char *exprc, *val;
    29333021
    29343022    if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
     
    29403028    *val++ = '\0';
    29413029
    2942     s = s1 = val;
    2943     while ((*s1 = nextchar(&s)) != '\0')
    2944         s1++;
    2945 
     3030    unescape_string_in_place(val);
    29463031    setvar_u(newvar(exprc), val);
    29473032    free(exprc);
     
    29553040#define files_happen (G.next_input_file__files_happen)
    29563041
    2957     FILE *F = NULL;
     3042    FILE *F;
    29583043    const char *fname, *ind;
    29593044
     
    29633048    rsm.pos = rsm.adv = 0;
    29643049
    2965     do {
     3050    for (;;) {
    29663051        if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
    29673052            if (files_happen)
     
    29693054            fname = "-";
    29703055            F = stdin;
    2971         } else {
    2972             ind = getvar_s(incvar(intvar[ARGIND]));
    2973             fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
    2974             if (fname && *fname && !is_assignment(fname))
    2975                 F = xfopen_stdin(fname);
    2976         }
    2977     } while (!F);
     3056            break;
     3057        }
     3058        ind = getvar_s(incvar(intvar[ARGIND]));
     3059        fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
     3060        if (fname && *fname && !is_assignment(fname)) {
     3061            F = xfopen_stdin(fname);
     3062            break;
     3063        }
     3064    }
    29783065
    29793066    files_happen = TRUE;
     
    29893076{
    29903077    unsigned opt;
    2991     char *opt_F, *opt_W;
     3078    char *opt_F;
    29923079    llist_t *list_v = NULL;
    29933080    llist_t *list_f = NULL;
     
    30513138    }
    30523139    opt_complementary = "v::f::"; /* -v and -f can occur multiple times */
    3053     opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W);
     3140    opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, NULL);
    30543141    argv += optind;
    30553142    argc -= optind;
    3056     if (opt & 0x1)
    3057         setvar_s(intvar[FS], opt_F); // -F
     3143    if (opt & 0x1) { /* -F */
     3144        unescape_string_in_place(opt_F);
     3145        setvar_s(intvar[FS], opt_F);
     3146    }
    30583147    while (list_v) { /* -v */
    30593148        if (!is_assignment(llist_pop(&list_v)))
     
    30853174    }
    30863175    if (opt & 0x8) // -W
    3087         bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
     3176        bb_error_msg("warning: option -W is ignored");
    30883177
    30893178    /* fill in ARGV array */
  • branches/3.2/mindi-busybox/editors/cmp.c

    r2725 r3232  
    1010/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */
    1111/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */
     12
     13//usage:#define cmp_trivial_usage
     14//usage:       "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]"
     15//usage:#define cmp_full_usage "\n\n"
     16//usage:       "Compare FILE1 with FILE2 (or stdin)\n"
     17//usage:     "\n    -l  Write the byte numbers (decimal) and values (octal)"
     18//usage:     "\n        for all differing bytes"
     19//usage:     "\n    -s  Quiet"
    1220
    1321#include "libbb.h"
  • branches/3.2/mindi-busybox/editors/diff.c

    r2725 r3232  
    7777 */
    7878
     79//usage:#define diff_trivial_usage
     80//usage:       "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2"
     81//usage:#define diff_full_usage "\n\n"
     82//usage:       "Compare files line by line and output the differences between them.\n"
     83//usage:       "This implementation supports unified diffs only.\n"
     84//usage:     "\n    -a  Treat all files as text"
     85//usage:     "\n    -b  Ignore changes in the amount of whitespace"
     86//usage:     "\n    -B  Ignore changes whose lines are all blank"
     87//usage:     "\n    -d  Try hard to find a smaller set of changes"
     88//usage:     "\n    -i  Ignore case differences"
     89//usage:     "\n    -L  Use LABEL instead of the filename in the unified header"
     90//usage:     "\n    -N  Treat absent files as empty"
     91//usage:     "\n    -q  Output only whether files differ"
     92//usage:     "\n    -r  Recurse"
     93//usage:     "\n    -S  Start with FILE when comparing directories"
     94//usage:     "\n    -T  Make tabs line up by prefixing a tab when necessary"
     95//usage:     "\n    -s  Report when two files are the same"
     96//usage:     "\n    -t  Expand tabs to spaces in output"
     97//usage:     "\n    -U  Output LINES lines of context"
     98//usage:     "\n    -w  Ignore all whitespace"
     99
    79100#include "libbb.h"
    80101
    81102#if 0
    82 //#define dbg_error_msg(...) bb_error_msg(__VA_ARGS__)
     103# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__)
    83104#else
    84 #define dbg_error_msg(...) ((void)0)
     105# define dbg_error_msg(...) ((void)0)
    85106#endif
    86107
     
    673694static int diffreg(char *file[2])
    674695{
    675     FILE *fp[2] = { stdin, stdin };
     696    FILE *fp[2];
    676697    bool binary = false, differ = false;
    677698    int status = STATUS_SAME, i;
    678699
     700    fp[0] = stdin;
     701    fp[1] = stdin;
    679702    for (i = 0; i < 2; i++) {
    680703        int fd = open_or_warn_stdin(file[i]);
     
    795818            if (r != 0 || !S_ISDIR(osb.st_mode)) {
    796819                /* other dir doesn't have similarly named
    797                  * directory, don't recurse */
     820                 * directory, don't recurse; return 1 upon
     821                 * exit, just like diffutils' diff */
     822                exit_status |= 1;
    798823                return SKIP;
    799824            }
     
    819844        list[i].len = strlen(p[i]);
    820845        recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS,
    821                          add_to_dirlist, skip_dir, &list[i], 0);
     846                add_to_dirlist, skip_dir, &list[i], 0);
    822847        /* Sort dl alphabetically.
    823848         * GNU diff does this ignoring any number of trailing dots.
     
    847872        pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1]));
    848873        k = pos > 0;
    849         if (pos && !(option_mask32 & FLAG(N)))
     874        if (pos && !(option_mask32 & FLAG(N))) {
    850875            printf("Only in %s: %s\n", p[k], dp[k]);
    851         else {
     876            exit_status |= 1;
     877        } else {
    852878            char *fullpath[2], *path[2]; /* if -N */
    853879
     
    950976        bb_error_msg_and_die("can't compare stdin to a directory");
    951977
     978    /* Compare metadata to check if the files are the same physical file.
     979     *
     980     * Comment from diffutils source says:
     981     * POSIX says that two files are identical if st_ino and st_dev are
     982     * the same, but many file systems incorrectly assign the same (device,
     983     * inode) pair to two distinct files, including:
     984     * GNU/Linux NFS servers that export all local file systems as a
     985     * single NFS file system, if a local device number (st_dev) exceeds
     986     * 255, or if a local inode number (st_ino) exceeds 16777215.
     987     */
     988    if (ENABLE_DESKTOP
     989     && stb[0].st_ino == stb[1].st_ino
     990     && stb[0].st_dev == stb[1].st_dev
     991     && stb[0].st_size == stb[1].st_size
     992     && stb[0].st_mtime == stb[1].st_mtime
     993     && stb[0].st_ctime == stb[1].st_ctime
     994     && stb[0].st_mode == stb[1].st_mode
     995     && stb[0].st_nlink == stb[1].st_nlink
     996     && stb[0].st_uid == stb[1].st_uid
     997     && stb[0].st_gid == stb[1].st_gid
     998    ) {
     999        /* files are physically the same; no need to compare them */
     1000        return STATUS_SAME;
     1001    }
     1002
    9521003    if (S_ISDIR(stb[0].st_mode) && S_ISDIR(stb[1].st_mode)) {
    9531004#if ENABLE_FEATURE_DIFF_DIR
  • branches/3.2/mindi-busybox/editors/ed.c

    r2725 r3232  
    77 * The "ed" built-in command (much simplified)
    88 */
     9
     10//usage:#define ed_trivial_usage ""
     11//usage:#define ed_full_usage ""
    912
    1013#include "libbb.h"
     
    130133         * >0 length of input string, including terminating '\n'
    131134         */
    132         len = read_line_input(": ", buf, sizeof(buf), NULL);
     135        len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1);
    133136        if (len <= 0)
    134137            return;
     
    228231            if (!dirty)
    229232                return;
    230             len = read_line_input("Really quit? ", buf, 16, NULL);
     233            len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1);
    231234            /* read error/EOF - no way to continue */
    232235            if (len < 0)
     
    452455        /*
    453456         * The new string is larger, so allocate a new line
    454          * structure and use that.  Link it in in place of
     457         * structure and use that.  Link it in place of
    455458         * the old line structure.
    456459         */
     
    542545         * >0 length of input string, including terminating '\n'
    543546         */
    544         len = read_line_input("", buf, sizeof(buf), NULL);
     547        len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1);
    545548        if (len <= 0) {
    546549            /* Previously, ctrl-C was exiting to shell.
  • branches/3.2/mindi-busybox/editors/patch.c

    r2725 r3232  
    1616 * -o outfile output here instead of in place
    1717 * -r rejectfile write rejected hunks to this file
     18 * --dry-run (regression!)
    1819 *
    1920 * -f force (no questions asked)
     
    2223 */
    2324
    24 //applet:IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP))
    25 
    26 //kbuild:lib-$(CONFIG_PATCH) += patch.o
    27 
    2825//config:config PATCH
    2926//config:   bool "patch"
     
    3128//config:   help
    3229//config:     Apply a unified diff formatted patch.
     30
     31//applet:IF_PATCH(APPLET(patch, BB_DIR_USR_BIN, BB_SUID_DROP))
     32
     33//kbuild:lib-$(CONFIG_PATCH) += patch.o
    3334
    3435//usage:#define patch_trivial_usage
     
    4041//usage:     "\n    -R,--reverse        Reverse patch"
    4142//usage:     "\n    -N,--forward        Ignore already applied patches"
    42 //usage:     "\n    --dry-run       Don't actually change files"
     43/*usage:     "\n    --dry-run       Don't actually change files" - TODO */
    4344//usage:     "\n    -E,--remove-empty-files Remove output files if they become empty"
    4445//usage:    )
     
    5051//usage:     "\n    -E  Remove output files if they become empty"
    5152//usage:    )
     53/* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */
     54/* -x "debug" is supported but does nothing */
    5255//usage:
    5356//usage:#define patch_example_usage
     
    6871// Free all the elements of a linked list
    6972// Call freeit() on each element before freeing it.
    70 static
    71 void dlist_free(struct double_list *list, void (*freeit)(void *data))
     73static void dlist_free(struct double_list *list, void (*freeit)(void *data))
    7274{
    7375    while (list) {
     
    8183
    8284// Add an entry before "list" element in (circular) doubly linked list
    83 static
    84 struct double_list *dlist_add(struct double_list **list, char *data)
     85static struct double_list *dlist_add(struct double_list **list, char *data)
    8586{
    8687    struct double_list *llist;
     
    131132#define FLAG_IGNORE  (1 << 4)
    132133#define FLAG_RMEMPTY (1 << 5)
    133 //non-standard:
    134 #define FLAG_DEBUG   (1 << 6)
     134/* Enable this bit and use -x for debug output: */
     135#define FLAG_DEBUG   (0 << 6)
    135136
    136137// Dispose of a line of input, either by writing it out or discarding it.
     
    230231        if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data);
    231232    }
    232     matcheof = matcheof < TT.context;
     233    matcheof = !matcheof || matcheof < TT.context;
    233234
    234235    if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
     
    239240    plist = TT.current_hunk;
    240241    buf = NULL;
    241     if (TT.context) for (;;) {
    242         char *data = xmalloc_reads(TT.filein, NULL, NULL);
     242    if (reverse ? TT.oldlen : TT.newlen) for (;;) {
     243        char *data = xmalloc_reads(TT.filein, NULL);
    243244
    244245        TT.linenum++;
     
    353354    char *oldname = NULL, *newname = NULL;
    354355    char *opt_p, *opt_i;
     356    long oldlen = oldlen; /* for compiler */
     357    long newlen = newlen; /* for compiler */
    355358
    356359    INIT_TT();
     
    392395                dlist_add(&TT.current_hunk, patchline);
    393396
    394                 if (*patchline != '+') TT.oldlen--;
    395                 if (*patchline != '-') TT.newlen--;
     397                if (*patchline != '+') oldlen--;
     398                if (*patchline != '-') newlen--;
    396399
    397400                // Context line?
     
    401404                // If we've consumed all expected hunk lines, apply the hunk.
    402405
    403                 if (!TT.oldlen && !TT.newlen) state = apply_one_hunk();
     406                if (!oldlen && !newlen) state = apply_one_hunk();
    404407                continue;
    405408            }
     
    448451            // Read oldline[,oldlen] +newline[,newlen]
    449452
    450             TT.oldlen = TT.newlen = 1;
     453            TT.oldlen = oldlen = TT.newlen = newlen = 1;
    451454            TT.oldline = strtol(s, &s, 10);
    452             if (*s == ',') TT.oldlen=strtol(s+1, &s, 10);
     455            if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10);
    453456            TT.newline = strtol(s+2, &s, 10);
    454             if (*s == ',') TT.newlen = strtol(s+1, &s, 10);
     457            if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10);
     458
     459            if (oldlen < 1 && newlen < 1)
     460                bb_error_msg_and_die("Really? %s", patchline);
    455461
    456462            TT.context = 0;
     
    462468                char *name;
    463469
    464                 oldsum = TT.oldline + TT.oldlen;
    465                 newsum = TT.newline + TT.newlen;
     470                oldsum = TT.oldline + oldlen;
     471                newsum = TT.newline + newlen;
    466472
    467473                name = reverse ? oldname : newname;
     
    469475                // We're deleting oldname if new file is /dev/null (before -p)
    470476                // or if new hunk is empty (zero context) after patching
    471                 if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum))
    472                 {
     477                if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) {
    473478                    name = reverse ? newname : oldname;
    474479                    empty++;
     
    476481
    477482                // handle -p path truncation.
    478                 for (i=0, s = name; *s;) {
    479                     if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break;
    480                     if (*(s++)=='/') {
    481                         name = s;
    482                         i++;
    483                     }
     483                for (i = 0, s = name; *s;) {
     484                    if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i)
     485                        break;
     486                    if (*s++ != '/')
     487                        continue;
     488                    while (*s == '/')
     489                        s++;
     490                    i++;
     491                    name = s;
    484492                }
    485493
  • branches/3.2/mindi-busybox/editors/sed.c

    r2725 r3232  
    1515
    1616/* Code overview.
    17 
    18   Files are laid out to avoid unnecessary function declarations.  So for
    19   example, every function add_cmd calls occurs before add_cmd in this file.
    20 
    21   add_cmd() is called on each line of sed command text (from a file or from
    22   the command line).  It calls get_address() and parse_cmd_args().  The
    23   resulting sed_cmd_t structures are appended to a linked list
    24   (G.sed_cmd_head/G.sed_cmd_tail).
    25 
    26   add_input_file() adds a FILE* to the list of input files.  We need to
    27   know all input sources ahead of time to find the last line for the $ match.
    28 
    29   process_files() does actual sedding, reading data lines from each input FILE *
    30   (which could be stdin) and applying the sed command list (sed_cmd_head) to
    31   each of the resulting lines.
    32 
    33   sed_main() is where external code calls into this, with a command line.
    34 */
    35 
    36 
    37 /*
    38     Supported features and commands in this version of sed:
    39 
    40      - comments ('#')
    41      - address matching: num|/matchstr/[,num|/matchstr/|$]command
    42      - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
    43      - edit commands: (a)ppend, (i)nsert, (c)hange
    44      - file commands: (r)ead
    45      - backreferences in substitution expressions (\0, \1, \2...\9)
    46      - grouped commands: {cmd1;cmd2}
    47      - transliteration (y/source-chars/dest-chars/)
    48      - pattern space hold space storing / swapping (g, h, x)
    49      - labels / branching (: label, b, t, T)
    50 
    51      (Note: Specifying an address (range) to match is *optional*; commands
    52      default to the whole pattern space if no specific address match was
    53      requested.)
    54 
    55     Todo:
    56      - Create a wrapper around regex to make libc's regex conform with sed
    57 
    58     Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
    59 */
     17 *
     18 * Files are laid out to avoid unnecessary function declarations.  So for
     19 * example, every function add_cmd calls occurs before add_cmd in this file.
     20 *
     21 * add_cmd() is called on each line of sed command text (from a file or from
     22 * the command line).  It calls get_address() and parse_cmd_args().  The
     23 * resulting sed_cmd_t structures are appended to a linked list
     24 * (G.sed_cmd_head/G.sed_cmd_tail).
     25 *
     26 * add_input_file() adds a FILE* to the list of input files.  We need to
     27 * know all input sources ahead of time to find the last line for the $ match.
     28 *
     29 * process_files() does actual sedding, reading data lines from each input FILE*
     30 * (which could be stdin) and applying the sed command list (sed_cmd_head) to
     31 * each of the resulting lines.
     32 *
     33 * sed_main() is where external code calls into this, with a command line.
     34 */
     35
     36/* Supported features and commands in this version of sed:
     37 *
     38 * - comments ('#')
     39 * - address matching: num|/matchstr/[,num|/matchstr/|$]command
     40 * - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags)
     41 * - edit commands: (a)ppend, (i)nsert, (c)hange
     42 * - file commands: (r)ead
     43 * - backreferences in substitution expressions (\0, \1, \2...\9)
     44 * - grouped commands: {cmd1;cmd2}
     45 * - transliteration (y/source-chars/dest-chars/)
     46 * - pattern space hold space storing / swapping (g, h, x)
     47 * - labels / branching (: label, b, t, T)
     48 *
     49 * (Note: Specifying an address (range) to match is *optional*; commands
     50 * default to the whole pattern space if no specific address match was
     51 * requested.)
     52 *
     53 * Todo:
     54 * - Create a wrapper around regex to make libc's regex conform with sed
     55 *
     56 * Reference
     57 * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html
     58 * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html
     59 */
     60
     61//usage:#define sed_trivial_usage
     62//usage:       "[-inr] [-f FILE]... [-e CMD]... [FILE]...\n"
     63//usage:       "or: sed [-inr] CMD [FILE]..."
     64//usage:#define sed_full_usage "\n\n"
     65//usage:       "    -e CMD  Add CMD to sed commands to be executed"
     66//usage:     "\n    -f FILE Add FILE contents to sed commands to be executed"
     67//usage:     "\n    -i[SFX] Edit files in-place (otherwise sends to stdout)"
     68//usage:     "\n        Optionally back files up, appending SFX"
     69//usage:     "\n    -n  Suppress automatic printing of pattern space"
     70//usage:     "\n    -r  Use extended regex syntax"
     71//usage:     "\n"
     72//usage:     "\nIf no -e or -f, the first non-option argument is the sed command string."
     73//usage:     "\nRemaining arguments are input files (stdin if none)."
     74//usage:
     75//usage:#define sed_example_usage
     76//usage:       "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n"
     77//usage:       "bar\n"
    6078
    6179#include "libbb.h"
    6280#include "xregex.h"
     81
     82#if 0
     83# define dbg(...) bb_error_msg(__VA_ARGS__)
     84#else
     85# define dbg(...) ((void)0)
     86#endif
     87
    6388
    6489enum {
     
    76101    regex_t *sub_match;     /* For 's/sub_match/string/' */
    77102    int beg_line;           /* 'sed 1p'   0 == apply commands to all lines */
     103    int beg_line_orig;      /* copy of the above, needed for -i */
    78104    int end_line;           /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
    79105
     
    110136
    111137    /* linked list of sed commands */
    112     sed_cmd_t sed_cmd_head, *sed_cmd_tail;
     138    sed_cmd_t *sed_cmd_head, **sed_cmd_tail;
    113139
    114140    /* Linked list of append lines */
     
    125151#define G (*(struct globals*)&bb_common_bufsiz1)
    126152struct BUG_G_too_big {
    127         char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
     153    char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
    128154};
    129155#define INIT_G() do { \
     
    135161static void sed_free_and_close_stuff(void)
    136162{
    137     sed_cmd_t *sed_cmd = G.sed_cmd_head.next;
     163    sed_cmd_t *sed_cmd = G.sed_cmd_head;
    138164
    139165    llist_free(G.append_head, free);
     
    201227static char *copy_parsing_escapes(const char *string, int len)
    202228{
     229    const char *s;
    203230    char *dest = xmalloc(len + 1);
    204231
    205     parse_escapes(dest, string, len, 'n', '\n');
    206     /* GNU sed also recognizes \t */
    207     parse_escapes(dest, dest, strlen(dest), 't', '\t');
     232    /* sed recognizes \n */
     233    /* GNU sed also recognizes \t and \r */
     234    for (s = "\nn\tt\rr"; *s; s += 2) {
     235        parse_escapes(dest, string, len, s[1], s[0]);
     236        string = dest;
     237        len = strlen(dest);
     238    }
    208239    return dest;
    209240}
     
    228259    }
    229260
    230     for (; (ch = str[idx]); idx++) {
     261    for (; (ch = str[idx]) != '\0'; idx++) {
    231262        if (bracket >= 0) {
    232             if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2
    233                     && str[idx - 1] == '^')))
     263            if (ch == ']'
     264             && !(bracket == idx - 1 || (bracket == idx - 2 && str[idx - 1] == '^'))
     265            ) {
    234266                bracket = -1;
     267            }
    235268        } else if (escaped)
    236269            escaped = 0;
     
    253286{
    254287    const char *cmdstr_ptr = cmdstr;
    255     char delimiter;
     288    unsigned char delimiter;
    256289    int idx = 0;
    257290
     
    268301    /* save the replacement string */
    269302    cmdstr_ptr += idx + 1;
    270     idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr);
     303    idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr);
    271304    *replace = copy_parsing_escapes(cmdstr_ptr, idx);
    272305
     
    293326
    294327        delimiter = '/';
    295         if (*my_str == '\\') delimiter = *++pos;
     328        if (*my_str == '\\')
     329            delimiter = *++pos;
    296330        next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
    297331        temp = copy_parsing_escapes(pos, next);
    298         *regex = xmalloc(sizeof(regex_t));
     332        *regex = xzalloc(sizeof(regex_t));
    299333        xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
    300334        free(temp);
     
    405439    if (*match != '\0') {
    406440        /* If match is empty, we use last regex used at runtime */
    407         sed_cmd->sub_match = xmalloc(sizeof(regex_t));
     441        sed_cmd->sub_match = xzalloc(sizeof(regex_t));
     442        dbg("xregcomp('%s',%x)", match, cflags);
    408443        xregcomp(sed_cmd->sub_match, match, cflags);
     444        dbg("regcomp ok");
    409445    }
    410446    free(match);
     
    418454static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
    419455{
     456    static const char cmd_letters[] = "saicrw:btTydDgGhHlnNpPqx={}";
     457    enum {
     458        IDX_s = 0,
     459        IDX_a,
     460        IDX_i,
     461        IDX_c,
     462        IDX_r,
     463        IDX_w,
     464        IDX_colon,
     465        IDX_b,
     466        IDX_t,
     467        IDX_T,
     468        IDX_y,
     469        IDX_d,
     470        IDX_D,
     471        IDX_g,
     472        IDX_G,
     473        IDX_h,
     474        IDX_H,
     475        IDX_l,
     476        IDX_n,
     477        IDX_N,
     478        IDX_p,
     479        IDX_P,
     480        IDX_q,
     481        IDX_x,
     482        IDX_equal,
     483        IDX_lbrace,
     484        IDX_rbrace,
     485        IDX_nul
     486    };
     487    struct chk { char chk[sizeof(cmd_letters)-1 == IDX_nul ? 1 : -1]; };
     488
     489    unsigned idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters;
     490
    420491    /* handle (s)ubstitution command */
    421     if (sed_cmd->cmd == 's')
     492    if (idx == IDX_s) {
    422493        cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
     494    }
    423495    /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
    424     else if (strchr("aic", sed_cmd->cmd)) {
    425         if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c')
    426             bb_error_msg_and_die("only a beginning address can be specified for edit commands");
     496    else if (idx <= IDX_c) { /* a,i,c */
     497        if (idx < IDX_c) { /* a,i */
     498            if (sed_cmd->end_line || sed_cmd->end_match)
     499                bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
     500        }
    427501        for (;;) {
    428502            if (*cmdstr == '\n' || *cmdstr == '\\') {
     
    438512        parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0');
    439513        cmdstr += strlen(cmdstr);
     514    }
    440515    /* handle file cmds: (r)ead */
    441     } else if (strchr("rw", sed_cmd->cmd)) {
    442         if (sed_cmd->end_line || sed_cmd->end_match)
    443             bb_error_msg_and_die("command only uses one address");
     516    else if (idx <= IDX_w) { /* r,w */
     517        if (idx < IDX_w) { /* r */
     518            if (sed_cmd->end_line || sed_cmd->end_match)
     519                bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd);
     520        }
    444521        cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string);
    445522        if (sed_cmd->cmd == 'w') {
     
    447524            sed_cmd->sw_last_char = '\n';
    448525        }
     526    }
    449527    /* handle branch commands */
    450     } else if (strchr(":btT", sed_cmd->cmd)) {
     528    else if (idx <= IDX_T) { /* :,b,t,T */
    451529        int length;
    452530
     
    459537    }
    460538    /* translation command */
    461     else if (sed_cmd->cmd == 'y') {
     539    else if (idx == IDX_y) {
    462540        char *match, *replace;
    463541        int i = cmdstr[0];
     
    479557     * then it must be an invalid command.
    480558     */
    481     else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
     559    else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */
    482560        bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
    483561    }
     
    541619        /* first part (if present) is an address: either a '$', a number or a /regex/ */
    542620        cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match);
     621        sed_cmd->beg_line_orig = sed_cmd->beg_line;
    543622
    544623        /* second part (if present) will begin with a comma */
     
    572651
    573652        /* Add the command to the command array */
    574         G.sed_cmd_tail->next = sed_cmd;
    575         G.sed_cmd_tail = G.sed_cmd_tail->next;
     653        *G.sed_cmd_tail = sed_cmd;
     654        G.sed_cmd_tail = &sed_cmd->next;
    576655    }
    577656
     
    601680    /* go through the replacement string */
    602681    for (i = 0; replace[i]; i++) {
    603         /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
     682        /* if we find a backreference (\1, \2, etc.) print the backref'ed text */
    604683        if (replace[i] == '\\') {
    605684            unsigned backref = replace[++i] - '0';
     
    635714{
    636715    char *line = *line_p;
    637     int altered = 0;
    638716    unsigned match_count = 0;
     717    bool altered = 0;
     718    bool prev_match_empty = 1;
     719    bool tried_at_eol = 0;
    639720    regex_t *current_regex;
    640721
     
    649730
    650731    /* Find the first match */
    651     if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0))
     732    dbg("matching '%s'", line);
     733    if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) {
     734        dbg("no match");
    652735        return 0;
     736    }
     737    dbg("match");
    653738
    654739    /* Initialize temporary output buffer. */
     
    659744    /* Now loop through, substituting for matches */
    660745    do {
     746        int start = G.regmatch[0].rm_so;
     747        int end = G.regmatch[0].rm_eo;
    661748        int i;
    662749
    663         /* Work around bug in glibc regexec, demonstrated by:
    664            echo " a.b" | busybox sed 's [^ .]* x g'
    665            The match_count check is so not to break
    666            echo "hi" | busybox sed 's/^/!/g' */
    667         if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
    668             pipe_putc(*line++);
    669             continue;
    670         }
    671 
    672750        match_count++;
    673751
    674752        /* If we aren't interested in this match, output old line to
    675            end of match and continue */
     753         * end of match and continue */
    676754        if (sed_cmd->which_match
    677755         && (sed_cmd->which_match != match_count)
    678756        ) {
    679             for (i = 0; i < G.regmatch[0].rm_eo; i++)
     757            for (i = 0; i < end; i++)
    680758                pipe_putc(*line++);
    681             continue;
    682         }
    683 
    684         /* print everything before the match */
    685         for (i = 0; i < G.regmatch[0].rm_so; i++)
     759            /* Null match? Print one more char */
     760            if (start == end && *line)
     761                pipe_putc(*line++);
     762            goto next;
     763        }
     764
     765        /* Print everything before the match */
     766        for (i = 0; i < start; i++)
    686767            pipe_putc(line[i]);
    687768
    688         /* then print the substitution string */
    689         do_subst_w_backrefs(line, sed_cmd->string);
    690 
    691         /* advance past the match */
    692         line += G.regmatch[0].rm_eo;
    693         /* flag that something has changed */
    694         altered++;
     769        /* Then print the substitution string,
     770         * unless we just matched empty string after non-empty one.
     771         * Example: string "cccd", pattern "c*", repl "R":
     772         * result is "RdR", not "RRdR": first match "ccc",
     773         * second is "" before "d", third is "" after "d".
     774         * Second match is NOT replaced!
     775         */
     776        if (prev_match_empty || start != 0 || start != end) {
     777            //dbg("%d %d %d", prev_match_empty, start, end);
     778            dbg("inserting replacement at %d in '%s'", start, line);
     779            do_subst_w_backrefs(line, sed_cmd->string);
     780            /* Flag that something has changed */
     781            altered = 1;
     782        } else {
     783            dbg("NOT inserting replacement at %d in '%s'", start, line);
     784        }
     785
     786        /* If matched string is empty (f.e. "c*" pattern),
     787         * copy verbatim one char after it before attempting more matches
     788         */
     789        prev_match_empty = (start == end);
     790        if (prev_match_empty) {
     791            if (!line[end]) {
     792                tried_at_eol = 1;
     793            } else {
     794                pipe_putc(line[end]);
     795                end++;
     796            }
     797        }
     798
     799        /* Advance past the match */
     800        dbg("line += %d", end);
     801        line += end;
    695802
    696803        /* if we're not doing this globally, get out now */
    697         if (sed_cmd->which_match)
    698             break;
    699 
    700 //maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
    701     } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
     804        if (sed_cmd->which_match != 0)
     805            break;
     806 next:
     807        /* Exit if we are at EOL and already tried matching at it */
     808        if (*line == '\0') {
     809            if (tried_at_eol)
     810                break;
     811            tried_at_eol = 1;
     812        }
     813
     814//maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL?
     815    } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH);
    702816
    703817    /* Copy rest of string into output pipeline */
     
    719833    sed_cmd_t *sed_cmd;
    720834
    721     for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     835    for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
    722836        if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
    723837            return sed_cmd;
     
    8951009    /* For every line, go through all the commands */
    8961010 restart:
    897     for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     1011    for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
    8981012        int old_matched, matched;
    8991013
     
    9021016        /* Determine if this command matches this line: */
    9031017
    904         //bb_error_msg("match1:%d", sed_cmd->in_match);
    905         //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
    906         //      && !sed_cmd->beg_match && !sed_cmd->end_match));
    907         //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0
    908         //  && (sed_cmd->end_line || sed_cmd->end_match
    909         //      ? (sed_cmd->beg_line <= linenum)
    910         //      : (sed_cmd->beg_line == linenum)
    911         //      )
    912         //  )
    913         //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space)));
    914         //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
     1018        dbg("match1:%d", sed_cmd->in_match);
     1019        dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line
     1020                && !sed_cmd->beg_match && !sed_cmd->end_match));
     1021        dbg("match3:%d", (sed_cmd->beg_line > 0
     1022            && (sed_cmd->end_line || sed_cmd->end_match
     1023                ? (sed_cmd->beg_line <= linenum)
     1024                : (sed_cmd->beg_line == linenum)
     1025                )
     1026            ));
     1027        dbg("match4:%d", (beg_match(sed_cmd, pattern_space)));
     1028        dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL));
    9151029
    9161030        /* Are we continuing a previous multi-line match? */
     
    9231037                && (sed_cmd->end_line || sed_cmd->end_match
    9241038                  /* note: even if end is numeric and is < linenum too,
    925                    * GNU sed matches! We match too */
     1039                   * GNU sed matches! We match too, therefore we don't
     1040                   * check here that linenum <= end.
     1041                   * Example:
     1042                   * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p'
     1043                   * first three input lines are deleted;
     1044                   * 4th line is matched and printed
     1045                   * by "2,3" (!) and by "4" ranges
     1046                   */
    9261047                ? (sed_cmd->beg_line <= linenum)    /* N,end */
    9271048                : (sed_cmd->beg_line == linenum)    /* N */
     
    9361057        matched = sed_cmd->in_match;
    9371058
    938         //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
    939         //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
     1059        dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d",
     1060            sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum);
    9401061
    9411062        /* Is this line the end of the current match? */
     
    9431064        if (matched) {
    9441065            /* once matched, "n,xxx" range is dead, disabling it */
    945             if (sed_cmd->beg_line > 0
    946              && !(option_mask32 & OPT_in_place) /* but not for -i */
    947             ) {
     1066            if (sed_cmd->beg_line > 0) {
    9481067                sed_cmd->beg_line = -2;
    9491068            }
    9501069            sed_cmd->in_match = !(
    9511070                /* has the ending line come, or is this a single address command? */
    952                 (sed_cmd->end_line ?
    953                     sed_cmd->end_line == -1 ?
    954                         !next_line
     1071                (sed_cmd->end_line
     1072                    ? sed_cmd->end_line == -1
     1073                        ? !next_line
    9551074                        : (sed_cmd->end_line <= linenum)
    9561075                    : !sed_cmd->end_match
     
    9591078                || (sed_cmd->end_match && old_matched
    9601079                     && (regexec(sed_cmd->end_match,
    961                                  pattern_space, 0, NULL, 0) == 0))
     1080                        pattern_space, 0, NULL, 0) == 0)
     1081                )
    9621082            );
    9631083        }
     
    9931113
    9941114        /* actual sedding */
    995         //bb_error_msg("pattern_space:'%s' next_line:'%s' cmd:%c",
    996         //pattern_space, next_line, sed_cmd->cmd);
     1115        dbg("pattern_space:'%s' next_line:'%s' cmd:%c",
     1116                pattern_space, next_line, sed_cmd->cmd);
    9971117        switch (sed_cmd->cmd) {
    9981118
     
    10411161            if (!do_subst_command(sed_cmd, &pattern_space))
    10421162                break;
     1163            dbg("do_subst_command succeeded:'%s'", pattern_space);
    10431164            substituted |= 1;
    10441165
     
    12881409    unsigned opt;
    12891410    llist_t *opt_e, *opt_f;
     1411    char *opt_i;
     1412
     1413#if ENABLE_LONG_OPTS
     1414    static const char sed_longopts[] ALIGN1 =
     1415        /* name             has_arg             short */
     1416        "in-place\0"        Optional_argument   "i"
     1417        "regexp-extended\0" No_argument         "r"
     1418        "quiet\0"           No_argument         "n"
     1419        "silent\0"          No_argument         "n"
     1420        "expression\0"      Required_argument   "e"
     1421        "file\0"            Required_argument   "f";
     1422#endif
     1423
    12901424    int status = EXIT_SUCCESS;
    12911425
     
    12961430
    12971431    /* Lie to autoconf when it starts asking stupid questions. */
    1298     if (argv[1] && !strcmp(argv[1], "--version")) {
     1432    if (argv[1] && strcmp(argv[1], "--version") == 0) {
    12991433        puts("This is not GNU sed version 4.0");
    13001434        return 0;
     
    13031437    /* do normal option parsing */
    13041438    opt_e = opt_f = NULL;
     1439    opt_i = NULL;
    13051440    opt_complementary = "e::f::" /* can occur multiple times */
    13061441                        "nn"; /* count -n */
     1442
     1443    IF_LONG_OPTS(applet_long_options = sed_longopts);
     1444
    13071445    /* -i must be first, to match OPT_in_place definition */
    1308     opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
     1446    opt = getopt32(argv, "i::rne:f:", &opt_i, &opt_e, &opt_f,
    13091447                &G.be_quiet); /* counter for -n */
    13101448    //argc -= optind;
     
    13491487    } else {
    13501488        int i;
    1351         FILE *file;
    13521489
    13531490        for (i = 0; argv[i]; i++) {
    13541491            struct stat statbuf;
    13551492            int nonstdoutfd;
     1493            FILE *file;
     1494            sed_cmd_t *sed_cmd;
    13561495
    13571496            if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
     
    13651504                continue;
    13661505            }
     1506            add_input_file(file);
    13671507            if (!(opt & OPT_in_place)) {
    1368                 add_input_file(file);
    13691508                continue;
    13701509            }
     1510
     1511            /* -i: process each FILE separately: */
    13711512
    13721513            G.outname = xasprintf("%sXXXXXX", argv[i]);
     
    13801521            fchmod(nonstdoutfd, statbuf.st_mode);
    13811522            fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid);
    1382             add_input_file(file);
     1523
    13831524            process_files();
    13841525            fclose(G.nonstdout);
    1385 
    13861526            G.nonstdout = stdout;
    1387             /* unlink(argv[i]); */
    1388             xrename(G.outname, argv[i]);
     1527
     1528            if (opt_i) {
     1529                char *backupname = xasprintf("%s%s", argv[i], opt_i);
     1530                xrename(argv[i], backupname);
     1531                free(backupname);
     1532            }
     1533            /* else unlink(argv[i]); - rename below does this */
     1534            xrename(G.outname, argv[i]); //TODO: rollback backup on error?
    13891535            free(G.outname);
    13901536            G.outname = NULL;
     1537
     1538            /* Re-enable disabled range matches */
     1539            for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) {
     1540                sed_cmd->beg_line = sed_cmd->beg_line_orig;
     1541            }
    13911542        }
    13921543        /* Here, to handle "sed 'cmds' nonexistent_file" case we did:
  • branches/3.2/mindi-busybox/editors/vi.c

    r2725 r3232  
    1515 *  :map macros
    1616 *  if mark[] values were line numbers rather than pointers
    17  *     it would be easier to change the mark when add/delete lines
     17 *      it would be easier to change the mark when add/delete lines
    1818 *  More intelligence in refresh()
    1919 *  ":r !cmd"  and  "!cmd"  to filter text through an external command
     
    2222 */
    2323
     24//config:config VI
     25//config:   bool "vi"
     26//config:   default y
     27//config:   help
     28//config:     'vi' is a text editor. More specifically, it is the One True
     29//config:     text editor <grin>. It does, however, have a rather steep
     30//config:     learning curve. If you are not already comfortable with 'vi'
     31//config:     you may wish to use something else.
     32//config:
     33//config:config FEATURE_VI_MAX_LEN
     34//config:   int "Maximum screen width in vi"
     35//config:   range 256 16384
     36//config:   default 4096
     37//config:   depends on VI
     38//config:   help
     39//config:     Contrary to what you may think, this is not eating much.
     40//config:     Make it smaller than 4k only if you are very limited on memory.
     41//config:
     42//config:config FEATURE_VI_8BIT
     43//config:   bool "Allow vi to display 8-bit chars (otherwise shows dots)"
     44//config:   default n
     45//config:   depends on VI
     46//config:   help
     47//config:     If your terminal can display characters with high bit set,
     48//config:     you may want to enable this. Note: vi is not Unicode-capable.
     49//config:     If your terminal combines several 8-bit bytes into one character
     50//config:     (as in Unicode mode), this will not work properly.
     51//config:
     52//config:config FEATURE_VI_COLON
     53//config:   bool "Enable \":\" colon commands (no \"ex\" mode)"
     54//config:   default y
     55//config:   depends on VI
     56//config:   help
     57//config:     Enable a limited set of colon commands for vi. This does not
     58//config:     provide an "ex" mode.
     59//config:
     60//config:config FEATURE_VI_YANKMARK
     61//config:   bool "Enable yank/put commands and mark cmds"
     62//config:   default y
     63//config:   depends on VI
     64//config:   help
     65//config:     This will enable you to use yank and put, as well as mark in
     66//config:     busybox vi.
     67//config:
     68//config:config FEATURE_VI_SEARCH
     69//config:   bool "Enable search and replace cmds"
     70//config:   default y
     71//config:   depends on VI
     72//config:   help
     73//config:     Select this if you wish to be able to do search and replace in
     74//config:     busybox vi.
     75//config:
     76//config:config FEATURE_VI_REGEX_SEARCH
     77//config:   bool "Enable regex in search and replace"
     78//config:   default n   # Uses GNU regex, which may be unavailable. FIXME
     79//config:   depends on FEATURE_VI_SEARCH
     80//config:   help
     81//config:     Use extended regex search.
     82//config:
     83//config:config FEATURE_VI_USE_SIGNALS
     84//config:   bool "Catch signals"
     85//config:   default y
     86//config:   depends on VI
     87//config:   help
     88//config:     Selecting this option will make busybox vi signal aware. This will
     89//config:     make busybox vi support SIGWINCH to deal with Window Changes, catch
     90//config:     Ctrl-Z and Ctrl-C and alarms.
     91//config:
     92//config:config FEATURE_VI_DOT_CMD
     93//config:   bool "Remember previous cmd and \".\" cmd"
     94//config:   default y
     95//config:   depends on VI
     96//config:   help
     97//config:     Make busybox vi remember the last command and be able to repeat it.
     98//config:
     99//config:config FEATURE_VI_READONLY
     100//config:   bool "Enable -R option and \"view\" mode"
     101//config:   default y
     102//config:   depends on VI
     103//config:   help
     104//config:     Enable the read-only command line option, which allows the user to
     105//config:     open a file in read-only mode.
     106//config:
     107//config:config FEATURE_VI_SETOPTS
     108//config:   bool "Enable set-able options, ai ic showmatch"
     109//config:   default y
     110//config:   depends on VI
     111//config:   help
     112//config:     Enable the editor to set some (ai, ic, showmatch) options.
     113//config:
     114//config:config FEATURE_VI_SET
     115//config:   bool "Support for :set"
     116//config:   default y
     117//config:   depends on VI
     118//config:   help
     119//config:     Support for ":set".
     120//config:
     121//config:config FEATURE_VI_WIN_RESIZE
     122//config:   bool "Handle window resize"
     123//config:   default y
     124//config:   depends on VI
     125//config:   help
     126//config:     Make busybox vi behave nicely with terminals that get resized.
     127//config:
     128//config:config FEATURE_VI_ASK_TERMINAL
     129//config:   bool "Use 'tell me cursor position' ESC sequence to measure window"
     130//config:   default y
     131//config:   depends on VI
     132//config:   help
     133//config:     If terminal size can't be retrieved and $LINES/$COLUMNS are not set,
     134//config:     this option makes vi perform a last-ditch effort to find it:
     135//config:     position cursor to 999,999 and ask terminal to report real
     136//config:     cursor position using "ESC [ 6 n" escape sequence, then read stdin.
     137//config:
     138//config:     This is not clean but helps a lot on serial lines and such.
     139
     140//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP))
     141
     142//kbuild:lib-$(CONFIG_VI) += vi.o
     143
     144//usage:#define vi_trivial_usage
     145//usage:       "[OPTIONS] [FILE]..."
     146//usage:#define vi_full_usage "\n\n"
     147//usage:       "Edit FILE\n"
     148//usage:    IF_FEATURE_VI_COLON(
     149//usage:     "\n    -c CMD  Initial command to run ($EXINIT also available)"
     150//usage:    )
     151//usage:    IF_FEATURE_VI_READONLY(
     152//usage:     "\n    -R  Read-only"
     153//usage:    )
     154//usage:     "\n    -H  List available features"
     155
    24156#include "libbb.h"
     157/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */
     158#if ENABLE_FEATURE_VI_REGEX_SEARCH
     159# include <regex.h>
     160#endif
    25161
    26162/* the CRASHME code is unmaintained, and doesn't currently build */
     
    41177/* 0x9b is Meta-ESC */
    42178#if ENABLE_FEATURE_VI_8BIT
    43 #define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)
     179# define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)
    44180#else
    45 #define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f)
     181# define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f)
    46182#endif
    47183
     
    59195};
    60196
    61 /* vt102 typical ESC sequence */
    62 /* terminal standout start/normal ESC sequence */
    63 #define SOs "\033[7m"
    64 #define SOn "\033[0m"
    65 /* terminal bell sequence */
    66 #define bell "\007"
    67 /* Clear-end-of-line and Clear-end-of-screen ESC sequence */
    68 #define Ceol "\033[K"
    69 #define Ceos "\033[J"
    70 /* Cursor motion arbitrary destination ESC sequence */
    71 #define CMrc "\033[%u;%uH"
    72 /* Cursor motion up and down ESC sequence */
    73 #define CMup "\033[A"
    74 #define CMdown "\n"
     197/* VT102 ESC sequences.
     198 * See "Xterm Control Sequences"
     199 * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
     200 */
     201/* Inverse/Normal text */
     202#define ESC_BOLD_TEXT "\033[7m"
     203#define ESC_NORM_TEXT "\033[0m"
     204/* Bell */
     205#define ESC_BELL "\007"
     206/* Clear-to-end-of-line */
     207#define ESC_CLEAR2EOL "\033[K"
     208/* Clear-to-end-of-screen.
     209 * (We use default param here.
     210 * Full sequence is "ESC [ <num> J",
     211 * <num> is 0/1/2 = "erase below/above/all".)
     212 */
     213#define ESC_CLEAR2EOS "\033[J"
     214/* Cursor to given coordinate (1,1: top left) */
     215#define ESC_SET_CURSOR_POS "\033[%u;%uH"
     216//UNUSED
     217///* Cursor up and down */
     218//#define ESC_CURSOR_UP "\033[A"
     219//#define ESC_CURSOR_DOWN "\n"
    75220
    76221#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
     
    135280    int file_modified;       // buffer contents changed (counter, not flag!)
    136281    int last_file_modified;  // = -1;
    137     int fn_start;            // index of first cmd line file name
    138282    int save_argc;           // how many file names on cmd line
    139283    int cmdcnt;              // repetition count
     
    161305    char *ioq, *ioq_start;   // pointer to string for get_one_char to "read"
    162306#endif
    163 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    164     int last_row;        // where the cursor was last moved to
    165 #endif
    166307#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
    167308    int my_pid;
     
    220361#define file_modified           (G.file_modified      )
    221362#define last_file_modified      (G.last_file_modified )
    222 #define fn_start                (G.fn_start           )
    223363#define save_argc               (G.save_argc          )
    224364#define cmdcnt                  (G.cmdcnt             )
     
    248388#define ioq                     (G.ioq                )
    249389#define ioq_start               (G.ioq_start          )
    250 #define last_row                (G.last_row           )
    251390#define my_pid                  (G.my_pid             )
    252391#define last_search_pattern     (G.last_search_pattern)
     
    329468static int file_insert(const char *, char *, int);
    330469static int file_write(char *, char *, char *);
    331 #if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    332 #define place_cursor(a, b, optimize) place_cursor(a, b)
    333 #endif
    334 static void place_cursor(int, int, int);
     470static void place_cursor(int, int);
    335471static void screen_erase(void);
    336472static void clear_to_eol(void);
     
    355491#if ENABLE_FEATURE_VI_SEARCH
    356492static char *char_search(char *, const char *, int, int);   // search for pattern starting at p
    357 static int mycmp(const char *, const char *, int);  // string cmp based in "ignorecase"
    358493#endif
    359494#if ENABLE_FEATURE_VI_COLON
     
    418553#endif
    419554
    420     vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE;
     555    // autoindent is not default in vim 7.3
     556    vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE;
    421557    //  1-  process $HOME/.exrc file (not inplemented yet)
    422558    //  2-  process EXINIT variable from environment
     
    444580        case 'c':       // cmd line vi command
    445581            if (*optarg)
    446                 initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN);
     582                initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN);
    447583            break;
    448584#endif
     
    457593
    458594    // The argv array can be used by the ":next"  and ":rewind" commands
    459     // save optind.
    460     fn_start = optind;  // remember first file name for :next and :rew
     595    argv += optind;
     596    argc -= optind;
     597
     598    //----- This is the main file handling loop --------------
    461599    save_argc = argc;
    462 
    463     //----- This is the main file handling loop --------------
     600    optind = 0;
     601    // "Save cursor, use alternate screen buffer, clear screen"
     602    write1("\033[?1049h");
    464603    while (1) {
    465604        edit_file(argv[optind]); /* param might be NULL */
     
    467606            break;
    468607    }
     608    // "Use normal screen buffer, restore cursor"
     609    write1("\033[?1049l");
    469610    //-----------------------------------------------------------
    470611
     
    524665#endif
    525666    int c;
    526     int size;
    527667#if ENABLE_FEATURE_VI_USE_SIGNALS
    528668    int sig;
     
    533673    rows = 24;
    534674    columns = 80;
    535     size = 0;
    536675    IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions();
    537676#if ENABLE_FEATURE_VI_ASK_TERMINAL
     
    8811020        // don't edit, if the current file has been modified
    8821021        if (file_modified && !useforce) {
    883             status_line_bold("No write since last change (:edit! overrides)");
     1022            status_line_bold("No write since last change (:%s! overrides)", cmd);
    8841023            goto ret;
    8851024        }
     
    9001039
    9011040#if ENABLE_FEATURE_VI_YANKMARK
    902         if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
     1041        if (Ureg >= 0 && Ureg < 28) {
    9031042            free(reg[Ureg]);    //   free orig line reg- for 'U'
    904             reg[Ureg]= 0;
    905         }
    906         if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) {
     1043            reg[Ureg] = NULL;
     1044        }
     1045        if (YDreg >= 0 && YDreg < 28) {
    9071046            free(reg[YDreg]);   //   free default yank/delete register
    908             reg[YDreg]= 0;
     1047            reg[YDreg] = NULL;
    9091048        }
    9101049#endif
     
    9711110    } else if (strncmp(cmd, "quit", i) == 0 // quit
    9721111            || strncmp(cmd, "next", i) == 0 // edit next file
     1112            || strncmp(cmd, "prev", i) == 0 // edit previous file
    9731113    ) {
    9741114        int n;
    9751115        if (useforce) {
    976             // force end of argv list
    9771116            if (*cmd == 'q') {
     1117                // force end of argv list
    9781118                optind = save_argc;
    9791119            }
     
    9831123        // don't exit if the file been modified
    9841124        if (file_modified) {
    985             status_line_bold("No write since last change (:%s! overrides)",
    986                  (*cmd == 'q' ? "quit" : "next"));
     1125            status_line_bold("No write since last change (:%s! overrides)", cmd);
    9871126            goto ret;
    9881127        }
     
    9961135            status_line_bold("No more files to edit");
    9971136            goto ret;
     1137        }
     1138        if (*cmd == 'p') {
     1139            // are there previous files to edit
     1140            if (optind < 1) {
     1141                status_line_bold("No previous files to edit");
     1142                goto ret;
     1143            }
     1144            optind -= 2;
    9981145        }
    9991146        editing = 0;
     
    10321179    } else if (strncmp(cmd, "rewind", i) == 0) {    // rewind cmd line args
    10331180        if (file_modified && !useforce) {
    1034             status_line_bold("No write since last change (:rewind! overrides)");
     1181            status_line_bold("No write since last change (:%s! overrides)", cmd);
    10351182        } else {
    10361183            // reset the filenames to edit
    1037             optind = fn_start - 1;
     1184            optind = -1; /* start from 0th file */
    10381185            editing = 0;
    10391186        }
     
    10441191#endif
    10451192        i = 0;          // offset into args
    1046         // only blank is regarded as args delmiter. What about tab '\t' ?
     1193        // only blank is regarded as args delimiter. What about tab '\t'?
    10471194        if (!args[0] || strcasecmp(args, "all") == 0) {
    10481195            // print out values of all options
     
    10851232#if ENABLE_FEATURE_VI_SEARCH
    10861233    } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern
    1087         char *ls, *F, *R;
    1088         int gflag;
     1234        char *F, *R, *flags;
     1235        size_t len_F, len_R;
     1236        int gflag;      // global replace flag
    10891237
    10901238        // F points to the "find" pattern
    10911239        // R points to the "replace" pattern
    1092         // replace the cmd line delimiters "/" with NULLs
    1093         gflag = 0;      // global replace flag
     1240        // replace the cmd line delimiters "/" with NULs
    10941241        c = orig_buf[1];    // what is the delimiter
    10951242        F = orig_buf + 2;   // start of "find"
     
    10971244        if (!R)
    10981245            goto colon_s_fail;
     1246        len_F = R - F;
    10991247        *R++ = '\0';    // terminate "find"
    1100         buf1 = strchr(R, c);
    1101         if (!buf1)
     1248        flags = strchr(R, c);
     1249        if (!flags)
    11021250            goto colon_s_fail;
    1103         *buf1++ = '\0'; // terminate "replace"
    1104         if (*buf1 == 'g') { // :s/foo/bar/g
    1105             buf1++;
    1106             gflag++;    // turn on gflag
    1107         }
     1251        len_R = flags - R;
     1252        *flags++ = '\0';    // terminate "replace"
     1253        gflag = *flags;
     1254
    11081255        q = begin_line(q);
    11091256        if (b < 0) {    // maybe :s/foo/bar/
    1110             q = begin_line(dot);    // start with cur line
    1111             b = count_lines(text, q);   // cur line number
     1257            q = begin_line(dot);      // start with cur line
     1258            b = count_lines(text, q); // cur line number
    11121259        }
    11131260        if (e < 0)
    11141261            e = b;      // maybe :.s/foo/bar/
     1262
    11151263        for (i = b; i <= e; i++) {  // so, :20,23 s \0 find \0 replace \0
    1116             ls = q;     // orig line start
     1264            char *ls = q;       // orig line start
     1265            char *found;
    11171266 vc4:
    1118             buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
    1119             if (buf1) {
     1267            found = char_search(q, F, FORWARD, LIMITED);    // search cur line only for "find"
     1268            if (found) {
    11201269                uintptr_t bias;
    11211270                // we found the "find" pattern - delete it
    1122                 text_hole_delete(buf1, buf1 + strlen(F) - 1);
     1271                text_hole_delete(found, found + len_F - 1);
    11231272                // inset the "replace" patern
    1124                 bias = string_insert(buf1, R);  // insert the string
    1125                 buf1 += bias;
     1273                bias = string_insert(found, R); // insert the string
     1274                found += bias;
    11261275                ls += bias;
    11271276                /*q += bias; - recalculated anyway */
    11281277                // check for "global"  :s/foo/bar/g
    1129                 if (gflag == 1) {
    1130                     if ((buf1 + strlen(R)) < end_line(ls)) {
    1131                         q = buf1 + strlen(R);
     1278                if (gflag == 'g') {
     1279                    if ((found + len_R) < end_line(ls)) {
     1280                        q = found + len_R;
    11321281                        goto vc4;   // don't let q move past cur line
    11331282                    }
     
    15521701
    15531702#if ENABLE_FEATURE_VI_SEARCH
    1554 static int mycmp(const char *s1, const char *s2, int len)
    1555 {
    1556     if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) {
    1557         return strncasecmp(s1, s2, len);
    1558     }
    1559     return strncmp(s1, s2, len);
    1560 }
     1703
     1704# if ENABLE_FEATURE_VI_REGEX_SEARCH
    15611705
    15621706// search for pattern starting at p
    15631707static char *char_search(char *p, const char *pat, int dir, int range)
    15641708{
    1565 #ifndef REGEX_SEARCH
    1566     char *start, *stop;
    1567     int len;
    1568 
    1569     len = strlen(pat);
    1570     if (dir == FORWARD) {
    1571         stop = end - 1; // assume range is p - end-1
    1572         if (range == LIMITED)
    1573             stop = next_line(p);    // range is to next line
    1574         for (start = p; start < stop; start++) {
    1575             if (mycmp(start, pat, len) == 0) {
    1576                 return start;
    1577             }
    1578         }
    1579     } else if (dir == BACK) {
    1580         stop = text;    // assume range is text - p
    1581         if (range == LIMITED)
    1582             stop = prev_line(p);    // range is to prev line
    1583         for (start = p - len; start >= stop; start--) {
    1584             if (mycmp(start, pat, len) == 0) {
    1585                 return start;
    1586             }
    1587         }
    1588     }
    1589     // pattern not found
    1590     return NULL;
    1591 #else /* REGEX_SEARCH */
    15921709    char *q;
    15931710    struct re_pattern_buffer preg;
    15941711    int i;
    1595     int size, range;
     1712    int size;
    15961713
    15971714    re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
     
    16161733    range = q - p;
    16171734
    1618     q = re_compile_pattern(pat, strlen(pat), &preg);
     1735    q = (char *)re_compile_pattern(pat, strlen(pat), (struct re_pattern_buffer *)&preg);
    16191736    if (q != 0) {
    16201737        // The pattern was not compiled
     
    16501767    }
    16511768    return p;
    1652 #endif /* REGEX_SEARCH */
    1653 }
     1769}
     1770
     1771# else
     1772
     1773#  if ENABLE_FEATURE_VI_SETOPTS
     1774static int mycmp(const char *s1, const char *s2, int len)
     1775{
     1776    if (ignorecase) {
     1777        return strncasecmp(s1, s2, len);
     1778    }
     1779    return strncmp(s1, s2, len);
     1780}
     1781#  else
     1782#   define mycmp strncmp
     1783#  endif
     1784
     1785static char *char_search(char *p, const char *pat, int dir, int range)
     1786{
     1787    char *start, *stop;
     1788    int len;
     1789
     1790    len = strlen(pat);
     1791    if (dir == FORWARD) {
     1792        stop = end - 1; // assume range is p - end-1
     1793        if (range == LIMITED)
     1794            stop = next_line(p);    // range is to next line
     1795        for (start = p; start < stop; start++) {
     1796            if (mycmp(start, pat, len) == 0) {
     1797                return start;
     1798            }
     1799        }
     1800    } else if (dir == BACK) {
     1801        stop = text;    // assume range is text - p
     1802        if (range == LIMITED)
     1803            stop = prev_line(p);    // range is to prev line
     1804        for (start = p - len; start >= stop; start--) {
     1805            if (mycmp(start, pat, len) == 0) {
     1806                return start;
     1807            }
     1808        }
     1809    }
     1810    // pattern not found
     1811    return NULL;
     1812}
     1813
     1814# endif
     1815
    16541816#endif /* FEATURE_VI_SEARCH */
    16551817
     
    16781840        }
    16791841    } else {
     1842#if ENABLE_FEATURE_VI_SETOPTS
    16801843        // insert a char into text[]
    16811844        char *sp;       // "save p"
     1845#endif
    16821846
    16831847        if (c == 13)
    16841848            c = '\n';   // translate \r to \n
     1849#if ENABLE_FEATURE_VI_SETOPTS
    16851850        sp = p;         // remember addr of insert
     1851#endif
    16861852        p += 1 + stupid_insert(p, c);   // insert the char
    16871853#if ENABLE_FEATURE_VI_SETOPTS
     
    17641930        q = dot;
    17651931    } else {
    1766         // nothing -- this causes any other values of c to
    1767         // represent the one-character range under the
    1768         // cursor.  this is correct for ' ' and 'l', but
    1769         // perhaps no others.
    1770         //
     1932        // nothing -- this causes any other values of c to
     1933        // represent the one-character range under the
     1934        // cursor.  this is correct for ' ' and 'l', but
     1935        // perhaps no others.
     1936        //
    17711937    }
    17721938    if (q < p) {
     
    19162082        end         += bias;
    19172083        p           += bias;
     2084#if ENABLE_FEATURE_VI_YANKMARK
     2085        {
     2086            int i;
     2087            for (i = 0; i < ARRAY_SIZE(mark); i++)
     2088                if (mark[i])
     2089                    mark[i] += bias;
     2090        }
     2091#endif
    19182092        text = new_text;
    19192093    }
     
    20022176#endif
    20032177#if ENABLE_FEATURE_VI_DOT_CMD
    2004     "\n\tLast command repeat with \'.\'"
     2178    "\n\tLast command repeat with ."
    20052179#endif
    20062180#if ENABLE_FEATURE_VI_YANKMARK
     
    20092183#endif
    20102184#if ENABLE_FEATURE_VI_READONLY
    2011     "\n\tReadonly if vi is called as \"view\""
    2012     "\n\tReadonly with -R command line arg"
     2185    //not implemented: "\n\tReadonly if vi is called as \"view\""
     2186    //redundant: usage text says this too: "\n\tReadonly with -R command line arg"
    20132187#endif
    20142188#if ENABLE_FEATURE_VI_SET
    2015     "\n\tSome colon mode commands with \':\'"
     2189    "\n\tSome colon mode commands with :"
    20162190#endif
    20172191#if ENABLE_FEATURE_VI_SETOPTS
     
    21472321    tcgetattr(0, &term_orig);
    21482322    term_vi = term_orig;
    2149     term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG ON- allow intr's
     2323    term_vi.c_lflag &= (~ICANON & ~ECHO);   // leave ISIG on - allow intr's
    21502324    term_vi.c_iflag &= (~IXON & ~ICRNL);
    21512325    term_vi.c_oflag &= (~ONLCR);
     
    24182592
    24192593//----- Move the cursor to row x col (count from 0, not 1) -------
    2420 static void place_cursor(int row, int col, int optimize)
    2421 {
    2422     char cm1[sizeof(CMrc) + sizeof(int)*3 * 2];
    2423 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    2424     enum {
    2425         SZ_UP = sizeof(CMup),
    2426         SZ_DN = sizeof(CMdown),
    2427         SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN,
    2428     };
    2429     char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size
    2430 #endif
    2431     char *cm;
     2594static void place_cursor(int row, int col)
     2595{
     2596    char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2];
    24322597
    24332598    if (row < 0) row = 0;
     
    24362601    if (col >= columns) col = columns - 1;
    24372602
    2438     //----- 1.  Try the standard terminal ESC sequence
    2439     sprintf(cm1, CMrc, row + 1, col + 1);
    2440     cm = cm1;
    2441 
    2442 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    2443     if (optimize && col < 16) {
    2444         char *screenp;
    2445         int Rrow = last_row;
    2446         int diff = Rrow - row;
    2447 
    2448         if (diff < -5 || diff > 5)
    2449             goto skip;
    2450 
    2451         //----- find the minimum # of chars to move cursor -------------
    2452         //----- 2.  Try moving with discreet chars (Newline, [back]space, ...)
    2453         cm2[0] = '\0';
    2454 
    2455         // move to the correct row
    2456         while (row < Rrow) {
    2457             // the cursor has to move up
    2458             strcat(cm2, CMup);
    2459             Rrow--;
    2460         }
    2461         while (row > Rrow) {
    2462             // the cursor has to move down
    2463             strcat(cm2, CMdown);
    2464             Rrow++;
    2465         }
    2466 
    2467         // now move to the correct column
    2468         strcat(cm2, "\r");          // start at col 0
    2469         // just send out orignal source char to get to correct place
    2470         screenp = &screen[row * columns];   // start of screen line
    2471         strncat(cm2, screenp, col);
    2472 
    2473         // pick the shortest cursor motion to send out
    2474         if (strlen(cm2) < strlen(cm)) {
    2475             cm = cm2;
    2476         }
    2477  skip: ;
    2478     }
    2479     last_row = row;
    2480 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */
    2481     write1(cm);
     2603    sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1);
     2604    write1(cm1);
    24822605}
    24832606
     
    24852608static void clear_to_eol(void)
    24862609{
    2487     write1(Ceol);   // Erase from cursor to end of line
     2610    write1(ESC_CLEAR2EOL);
    24882611}
    24892612
    24902613static void go_bottom_and_clear_to_eol(void)
    24912614{
    2492     place_cursor(rows - 1, 0, FALSE); // go to bottom of screen
    2493     clear_to_eol(); // erase to end of line
     2615    place_cursor(rows - 1, 0);
     2616    clear_to_eol();
    24942617}
    24952618
     
    24972620static void clear_to_eos(void)
    24982621{
    2499     write1(Ceos);   // Erase from cursor to end of screen
     2622    write1(ESC_CLEAR2EOS);
    25002623}
    25012624
    25022625//----- Start standout mode ------------------------------------
    2503 static void standout_start(void) // send "start reverse video" sequence
    2504 {
    2505     write1(SOs);     // Start reverse video mode
     2626static void standout_start(void)
     2627{
     2628    write1(ESC_BOLD_TEXT);
    25062629}
    25072630
    25082631//----- End standout mode --------------------------------------
    2509 static void standout_end(void) // send "end reverse video" sequence
    2510 {
    2511     write1(SOn);     // End reverse video mode
     2632static void standout_end(void)
     2633{
     2634    write1(ESC_NORM_TEXT);
    25122635}
    25132636
     
    25152638static void flash(int h)
    25162639{
    2517     standout_start();   // send "start reverse video" sequence
     2640    standout_start();
    25182641    redraw(TRUE);
    25192642    mysleep(h);
    2520     standout_end();     // send "end reverse video" sequence
     2643    standout_end();
    25212644    redraw(TRUE);
    25222645}
     
    25292652#endif
    25302653    if (!err_method) {
    2531         write1(bell);   // send out a bell character
     2654        write1(ESC_BELL);
    25322655    } else {
    25332656        flash(10);
     
    25752698            have_status_msg = 0;
    25762699        }
    2577         place_cursor(crow, ccol, FALSE);    // put cursor back in correct place
     2700        place_cursor(crow, ccol);  // put cursor back in correct place
    25782701    }
    25792702    fflush_all();
     
    25872710
    25882711    va_start(args, format);
    2589     strcpy(status_buffer, SOs); // Terminal standout mode on
    2590     vsprintf(status_buffer + sizeof(SOs)-1, format, args);
    2591     strcat(status_buffer, SOn); // Terminal standout mode off
     2712    strcpy(status_buffer, ESC_BOLD_TEXT);
     2713    vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args);
     2714    strcat(status_buffer, ESC_NORM_TEXT);
    25922715    va_end(args);
    25932716
    2594     have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2;
     2717    have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2;
    25952718}
    25962719
     
    26242747        c_is_no_print = (c & 0x80) && !Isprint(c);
    26252748        if (c_is_no_print) {
    2626             strcpy(d, SOn);
    2627             d += sizeof(SOn)-1;
     2749            strcpy(d, ESC_NORM_TEXT);
     2750            d += sizeof(ESC_NORM_TEXT)-1;
    26282751            c = '.';
    26292752        }
     
    26372760        *d = '\0';
    26382761        if (c_is_no_print) {
    2639             strcpy(d, SOs);
    2640             d += sizeof(SOs)-1;
     2762            strcpy(d, ESC_BOLD_TEXT);
     2763            d += sizeof(ESC_BOLD_TEXT)-1;
    26412764        }
    26422765        if (*s == '\n') {
     
    27202843static void redraw(int full_screen)
    27212844{
    2722     place_cursor(0, 0, FALSE);  // put cursor in correct place
    2723     clear_to_eos();     // tell terminal to erase display
     2845    place_cursor(0, 0);
     2846    clear_to_eos();
    27242847    screen_erase();     // erase the internal screen buffer
    27252848    last_status_cksum = 0;  // force status update
     
    28612984            // copy changed part of buffer to virtual screen
    28622985            memcpy(sp+cs, out_buf+cs, ce-cs+1);
    2863 
    2864             // move cursor to column of first change
    2865             //if (offset != old_offset) {
    2866             //  // place_cursor is still too stupid
    2867             //  // to handle offsets correctly
    2868             //  place_cursor(li, cs, FALSE);
    2869             //} else {
    2870                 place_cursor(li, cs, TRUE);
    2871             //}
    2872 
     2986            place_cursor(li, cs);
    28732987            // write line out to terminal
    28742988            fwrite(&sp[cs], ce - cs + 1, 1, stdout);
     
    28762990    }
    28772991
    2878     place_cursor(crow, ccol, TRUE);
     2992    place_cursor(crow, ccol);
    28792993
    28802994    old_offset = offset;
     
    29063020static void do_cmd(int c)
    29073021{
    2908     const char *msg = msg; // for compiler
    29093022    char *p, *q, *save_dot;
    29103023    char buf[12];
     
    29153028//  c1 = c; // quiet the compiler
    29163029//  cnt = yf = 0; // quiet the compiler
    2917 //  msg = p = q = save_dot = buf; // quiet the compiler
    2918     memset(buf, '\0', 12);
     3030//  p = q = save_dot = buf; // quiet the compiler
     3031    memset(buf, '\0', sizeof(buf));
    29193032
    29203033    show_status_line();
     
    30323145    case 8:     // ctrl-H- move left    (This may be ERASE char)
    30333146    case 0x7f:  // DEL- move left   (This may be ERASE char)
    3034         if (--cmdcnt > 0) {
    3035             do_cmd(c);
    3036         }
    3037         dot_left();
     3147        do {
     3148            dot_left();
     3149        } while (--cmdcnt > 0);
    30383150        break;
    30393151    case 10:            // Newline ^J
    30403152    case 'j':           // j- goto next line, same col
    30413153    case KEYCODE_DOWN:  // cursor key Down
    3042         if (--cmdcnt > 0) {
    3043             do_cmd(c);
    3044         }
    3045         dot_next();     // go to next B-o-l
    3046         dot = move_to_col(dot, ccol + offset);  // try stay in same col
     3154        do {
     3155            dot_next();     // go to next B-o-l
     3156            // try stay in same col
     3157            dot = move_to_col(dot, ccol + offset);
     3158        } while (--cmdcnt > 0);
    30473159        break;
    30483160    case 12:            // ctrl-L  force redraw whole screen
    30493161    case 18:            // ctrl-R  force redraw
    3050         place_cursor(0, 0, FALSE);  // put cursor in correct place
    3051         clear_to_eos(); // tel terminal to erase display
    3052         mysleep(10);
     3162        place_cursor(0, 0);
     3163        clear_to_eos();
     3164        //mysleep(10); // why???
    30533165        screen_erase(); // erase the internal screen buffer
    30543166        last_status_cksum = 0;  // force status update
     
    30573169    case 13:            // Carriage Return ^M
    30583170    case '+':           // +- goto next line
    3059         if (--cmdcnt > 0) {
    3060             do_cmd(c);
    3061         }
    3062         dot_next();
    3063         dot_skip_over_ws();
     3171        do {
     3172            dot_next();
     3173            dot_skip_over_ws();
     3174        } while (--cmdcnt > 0);
    30643175        break;
    30653176    case 21:            // ctrl-U  scroll up   half screen
     
    30793190    case 'l':           // move right
    30803191    case KEYCODE_RIGHT: // Cursor Key Right
    3081         if (--cmdcnt > 0) {
    3082             do_cmd(c);
    3083         }
    3084         dot_right();
     3192        do {
     3193            dot_right();
     3194        } while (--cmdcnt > 0);
    30853195        break;
    30863196#if ENABLE_FEATURE_VI_YANKMARK
     
    31523262        break;
    31533263    case 'U':           // U- Undo; replace current line with original version
    3154         if (reg[Ureg] != 0) {
     3264        if (reg[Ureg] != NULL) {
    31553265            p = begin_line(dot);
    31563266            q = end_line(dot);
     
    31643274    case '$':           // $- goto end of line
    31653275    case KEYCODE_END:       // Cursor Key End
    3166         if (--cmdcnt > 0) {
     3276        for (;;) {
     3277            dot = end_line(dot);
     3278            if (--cmdcnt <= 0)
     3279                break;
    31673280            dot_next();
    3168             do_cmd(c);
    3169         }
    3170         dot = end_line(dot);
     3281        }
    31713282        break;
    31723283    case '%':           // %- find matching char of pair () [] {}
     
    31933304        //**** fall through to ... ';'
    31943305    case ';':           // ;- look at rest of line for last forward char
    3195         if (--cmdcnt > 0) {
    3196             do_cmd(';');
    3197         }
     3306        do {
     3307            if (last_forward_char == 0)
     3308                break;
     3309            q = dot + 1;
     3310            while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
     3311                q++;
     3312            }
     3313            if (*q == last_forward_char)
     3314                dot = q;
     3315        } while (--cmdcnt > 0);
     3316        break;
     3317    case ',':           // repeat latest 'f' in opposite direction
    31983318        if (last_forward_char == 0)
    31993319            break;
    3200         q = dot + 1;
    3201         while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
    3202             q++;
    3203         }
    3204         if (*q == last_forward_char)
    3205             dot = q;
    3206         break;
    3207     case ',':           // repeat latest 'f' in opposite direction
    3208         if (--cmdcnt > 0) {
    3209             do_cmd(',');
    3210         }
    3211         if (last_forward_char == 0)
    3212             break;
    3213         q = dot - 1;
    3214         while (q >= text && *q != '\n' && *q != last_forward_char) {
    3215             q--;
    3216         }
    3217         if (q >= text && *q == last_forward_char)
    3218             dot = q;
     3320        do {
     3321            q = dot - 1;
     3322            while (q >= text && *q != '\n' && *q != last_forward_char) {
     3323                q--;
     3324            }
     3325            if (q >= text && *q == last_forward_char)
     3326                dot = q;
     3327        } while (--cmdcnt > 0);
    32193328        break;
    32203329
    32213330    case '-':           // -- goto prev line
    3222         if (--cmdcnt > 0) {
    3223             do_cmd(c);
    3224         }
    3225         dot_prev();
    3226         dot_skip_over_ws();
     3331        do {
     3332            dot_prev();
     3333            dot_skip_over_ws();
     3334        } while (--cmdcnt > 0);
    32273335        break;
    32283336#if ENABLE_FEATURE_VI_DOT_CMD
     
    32563364        break;
    32573365    case 'N':           // N- backward search for last pattern
    3258         if (--cmdcnt > 0) {
    3259             do_cmd(c);
    3260         }
    32613366        dir = BACK;     // assume BACKWARD search
    32623367        p = dot - 1;
     
    32703375        // search rest of text[] starting at next char
    32713376        // if search fails return orignal "p" not the "p+1" address
    3272         if (--cmdcnt > 0) {
    3273             do_cmd(c);
    3274         }
     3377        do {
     3378            const char *msg;
    32753379 dc3:
    3276         dir = FORWARD;  // assume FORWARD search
    3277         p = dot + 1;
    3278         if (last_search_pattern[0] == '?') {
    3279             dir = BACK;
    3280             p = dot - 1;
    3281         }
     3380            dir = FORWARD;  // assume FORWARD search
     3381            p = dot + 1;
     3382            if (last_search_pattern[0] == '?') {
     3383                dir = BACK;
     3384                p = dot - 1;
     3385            }
    32823386 dc4:
    3283         q = char_search(p, last_search_pattern + 1, dir, FULL);
    3284         if (q != NULL) {
    3285             dot = q;    // good search, update "dot"
    3286             msg = "";
    3287             goto dc2;
    3288         }
    3289         // no pattern found between "dot" and "end"- continue at top
    3290         p = text;
    3291         if (dir == BACK) {
    3292             p = end - 1;
    3293         }
    3294         q = char_search(p, last_search_pattern + 1, dir, FULL);
    3295         if (q != NULL) {    // found something
    3296             dot = q;    // found new pattern- goto it
    3297             msg = "search hit BOTTOM, continuing at TOP";
     3387            q = char_search(p, last_search_pattern + 1, dir, FULL);
     3388            if (q != NULL) {
     3389                dot = q;    // good search, update "dot"
     3390                msg = NULL;
     3391                goto dc2;
     3392            }
     3393            // no pattern found between "dot" and "end"- continue at top
     3394            p = text;
    32983395            if (dir == BACK) {
    3299                 msg = "search hit TOP, continuing at BOTTOM";
    3300             }
    3301         } else {
    3302             msg = "Pattern not found";
    3303         }
     3396                p = end - 1;
     3397            }
     3398            q = char_search(p, last_search_pattern + 1, dir, FULL);
     3399            if (q != NULL) {    // found something
     3400                dot = q;    // found new pattern- goto it
     3401                msg = "search hit BOTTOM, continuing at TOP";
     3402                if (dir == BACK) {
     3403                    msg = "search hit TOP, continuing at BOTTOM";
     3404                }
     3405            } else {
     3406                msg = "Pattern not found";
     3407            }
    33043408 dc2:
    3305         if (*msg)
    3306             status_line_bold("%s", msg);
     3409            if (msg)
     3410                status_line_bold("%s", msg);
     3411        } while (--cmdcnt > 0);
    33073412        break;
    33083413    case '{':           // {- move backward paragraph
     
    33493454        ) {
    33503455            if (file_modified && p[1] != '!') {
    3351                 status_line_bold("No write since last change (:quit! overrides)");
     3456                status_line_bold("No write since last change (:%s! overrides)", p);
    33523457            } else {
    33533458                editing = 0;
     
    34233528    case 'E':           // E- end of a blank-delimited word
    34243529    case 'W':           // W- forward a blank-delimited word
    3425         if (--cmdcnt > 0) {
    3426             do_cmd(c);
    3427         }
    34283530        dir = FORWARD;
    34293531        if (c == 'B')
    34303532            dir = BACK;
    3431         if (c == 'W' || isspace(dot[dir])) {
    3432             dot = skip_thing(dot, 1, dir, S_TO_WS);
    3433             dot = skip_thing(dot, 2, dir, S_OVER_WS);
    3434         }
    3435         if (c != 'W')
    3436             dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
     3533        do {
     3534            if (c == 'W' || isspace(dot[dir])) {
     3535                dot = skip_thing(dot, 1, dir, S_TO_WS);
     3536                dot = skip_thing(dot, 2, dir, S_OVER_WS);
     3537            }
     3538            if (c != 'W')
     3539                dot = skip_thing(dot, 1, dir, S_BEFORE_WS);
     3540        } while (--cmdcnt > 0);
    34373541        break;
    34383542    case 'C':           // C- Change to e-o-l
     
    34853589    case KEYCODE_INSERT:    // Cursor Key Insert
    34863590 dc_i:
    3487         cmd_mode = 1;   // start insrting
     3591        cmd_mode = 1;   // start inserting
    34883592        break;
    34893593    case 'J':           // J- join current and next lines together
    3490         if (--cmdcnt > 1) {
    3491             do_cmd(c);
    3492         }
    3493         dot_end();      // move to NL
    3494         if (dot < end - 1) {    // make sure not last char in text[]
    3495             *dot++ = ' ';   // replace NL with space
    3496             file_modified++;
    3497             while (isblank(*dot)) { // delete leading WS
    3498                 dot_delete();
    3499             }
    3500         }
     3594        do {
     3595            dot_end();      // move to NL
     3596            if (dot < end - 1) {    // make sure not last char in text[]
     3597                *dot++ = ' ';   // replace NL with space
     3598                file_modified++;
     3599                while (isblank(*dot)) { // delete leading WS
     3600                    dot_delete();
     3601                }
     3602            }
     3603        } while (--cmdcnt > 0);
    35013604        end_cmd_q();    // stop adding to q
    35023605        break;
     
    35423645    case 'x':           // x- delete the current char
    35433646    case 's':           // s- substitute the current char
    3544         if (--cmdcnt > 0) {
    3545             do_cmd(c);
    3546         }
    35473647        dir = 0;
    35483648        if (c == 'X')
    35493649            dir = -1;
    3550         if (dot[dir] != '\n') {
    3551             if (c == 'X')
    3552                 dot--;  // delete prev char
    3553             dot = yank_delete(dot, dot, 0, YANKDEL);    // delete char
    3554         }
     3650        do {
     3651            if (dot[dir] != '\n') {
     3652                if (c == 'X')
     3653                    dot--;  // delete prev char
     3654                dot = yank_delete(dot, dot, 0, YANKDEL);    // delete char
     3655            }
     3656        } while (--cmdcnt > 0);
     3657        end_cmd_q();    // stop adding to q
    35553658        if (c == 's')
    3556             goto dc_i;  // start insrting
    3557         end_cmd_q();    // stop adding to q
     3659            goto dc_i;  // start inserting
    35583660        break;
    35593661    case 'Z':           // Z- if modified, {write}; exit
     
    35863688    case 'b':           // b- back a word
    35873689    case 'e':           // e- end of word
    3588         if (--cmdcnt > 0) {
    3589             do_cmd(c);
    3590         }
    35913690        dir = FORWARD;
    35923691        if (c == 'b')
    35933692            dir = BACK;
    3594         if ((dot + dir) < text || (dot + dir) > end - 1)
    3595             break;
    3596         dot += dir;
    3597         if (isspace(*dot)) {
    3598             dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
    3599         }
    3600         if (isalnum(*dot) || *dot == '_') {
    3601             dot = skip_thing(dot, 1, dir, S_END_ALNUM);
    3602         } else if (ispunct(*dot)) {
    3603             dot = skip_thing(dot, 1, dir, S_END_PUNCT);
    3604         }
     3693        do {
     3694            if ((dot + dir) < text || (dot + dir) > end - 1)
     3695                break;
     3696            dot += dir;
     3697            if (isspace(*dot)) {
     3698                dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS);
     3699            }
     3700            if (isalnum(*dot) || *dot == '_') {
     3701                dot = skip_thing(dot, 1, dir, S_END_ALNUM);
     3702            } else if (ispunct(*dot)) {
     3703                dot = skip_thing(dot, 1, dir, S_END_PUNCT);
     3704            }
     3705        } while (--cmdcnt > 0);
    36053706        break;
    36063707    case 'c':           // c- change something
     
    36873788    case 'k':           // k- goto prev line, same col
    36883789    case KEYCODE_UP:        // cursor key Up
    3689         if (--cmdcnt > 0) {
    3690             do_cmd(c);
    3691         }
    3692         dot_prev();
    3693         dot = move_to_col(dot, ccol + offset);  // try stay in same col
     3790        do {
     3791            dot_prev();
     3792            dot = move_to_col(dot, ccol + offset);  // try stay in same col
     3793        } while (--cmdcnt > 0);
    36943794        break;
    36953795    case 'r':           // r- replace the current char with user input
     
    37093809        break;
    37103810    case 'w':           // w- forward a word
    3711         if (--cmdcnt > 0) {
    3712             do_cmd(c);
    3713         }
    3714         if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
    3715             dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
    3716         } else if (ispunct(*dot)) { // we are on PUNCT
    3717             dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
    3718         }
    3719         if (dot < end - 1)
    3720             dot++;      // move over word
    3721         if (isspace(*dot)) {
    3722             dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
    3723         }
     3811        do {
     3812            if (isalnum(*dot) || *dot == '_') { // we are on ALNUM
     3813                dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM);
     3814            } else if (ispunct(*dot)) { // we are on PUNCT
     3815                dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT);
     3816            }
     3817            if (dot < end - 1)
     3818                dot++;      // move over word
     3819            if (isspace(*dot)) {
     3820                dot = skip_thing(dot, 2, FORWARD, S_OVER_WS);
     3821            }
     3822        } while (--cmdcnt > 0);
    37243823        break;
    37253824    case 'z':           // z-
     
    37373836        break;
    37383837    case '~':           // ~- flip the case of letters   a-z -> A-Z
    3739         if (--cmdcnt > 0) {
    3740             do_cmd(c);
    3741         }
    3742         if (islower(*dot)) {
    3743             *dot = toupper(*dot);
    3744             file_modified++;
    3745         } else if (isupper(*dot)) {
    3746             *dot = tolower(*dot);
    3747             file_modified++;
    3748         }
    3749         dot_right();
     3838        do {
     3839            if (islower(*dot)) {
     3840                *dot = toupper(*dot);
     3841                file_modified++;
     3842            } else if (isupper(*dot)) {
     3843                *dot = tolower(*dot);
     3844                file_modified++;
     3845            }
     3846            dot_right();
     3847        } while (--cmdcnt > 0);
    37503848        end_cmd_q();    // stop adding to q
    37513849        break;
     
    39834081    if (msg[0]) {
    39844082        printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
    3985             totalcmds, last_input_char, msg, SOs, SOn);
     4083            totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT);
    39864084        fflush_all();
    39874085        while (safe_read(STDIN_FILENO, d, 1) > 0) {
Note: See TracChangeset for help on using the changeset viewer.