Changeset 1765 in MondoRescue for branches/2.2.5/mindi-busybox/editors


Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

Location:
branches/2.2.5/mindi-busybox/editors
Files:
3 added
2 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/editors/Config.in

    r821 r1765  
    66menu "Editors"
    77
    8 config CONFIG_AWK
     8config AWK
    99    bool "awk"
    1010    default n
     
    1313      the BusyBox implementation of that programming language.
    1414
    15 config CONFIG_FEATURE_AWK_MATH
     15config FEATURE_AWK_MATH
    1616    bool "Enable math functions (requires libm)"
    1717    default y
    18     depends on CONFIG_AWK
     18    depends on AWK
    1919    help
    2020      Enable math functions of the Awk programming language.
    2121      NOTE: This will require libm to be present for linking.
    2222
    23 config CONFIG_ED
     23config CMP
     24    bool "cmp"
     25    default n
     26    help
     27      cmp is used to compare two files and returns the result
     28      to standard output.
     29
     30config DIFF
     31    bool "diff"
     32    default n
     33    help
     34      diff compares two files or directories and outputs the
     35      differences between them in a form that can be given to
     36      the patch command.
     37
     38config FEATURE_DIFF_BINARY
     39    bool "Enable checks for binary files"
     40    default y
     41    depends on DIFF
     42    help
     43      This option enables support for checking for binary files
     44      before a comparison is carried out.
     45
     46config FEATURE_DIFF_DIR
     47    bool "Enable directory support"
     48    default y
     49    depends on DIFF
     50    help
     51      This option enables support for directory and subdirectory
     52      comparison.
     53
     54config FEATURE_DIFF_MINIMAL
     55    bool "Enable -d option to find smaller sets of changes"
     56    default n
     57    depends on DIFF
     58    help
     59      Enabling this option allows the use of -d to make diff
     60      try hard to find the smallest possible set of changes.
     61
     62config ED
    2463    bool "ed"
    2564    default n
     
    2968      this, you don't need it.
    3069
    31 config CONFIG_PATCH
     70config PATCH
    3271    bool "patch"
    3372    default n
     
    3574      Apply a unified diff formatted patch.
    3675
    37 config CONFIG_SED
     76config SED
    3877    bool "sed"
    3978    default n
     
    4281      or input from a pipeline.
    4382
    44 config CONFIG_VI
     83config VI
    4584    bool "vi"
    4685    default n
     
    5190      you may wish to use something else.
    5291
    53 config CONFIG_FEATURE_VI_COLON
     92config FEATURE_VI_MAX_LEN
     93    int "Maximum line length in vi"
     94    range 256 16384
     95    default 1024
     96    depends on VI
     97    help
     98      vi uses on-stack buffers for intermediate line buffers.
     99      You may want to decrease this parameter if your target machine
     100      benefits from smaller stack usage.
     101
     102config FEATURE_VI_COLON
    54103    bool "Enable \":\" colon commands (no \"ex\" mode)"
    55104    default y
    56     depends on CONFIG_VI
     105    depends on VI
    57106    help
    58107      Enable a limited set of colon commands for vi.  This does not
    59108      provide an "ex" mode.
    60109
    61 config CONFIG_FEATURE_VI_YANKMARK
     110config FEATURE_VI_YANKMARK
    62111    bool "Enable yank/put commands and mark cmds"
    63112    default y
    64     depends on CONFIG_VI
     113    depends on VI
    65114    help
    66115      This will enable you to use yank and put, as well as mark in
    67116      busybox vi.
    68117
    69 config CONFIG_FEATURE_VI_SEARCH
     118config FEATURE_VI_SEARCH
    70119    bool "Enable search and replace cmds"
    71120    default y
    72     depends on CONFIG_VI
     121    depends on VI
    73122    help
    74123      Select this if you wish to be able to do search and replace in
    75124      busybox vi.
    76125
    77 config CONFIG_FEATURE_VI_USE_SIGNALS
     126config FEATURE_VI_USE_SIGNALS
    78127    bool "Catch signals"
    79128    default y
    80     depends on CONFIG_VI
     129    depends on VI
    81130    help
    82131      Selecting this option will make busybox vi signal aware.  This will
     
    84133      Ctrl-Z and Ctrl-C and alarms.
    85134
    86 config CONFIG_FEATURE_VI_DOT_CMD
     135config FEATURE_VI_DOT_CMD
    87136    bool "Remember previous cmd and \".\" cmd"
    88137    default y
    89     depends on CONFIG_VI
     138    depends on VI
    90139    help
    91140      Make busybox vi remember the last command and be able to repeat it.
    92141
    93 config CONFIG_FEATURE_VI_READONLY
     142config FEATURE_VI_READONLY
    94143    bool "Enable -R option and \"view\" mode"
    95144    default y
    96     depends on CONFIG_VI
     145    depends on VI
    97146    help
    98147      Enable the read-only command line option, which allows the user to
    99148      open a file in read-only mode.
    100149
    101 config CONFIG_FEATURE_VI_SETOPTS
     150config FEATURE_VI_SETOPTS
    102151    bool "Enable set-able options, ai ic showmatch"
    103152    default y
    104     depends on CONFIG_VI
     153    depends on VI
    105154    help
    106155      Enable the editor to set some (ai, ic, showmatch) options.
    107156
    108 config CONFIG_FEATURE_VI_SET
     157config FEATURE_VI_SET
    109158    bool "Support for :set"
    110159    default y
    111     depends on CONFIG_VI
     160    depends on VI
    112161    help
    113162      Support for ":set".
    114163
    115 config CONFIG_FEATURE_VI_WIN_RESIZE
     164config FEATURE_VI_WIN_RESIZE
    116165    bool "Handle window resize"
    117166    default y
    118     depends on CONFIG_VI
     167    depends on VI
    119168    help
    120169      Make busybox vi behave nicely with terminals that get resized.
    121170
    122 config CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     171config FEATURE_VI_OPTIMIZE_CURSOR
    123172    bool "Optimize cursor movement"
    124173    default y
    125     depends on CONFIG_VI
     174    depends on VI
    126175    help
    127176      This will make the cursor movement faster, but requires more memory
    128177      and it makes the applet a tiny bit larger.
    129178
     179config FEATURE_ALLOW_EXEC
     180    bool "Allow vi and awk to execute shell commands"
     181    default y
     182    depends on VI || AWK
     183    help
     184      Enables vi and awk features which allows user to execute
     185      shell commands (using system() C call).
     186
    130187endmenu
    131 
  • branches/2.2.5/mindi-busybox/editors/awk.c

    r821 r1765  
    88 */
    99
    10 #include <stdio.h>
    11 #include <stdlib.h>
    12 #include <unistd.h>
    13 #include <errno.h>
    14 #include <string.h>
    15 #include <strings.h>
    16 #include <time.h>
     10#include "libbb.h"
     11#include "xregex.h"
    1712#include <math.h>
    18 #include <ctype.h>
    19 #include <getopt.h>
    20 
    21 #include "xregex.h"
    22 #include "busybox.h"
    23 
    24 
    25 #define MAXVARFMT   240
    26 #define MINNVBLOCK  64
     13extern char **environ;
     14
     15/* This is a NOEXEC applet. Be very careful! */
     16
     17
     18#define MAXVARFMT       240
     19#define MINNVBLOCK      64
    2720
    2821/* variable flags */
    29 #define VF_NUMBER   0x0001  /* 1 = primary type is number */
    30 #define VF_ARRAY    0x0002  /* 1 = it's an array */
    31 
    32 #define VF_CACHED   0x0100  /* 1 = num/str value has cached str/num eq */
    33 #define VF_USER     0x0200  /* 1 = user input (may be numeric string) */
    34 #define VF_SPECIAL  0x0400  /* 1 = requires extra handling when changed */
    35 #define VF_WALK     0x0800  /* 1 = variable has alloc'd x.walker list */
    36 #define VF_FSTR     0x1000  /* 1 = string points to fstring buffer */
    37 #define VF_CHILD    0x2000  /* 1 = function arg; x.parent points to source */
    38 #define VF_DIRTY    0x4000  /* 1 = variable was set explicitly */
     22#define VF_NUMBER       0x0001  /* 1 = primary type is number */
     23#define VF_ARRAY        0x0002  /* 1 = it's an array */
     24
     25#define VF_CACHED       0x0100  /* 1 = num/str value has cached str/num eq */
     26#define VF_USER         0x0200  /* 1 = user input (may be numeric string) */
     27#define VF_SPECIAL      0x0400  /* 1 = requires extra handling when changed */
     28#define VF_WALK         0x0800  /* 1 = variable has alloc'd x.walker list */
     29#define VF_FSTR         0x1000  /* 1 = var::string points to fstring buffer */
     30#define VF_CHILD        0x2000  /* 1 = function arg; x.parent points to source */
     31#define VF_DIRTY        0x4000  /* 1 = variable was set explicitly */
    3932
    4033/* these flags are static, don't change them when value is changed */
    41 #define VF_DONTTOUCH (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
     34#define VF_DONTTOUCH    (VF_ARRAY | VF_SPECIAL | VF_WALK | VF_CHILD | VF_DIRTY)
    4235
    4336/* Variable */
    4437typedef struct var_s {
    45     unsigned short type;        /* flags */
     38    unsigned type;            /* flags */
    4639    double number;
    4740    char *string;
    4841    union {
    49         int aidx;               /* func arg idx (for compilation stage) */
    50         struct xhash_s *array;  /* array ptr */
    51         struct var_s *parent;   /* for func args, ptr to actual parameter */
    52         char **walker;          /* list of array elements (for..in) */
     42        int aidx;               /* func arg idx (for compilation stage) */
     43        struct xhash_s *array;  /* array ptr */
     44        struct var_s *parent;   /* for func args, ptr to actual parameter */
     45        char **walker;          /* list of array elements (for..in) */
    5346    } x;
    5447} var;
     
    5851    struct node_s *first;
    5952    struct node_s *last;
    60     char *programname;
     53    const char *programname;
    6154} chain;
    6255
    6356/* Function */
    6457typedef struct func_s {
    65     unsigned short nargs;
     58    unsigned nargs;
    6659    struct chain_s body;
    6760} func;
     
    7467    int size;
    7568    int pos;
    76     unsigned short is_pipe;
     69    smallint is_pipe;
    7770} rstream;
    7871
    7972typedef struct hash_item_s {
    8073    union {
    81         struct var_s v;         /* variable/array hash */
    82         struct rstream_s rs;    /* redirect streams hash */
    83         struct func_s f;        /* functions hash */
     74        struct var_s v;         /* variable/array hash */
     75        struct rstream_s rs;    /* redirect streams hash */
     76        struct func_s f;        /* functions hash */
    8477    } data;
    85     struct hash_item_s *next;   /* next in chain */
    86     char name[1];               /* really it's longer */
     78    struct hash_item_s *next;       /* next in chain */
     79    char name[1];                   /* really it's longer */
    8780} hash_item;
    8881
    8982typedef struct xhash_s {
    90     unsigned int nel;                   /* num of elements */
    91     unsigned int csize;                 /* current hash size */
    92     unsigned int nprime;                /* next hash size in PRIMES[] */
    93     unsigned int glen;                  /* summary length of item names */
     83    unsigned nel;           /* num of elements */
     84    unsigned csize;         /* current hash size */
     85    unsigned nprime;        /* next hash size in PRIMES[] */
     86    unsigned glen;          /* summary length of item names */
    9487    struct hash_item_s **items;
    9588} xhash;
     
    9891typedef struct node_s {
    9992    uint32_t info;
    100     unsigned short lineno;
     93    unsigned lineno;
    10194    union {
    10295        struct node_s *n;
     
    164157#define TC_NUMBER   (1 << 29)
    165158
    166 #define TC_UOPPRE   (TC_UOPPRE1 | TC_UOPPRE2)
     159#define TC_UOPPRE  (TC_UOPPRE1 | TC_UOPPRE2)
    167160
    168161/* combined token classes */
    169 #define TC_BINOP    (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
    170 #define TC_UNARYOP  (TC_UOPPRE | TC_UOPPOST)
    171 #define TC_OPERAND  (TC_VARIABLE | TC_ARRAY | TC_FUNCTION | \
    172     TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
    173 
    174 #define TC_STATEMNT (TC_STATX | TC_WHILE)
    175 #define TC_OPTERM   (TC_SEMICOL | TC_NEWLINE)
     162#define TC_BINOP   (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN)
     163#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST)
     164#define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \
     165                   | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER)
     166
     167#define TC_STATEMNT (TC_STATX | TC_WHILE)
     168#define TC_OPTERM  (TC_SEMICOL | TC_NEWLINE)
    176169
    177170/* word tokens, cannot mean something else if not expected */
    178 #define TC_WORD     (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN | \
    179     TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
     171#define TC_WORD    (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \
     172                   | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END)
    180173
    181174/* discard newlines after these */
    182 #define TC_NOTERM   (TC_COMMA | TC_GRPSTART | TC_GRPTERM | \
    183     TC_BINOP | TC_OPTERM)
     175#define TC_NOTERM  (TC_COMMA | TC_GRPSTART | TC_GRPTERM \
     176                   | TC_BINOP | TC_OPTERM)
    184177
    185178/* what can expression begin with */
    186 #define TC_OPSEQ    (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
     179#define TC_OPSEQ   (TC_OPERAND | TC_UOPPRE | TC_REGEXP)
    187180/* what can group begin with */
    188 #define TC_GRPSEQ   (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
     181#define TC_GRPSEQ  (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART)
    189182
    190183/* if previous token class is CONCAT1 and next is CONCAT2, concatenation */
    191184/* operator is inserted between them */
    192 #define TC_CONCAT1  (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM | \
    193     TC_STRING | TC_NUMBER | TC_UOPPOST)
    194 #define TC_CONCAT2  (TC_OPERAND | TC_UOPPRE)
    195 
    196 #define OF_RES1     0x010000
    197 #define OF_RES2     0x020000
    198 #define OF_STR1     0x040000
    199 #define OF_STR2     0x080000
    200 #define OF_NUM1     0x100000
    201 #define OF_CHECKED  0x200000
     185#define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \
     186                   | TC_STRING | TC_NUMBER | TC_UOPPOST)
     187#define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE)
     188
     189#define OF_RES1    0x010000
     190#define OF_RES2    0x020000
     191#define OF_STR1    0x040000
     192#define OF_STR2    0x080000
     193#define OF_NUM1    0x100000
     194#define OF_CHECKED 0x200000
    202195
    203196/* combined operator flags */
     
    213206#define SS  (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2)
    214207
    215 #define OPCLSMASK   0xFF00
    216 #define OPNMASK     0x007F
     208#define OPCLSMASK 0xFF00
     209#define OPNMASK   0x007F
    217210
    218211/* operator priority is a highest byte (even: r->l, odd: l->r grouping)
     
    220213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string
    221214 */
    222 #define P(x)    (x << 24)
    223 #define PRIMASK     0x7F000000
    224 #define PRIMASK2    0x7E000000
     215#define P(x)      (x << 24)
     216#define PRIMASK   0x7F000000
     217#define PRIMASK2  0x7E000000
    225218
    226219/* Operation classes */
     
    230223
    231224enum {
    232     OC_DELETE=0x0100,   OC_EXEC=0x0200,     OC_NEWSOURCE=0x0300,
    233     OC_PRINT=0x0400,    OC_PRINTF=0x0500,   OC_WALKINIT=0x0600,
    234 
    235     OC_BR=0x0700,       OC_BREAK=0x0800,    OC_CONTINUE=0x0900,
    236     OC_EXIT=0x0a00,     OC_NEXT=0x0b00,     OC_NEXTFILE=0x0c00,
    237     OC_TEST=0x0d00,     OC_WALKNEXT=0x0e00,
    238 
    239     OC_BINARY=0x1000,   OC_BUILTIN=0x1100,  OC_COLON=0x1200,
    240     OC_COMMA=0x1300,    OC_COMPARE=0x1400,  OC_CONCAT=0x1500,
    241     OC_FBLTIN=0x1600,   OC_FIELD=0x1700,    OC_FNARG=0x1800,
    242     OC_FUNC=0x1900,     OC_GETLINE=0x1a00,  OC_IN=0x1b00,
    243     OC_LAND=0x1c00,     OC_LOR=0x1d00,      OC_MATCH=0x1e00,
    244     OC_MOVE=0x1f00,     OC_PGETLINE=0x2000, OC_REGEXP=0x2100,
    245     OC_REPLACE=0x2200,  OC_RETURN=0x2300,   OC_SPRINTF=0x2400,
    246     OC_TERNARY=0x2500,  OC_UNARY=0x2600,    OC_VAR=0x2700,
    247     OC_DONE=0x2800,
    248 
    249     ST_IF=0x3000,       ST_DO=0x3100,       ST_FOR=0x3200,
    250     ST_WHILE=0x3300
     225    OC_DELETE = 0x0100,     OC_EXEC = 0x0200,       OC_NEWSOURCE = 0x0300,
     226    OC_PRINT = 0x0400,      OC_PRINTF = 0x0500,     OC_WALKINIT = 0x0600,
     227
     228    OC_BR = 0x0700,         OC_BREAK = 0x0800,      OC_CONTINUE = 0x0900,
     229    OC_EXIT = 0x0a00,       OC_NEXT = 0x0b00,       OC_NEXTFILE = 0x0c00,
     230    OC_TEST = 0x0d00,       OC_WALKNEXT = 0x0e00,
     231
     232    OC_BINARY = 0x1000,     OC_BUILTIN = 0x1100,    OC_COLON = 0x1200,
     233    OC_COMMA = 0x1300,      OC_COMPARE = 0x1400,    OC_CONCAT = 0x1500,
     234    OC_FBLTIN = 0x1600,     OC_FIELD = 0x1700,      OC_FNARG = 0x1800,
     235    OC_FUNC = 0x1900,       OC_GETLINE = 0x1a00,    OC_IN = 0x1b00,
     236    OC_LAND = 0x1c00,       OC_LOR = 0x1d00,        OC_MATCH = 0x1e00,
     237    OC_MOVE = 0x1f00,       OC_PGETLINE = 0x2000,   OC_REGEXP = 0x2100,
     238    OC_REPLACE = 0x2200,    OC_RETURN = 0x2300,     OC_SPRINTF = 0x2400,
     239    OC_TERNARY = 0x2500,    OC_UNARY = 0x2600,      OC_VAR = 0x2700,
     240    OC_DONE = 0x2800,
     241
     242    ST_IF = 0x3000,         ST_DO = 0x3100,         ST_FOR = 0x3200,
     243    ST_WHILE = 0x3300
    251244};
    252245
    253246/* simple builtins */
    254247enum {
    255     F_in=0, F_rn,   F_co,   F_ex,   F_lg,   F_si,   F_sq,   F_sr,
     248    F_in,   F_rn,   F_co,   F_ex,   F_lg,   F_si,   F_sq,   F_sr,
    256249    F_ti,   F_le,   F_sy,   F_ff,   F_cl
    257250};
     
    259252/* builtins */
    260253enum {
    261     B_a2=0, B_ix,   B_ma,   B_sp,   B_ss,   B_ti,   B_lo,   B_up,
    262     B_ge,   B_gs,   B_su
     254    B_a2,   B_ix,   B_ma,   B_sp,   B_ss,   B_ti,   B_lo,   B_up,
     255    B_ge,   B_gs,   B_su,
     256    B_an,   B_co,   B_ls,   B_or,   B_rs,   B_xo,
    263257};
    264258
    265259/* tokens and their corresponding info values */
    266260
    267 #define NTC     "\377"      /* switch to next token class (tc<<1) */
    268 #define NTCC    '\377'
     261#define NTC     "\377"  /* switch to next token class (tc<<1) */
     262#define NTCC    '\377'
    269263
    270264#define OC_B    OC_BUILTIN
    271265
    272 static char * const tokenlist =
    273     "\1("       NTC
    274     "\1)"       NTC
    275     "\1/"       NTC                                 /* REGEXP */
    276     "\2>>"      "\1>"       "\1|"       NTC         /* OUTRDR */
    277     "\2++"      "\2--"      NTC                     /* UOPPOST */
    278     "\2++"      "\2--"      "\1$"       NTC         /* UOPPRE1 */
    279     "\2=="      "\1="       "\2+="      "\2-="      /* BINOPX */
    280     "\2*="      "\2/="      "\2%="      "\2^="
    281     "\1+"       "\1-"       "\3**="     "\2**"
    282     "\1/"       "\1%"       "\1^"       "\1*"
    283     "\2!="      "\2>="      "\2<="      "\1>"
    284     "\1<"       "\2!~"      "\1~"       "\2&&"
    285     "\2||"      "\1?"       "\1:"       NTC
    286     "\2in"      NTC
    287     "\1,"       NTC
    288     "\1|"       NTC
    289     "\1+"       "\1-"       "\1!"       NTC         /* UOPPRE2 */
    290     "\1]"       NTC
    291     "\1{"       NTC
    292     "\1}"       NTC
    293     "\1;"       NTC
    294     "\1\n"      NTC
    295     "\2if"      "\2do"      "\3for"     "\5break"   /* STATX */
    296     "\10continue"           "\6delete"  "\5print"
    297     "\6printf"  "\4next"    "\10nextfile"
    298     "\6return"  "\4exit"    NTC
    299     "\5while"   NTC
    300     "\4else"    NTC
    301 
    302     "\5close"   "\6system"  "\6fflush"  "\5atan2"   /* BUILTIN */
    303     "\3cos"     "\3exp"     "\3int"     "\3log"
    304     "\4rand"    "\3sin"     "\4sqrt"    "\5srand"
    305     "\6gensub"  "\4gsub"    "\5index"   "\6length"
    306     "\5match"   "\5split"   "\7sprintf" "\3sub"
    307     "\6substr"  "\7systime" "\10strftime"
    308     "\7tolower" "\7toupper" NTC
    309     "\7getline" NTC
    310     "\4func"    "\10function"   NTC
    311     "\5BEGIN"   NTC
    312     "\3END"     "\0"
     266static const char tokenlist[] ALIGN1 =
     267    "\1("       NTC
     268    "\1)"       NTC
     269    "\1/"       NTC                                 /* REGEXP */
     270    "\2>>"      "\1>"       "\1|"       NTC         /* OUTRDR */
     271    "\2++"      "\2--"      NTC                     /* UOPPOST */
     272    "\2++"      "\2--"      "\1$"       NTC         /* UOPPRE1 */
     273    "\2=="      "\1="       "\2+="      "\2-="      /* BINOPX */
     274    "\2*="      "\2/="      "\2%="      "\2^="
     275    "\1+"       "\1-"       "\3**="     "\2**"
     276    "\1/"       "\1%"       "\1^"       "\1*"
     277    "\2!="      "\2>="      "\2<="      "\1>"
     278    "\1<"       "\2!~"      "\1~"       "\2&&"
     279    "\2||"      "\1?"       "\1:"       NTC
     280    "\2in"      NTC
     281    "\1,"       NTC
     282    "\1|"       NTC
     283    "\1+"       "\1-"       "\1!"       NTC         /* UOPPRE2 */
     284    "\1]"       NTC
     285    "\1{"       NTC
     286    "\1}"       NTC
     287    "\1;"       NTC
     288    "\1\n"      NTC
     289    "\2if"      "\2do"      "\3for"     "\5break"   /* STATX */
     290    "\10continue"           "\6delete"  "\5print"
     291    "\6printf"  "\4next"    "\10nextfile"
     292    "\6return"  "\4exit"    NTC
     293    "\5while"   NTC
     294    "\4else"    NTC
     295
     296    "\3and"     "\5compl"   "\6lshift"  "\2or"
     297    "\6rshift"  "\3xor"
     298    "\5close"   "\6system"  "\6fflush"  "\5atan2"   /* BUILTIN */
     299    "\3cos"     "\3exp"     "\3int"     "\3log"
     300    "\4rand"    "\3sin"     "\4sqrt"    "\5srand"
     301    "\6gensub"  "\4gsub"    "\5index"   "\6length"
     302    "\5match"   "\5split"   "\7sprintf" "\3sub"
     303    "\6substr"  "\7systime" "\10strftime"
     304    "\7tolower" "\7toupper" NTC
     305    "\7getline" NTC
     306    "\4func"    "\10function"   NTC
     307    "\5BEGIN"   NTC
     308    "\3END"     "\0"
    313309    ;
    314310
    315311static const uint32_t tokeninfo[] = {
    316 
    317312    0,
    318313    0,
    319314    OC_REGEXP,
    320     xS|'a',     xS|'w',     xS|'|',
    321     OC_UNARY|xV|P(9)|'p',       OC_UNARY|xV|P(9)|'m',
    322     OC_UNARY|xV|P(9)|'P',       OC_UNARY|xV|P(9)|'M',
    323         OC_FIELD|xV|P(5),
    324     OC_COMPARE|VV|P(39)|5,      OC_MOVE|VV|P(74),
    325         OC_REPLACE|NV|P(74)|'+',    OC_REPLACE|NV|P(74)|'-',
    326     OC_REPLACE|NV|P(74)|'*',    OC_REPLACE|NV|P(74)|'/',
    327         OC_REPLACE|NV|P(74)|'%',    OC_REPLACE|NV|P(74)|'&',
    328     OC_BINARY|NV|P(29)|'+',     OC_BINARY|NV|P(29)|'-',
    329         OC_REPLACE|NV|P(74)|'&',    OC_BINARY|NV|P(15)|'&',
    330     OC_BINARY|NV|P(25)|'/',     OC_BINARY|NV|P(25)|'%',
    331         OC_BINARY|NV|P(15)|'&',     OC_BINARY|NV|P(25)|'*',
    332     OC_COMPARE|VV|P(39)|4,      OC_COMPARE|VV|P(39)|3,
    333         OC_COMPARE|VV|P(39)|0,      OC_COMPARE|VV|P(39)|1,
    334     OC_COMPARE|VV|P(39)|2,      OC_MATCH|Sx|P(45)|'!',
    335         OC_MATCH|Sx|P(45)|'~',      OC_LAND|Vx|P(55),
    336     OC_LOR|Vx|P(59),            OC_TERNARY|Vx|P(64)|'?',
    337         OC_COLON|xx|P(67)|':',
     315    xS|'a',     xS|'w',     xS|'|',
     316    OC_UNARY|xV|P(9)|'p',       OC_UNARY|xV|P(9)|'m',
     317    OC_UNARY|xV|P(9)|'P',       OC_UNARY|xV|P(9)|'M',
     318        OC_FIELD|xV|P(5),
     319    OC_COMPARE|VV|P(39)|5,      OC_MOVE|VV|P(74),
     320        OC_REPLACE|NV|P(74)|'+',    OC_REPLACE|NV|P(74)|'-',
     321    OC_REPLACE|NV|P(74)|'*',    OC_REPLACE|NV|P(74)|'/',
     322        OC_REPLACE|NV|P(74)|'%',    OC_REPLACE|NV|P(74)|'&',
     323    OC_BINARY|NV|P(29)|'+',     OC_BINARY|NV|P(29)|'-',
     324        OC_REPLACE|NV|P(74)|'&',    OC_BINARY|NV|P(15)|'&',
     325    OC_BINARY|NV|P(25)|'/',     OC_BINARY|NV|P(25)|'%',
     326        OC_BINARY|NV|P(15)|'&',     OC_BINARY|NV|P(25)|'*',
     327    OC_COMPARE|VV|P(39)|4,      OC_COMPARE|VV|P(39)|3,
     328        OC_COMPARE|VV|P(39)|0,      OC_COMPARE|VV|P(39)|1,
     329    OC_COMPARE|VV|P(39)|2,      OC_MATCH|Sx|P(45)|'!',
     330        OC_MATCH|Sx|P(45)|'~',      OC_LAND|Vx|P(55),
     331    OC_LOR|Vx|P(59),            OC_TERNARY|Vx|P(64)|'?',
     332        OC_COLON|xx|P(67)|':',
    338333    OC_IN|SV|P(49),
    339334    OC_COMMA|SS|P(80),
    340335    OC_PGETLINE|SV|P(37),
    341     OC_UNARY|xV|P(19)|'+',      OC_UNARY|xV|P(19)|'-',
    342         OC_UNARY|xV|P(19)|'!',
     336    OC_UNARY|xV|P(19)|'+',      OC_UNARY|xV|P(19)|'-',
     337        OC_UNARY|xV|P(19)|'!',
    343338    0,
    344339    0,
     
    346341    0,
    347342    0,
    348     ST_IF,          ST_DO,          ST_FOR,         OC_BREAK,
    349     OC_CONTINUE,                    OC_DELETE|Vx,   OC_PRINT,
    350     OC_PRINTF,      OC_NEXT,        OC_NEXTFILE,
    351     OC_RETURN|Vx,   OC_EXIT|Nx,
     343    ST_IF,          ST_DO,          ST_FOR,         OC_BREAK,
     344    OC_CONTINUE,                    OC_DELETE|Vx,   OC_PRINT,
     345    OC_PRINTF,      OC_NEXT,        OC_NEXTFILE,
     346    OC_RETURN|Vx,   OC_EXIT|Nx,
    352347    ST_WHILE,
    353348    0,
    354349
     350    OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
     351    OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
    355352    OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83),
    356353    OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg,
     
    369366/* asterisk marks SPECIAL vars; $ is just no-named Field0 */
    370367enum {
    371     CONVFMT=0,  OFMT,       FS,         OFS,
    372     ORS,        RS,         RT,         FILENAME,
    373     SUBSEP,     ARGIND,     ARGC,       ARGV,
    374     ERRNO,      FNR,
    375     NR,         NF,         IGNORECASE,
    376     ENVIRON,    F0,         _intvarcount_
     368    CONVFMT,    OFMT,       FS,         OFS,
     369    ORS,        RS,         RT,         FILENAME,
     370    SUBSEP,     ARGIND,     ARGC,       ARGV,
     371    ERRNO,      FNR,
     372    NR,         NF,         IGNORECASE,
     373    ENVIRON,    F0,         NUM_INTERNAL_VARS
    377374};
    378375
    379 static char * vNames =
    380     "CONVFMT\0" "OFMT\0"    "FS\0*"     "OFS\0"
    381     "ORS\0"     "RS\0*"     "RT\0"      "FILENAME\0"
    382     "SUBSEP\0"  "ARGIND\0"  "ARGC\0"    "ARGV\0"
    383     "ERRNO\0"   "FNR\0"
    384     "NR\0"      "NF\0*"     "IGNORECASE\0*"
    385     "ENVIRON\0" "$\0*"      "\0";
    386 
    387 static char * vValues =
    388     "%.6g\0"    "%.6g\0"    " \0"       " \0"
    389     "\n\0"      "\n\0"      "\0"        "\0"
     376static const char vNames[] ALIGN1 =
     377    "CONVFMT\0" "OFMT\0"    "FS\0*"     "OFS\0"
     378    "ORS\0"     "RS\0*"     "RT\0"      "FILENAME\0"
     379    "SUBSEP\0"  "ARGIND\0"  "ARGC\0"    "ARGV\0"
     380    "ERRNO\0"   "FNR\0"
     381    "NR\0"      "NF\0*"     "IGNORECASE\0*"
     382    "ENVIRON\0" "$\0*"      "\0";
     383
     384static const char vValues[] ALIGN1 =
     385    "%.6g\0"    "%.6g\0"    " \0"       " \0"
     386    "\n\0"      "\n\0"      "\0"        "\0"
    390387    "\034\0"
    391388    "\377";
    392389
    393390/* hash size may grow to these values */
    394 #define FIRST_PRIME 61;
    395 static const unsigned int PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
    396 enum { NPRIMES = sizeof(PRIMES) / sizeof(unsigned int) };
    397 
    398 /* globals */
    399 
    400 extern char **environ;
    401 
    402 static var * V[_intvarcount_];
    403 static chain beginseq, mainseq, endseq, *seq;
    404 static int nextrec, nextfile;
    405 static node *break_ptr, *continue_ptr;
    406 static rstream *iF;
    407 static xhash *vhash, *ahash, *fdhash, *fnhash;
    408 static char *programname;
    409 static short lineno;
    410 static int is_f0_split;
    411 static int nfields;
    412 static var *Fields;
    413 static tsplitter fsplitter, rsplitter;
    414 static nvblock *cb;
    415 static char *pos;
    416 static char *buf;
    417 static int icase;
    418 static int exiting;
    419 
    420 static struct {
    421     uint32_t tclass;
    422     uint32_t info;
    423     char *string;
    424     double number;
    425     short lineno;
    426     int rollback;
    427 } t;
     391#define FIRST_PRIME 61
     392static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
     393
     394
     395/* Globals. Split in two parts so that first one is addressed
     396 * with (mostly short) negative offsets */
     397struct globals {
     398    chain beginseq, mainseq, endseq, *seq;
     399    node *break_ptr, *continue_ptr;
     400    rstream *iF;
     401    xhash *vhash, *ahash, *fdhash, *fnhash;
     402    const char *g_progname;
     403    int g_lineno;
     404    int nfields;
     405    int maxfields; /* used in fsrealloc() only */
     406    var *Fields;
     407    nvblock *g_cb;
     408    char *g_pos;
     409    char *g_buf;
     410    smallint icase;
     411    smallint exiting;
     412    smallint nextrec;
     413    smallint nextfile;
     414    smallint is_f0_split;
     415};
     416struct globals2 {
     417    uint32_t t_info; /* often used */
     418    uint32_t t_tclass;
     419    char *t_string;
     420    int t_lineno;
     421    int t_rollback;
     422
     423    var *intvar[NUM_INTERNAL_VARS]; /* often used */
     424
     425    /* former statics from various functions */
     426    char *split_f0__fstrings;
     427
     428    uint32_t next_token__save_tclass;
     429    uint32_t next_token__save_info;
     430    uint32_t next_token__ltclass;
     431    smallint next_token__concat_inserted;
     432
     433    smallint next_input_file__files_happen;
     434    rstream next_input_file__rsm;
     435
     436    var *evaluate__fnargs;
     437    unsigned evaluate__seed;
     438    regex_t evaluate__sreg;
     439
     440    var ptest__v;
     441
     442    tsplitter exec_builtin__tspl;
     443
     444    /* biggest and least used members go last */
     445    double t_double;
     446    tsplitter fsplitter, rsplitter;
     447};
     448#define G1 (ptr_to_globals[-1])
     449#define G (*(struct globals2 *const)ptr_to_globals)
     450/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
     451/* char G1size[sizeof(G1)]; - 0x6c */
     452/* char Gsize[sizeof(G)]; - 0x1cc */
     453/* Trying to keep most of members accessible with short offsets: */
     454/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
     455#define beginseq     (G1.beginseq    )
     456#define mainseq      (G1.mainseq     )
     457#define endseq       (G1.endseq      )
     458#define seq          (G1.seq         )
     459#define break_ptr    (G1.break_ptr   )
     460#define continue_ptr (G1.continue_ptr)
     461#define iF           (G1.iF          )
     462#define vhash        (G1.vhash       )
     463#define ahash        (G1.ahash       )
     464#define fdhash       (G1.fdhash      )
     465#define fnhash       (G1.fnhash      )
     466#define g_progname   (G1.g_progname  )
     467#define g_lineno     (G1.g_lineno    )
     468#define nfields      (G1.nfields     )
     469#define maxfields    (G1.maxfields   )
     470#define Fields       (G1.Fields      )
     471#define g_cb         (G1.g_cb        )
     472#define g_pos        (G1.g_pos       )
     473#define g_buf        (G1.g_buf       )
     474#define icase        (G1.icase       )
     475#define exiting      (G1.exiting     )
     476#define nextrec      (G1.nextrec     )
     477#define nextfile     (G1.nextfile    )
     478#define is_f0_split  (G1.is_f0_split )
     479#define t_info       (G.t_info      )
     480#define t_tclass     (G.t_tclass    )
     481#define t_string     (G.t_string    )
     482#define t_double     (G.t_double    )
     483#define t_lineno     (G.t_lineno    )
     484#define t_rollback   (G.t_rollback  )
     485#define intvar       (G.intvar      )
     486#define fsplitter    (G.fsplitter   )
     487#define rsplitter    (G.rsplitter   )
     488#define INIT_G() do { \
     489    PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
     490    G.next_token__ltclass = TC_OPTERM; \
     491    G.evaluate__seed = 1; \
     492} while (0)
     493
    428494
    429495/* function prototypes */
     
    438504/* ---- error handling ---- */
    439505
    440 static const char EMSG_INTERNAL_ERROR[] = "Internal error";
    441 static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
    442 static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
    443 static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
    444 static const char EMSG_INV_FMT[] = "Invalid format specifier";
    445 static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
    446 static const char EMSG_NOT_ARRAY[] = "Not an array";
    447 static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
    448 static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
    449 #ifndef CONFIG_FEATURE_AWK_MATH
    450 static const char EMSG_NO_MATH[] = "Math support is not compiled in";
     506static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
     507static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
     508static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
     509static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
     510static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
     511static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
     512static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
     513static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
     514static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
     515#if !ENABLE_FEATURE_AWK_MATH
     516static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
    451517#endif
    452518
    453 static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
    454 static void syntax_error(const char * const message)
    455 {
    456     bb_error_msg_and_die("%s:%i: %s", programname, lineno, message);
    457 }
    458 
    459 #define runtime_error(x) syntax_error(x)
    460 
     519static void zero_out_var(var * vp)
     520{
     521    memset(vp, 0, sizeof(*vp));
     522}
     523
     524static void syntax_error(const char *const message) ATTRIBUTE_NORETURN;
     525static void syntax_error(const char *const message)
     526{
     527    bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
     528}
    461529
    462530/* ---- hash stuff ---- */
    463531
    464 static unsigned int hashidx(const char *name)
    465 {
    466     register unsigned int idx=0;
    467 
    468     while (*name)  idx = *name++ + (idx << 6) - idx;
     532static unsigned hashidx(const char *name)
     533{
     534    unsigned idx = 0;
     535
     536    while (*name) idx = *name++ + (idx << 6) - idx;
    469537    return idx;
    470538}
     
    475543    xhash *newhash;
    476544
    477     newhash = (xhash *)xzalloc(sizeof(xhash));
     545    newhash = xzalloc(sizeof(xhash));
    478546    newhash->csize = FIRST_PRIME;
    479     newhash->items = (hash_item **)xzalloc(newhash->csize * sizeof(hash_item *));
     547    newhash->items = xzalloc(newhash->csize * sizeof(hash_item *));
    480548
    481549    return newhash;
     
    499567static void hash_rebuild(xhash *hash)
    500568{
    501     unsigned int newsize, i, idx;
     569    unsigned newsize, i, idx;
    502570    hash_item **newitems, *hi, *thi;
    503571
    504     if (hash->nprime == NPRIMES)
     572    if (hash->nprime == ARRAY_SIZE(PRIMES))
    505573        return;
    506574
    507575    newsize = PRIMES[hash->nprime++];
    508     newitems = (hash_item **)xzalloc(newsize * sizeof(hash_item *));
    509 
    510     for (i=0; i<hash->csize; i++) {
     576    newitems = xzalloc(newsize * sizeof(hash_item *));
     577
     578    for (i = 0; i < hash->csize; i++) {
    511579        hi = hash->items[i];
    512580        while (hi) {
     
    528596{
    529597    hash_item *hi;
    530     unsigned int idx;
     598    unsigned idx;
    531599    int l;
    532600
    533601    hi = hash_search(hash, name);
    534     if (! hi) {
     602    if (!hi) {
    535603        if (++hash->nel / hash->csize > 10)
    536604            hash_rebuild(hash);
     
    548616}
    549617
    550 #define findvar(hash, name) (var *) hash_find ( (hash) , (name) )
    551 #define newvar(name) (var *) hash_find ( vhash , (name) )
    552 #define newfile(name) (rstream *) hash_find ( fdhash , (name) )
    553 #define newfunc(name) (func *) hash_find ( fnhash , (name) )
     618#define findvar(hash, name) ((var*)    hash_find((hash), (name)))
     619#define newvar(name)        ((var*)    hash_find(vhash, (name)))
     620#define newfile(name)       ((rstream*)hash_find(fdhash, (name)))
     621#define newfunc(name)       ((func*)   hash_find(fnhash, (name)))
    554622
    555623static void hash_remove(xhash *hash, const char *name)
     
    557625    hash_item *hi, **phi;
    558626
    559     phi = &(hash->items[ hashidx(name) % hash->csize ]);
     627    phi = &(hash->items[hashidx(name) % hash->csize]);
    560628    while (*phi) {
    561629        hi = *phi;
     
    575643static void skip_spaces(char **s)
    576644{
    577     register char *p = *s;
    578 
    579     while(*p == ' ' || *p == '\t' ||
    580             (*p == '\\' && *(p+1) == '\n' && (++p, ++t.lineno))) {
     645    char *p = *s;
     646
     647    while (1) {
     648        if (*p == '\\' && p[1] == '\n') {
     649            p++;
     650            t_lineno++;
     651        } else if (*p != ' ' && *p != '\t') {
     652            break;
     653        }
    581654        p++;
    582655    }
     
    586659static char *nextword(char **s)
    587660{
    588     register char *p = *s;
    589 
    590     while (*(*s)++) ;
     661    char *p = *s;
     662
     663    while (*(*s)++) /* */;
    591664
    592665    return p;
     
    595668static char nextchar(char **s)
    596669{
    597     register char c, *pps;
     670    char c, *pps;
    598671
    599672    c = *((*s)++);
     
    604677}
    605678
    606 static inline int isalnum_(int c)
     679static int ALWAYS_INLINE isalnum_(int c)
    607680{
    608681    return (isalnum(c) || c == '_');
     
    611684static FILE *afopen(const char *path, const char *mode)
    612685{
    613     return (*path == '-' && *(path+1) == '\0') ? stdin : bb_xfopen(path, mode);
     686    return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode);
    614687}
    615688
     
    623696        a = a->x.parent;
    624697
    625     if (! (a->type & VF_ARRAY)) {
     698    if (!(a->type & VF_ARRAY)) {
    626699        a->type |= VF_ARRAY;
    627700        a->x.array = hash_init();
     
    632705static void clear_array(xhash *array)
    633706{
    634     unsigned int i;
     707    unsigned i;
    635708    hash_item *hi, *thi;
    636709
    637     for (i=0; i<array->csize; i++) {
     710    for (i = 0; i < array->csize; i++) {
    638711        hi = array->items[i];
    639712        while (hi) {
     
    666739    v->string = value;
    667740    handle_special(v);
    668 
    669741    return v;
    670742}
     
    673745static var *setvar_s(var *v, const char *value)
    674746{
    675     return setvar_p(v, (value && *value) ? bb_xstrdup(value) : NULL);
     747    return setvar_p(v, (value && *value) ? xstrdup(value) : NULL);
    676748}
    677749
     
    687759static void setari_u(var *a, int idx, const char *s)
    688760{
    689     register var *v;
    690     static char sidx[12];
     761    char sidx[sizeof(int)*3 + 1];
     762    var *v;
    691763
    692764    sprintf(sidx, "%d", idx);
     
    705777}
    706778
    707 static char *getvar_s(var *v)
     779static const char *getvar_s(var *v)
    708780{
    709781    /* if v is numeric and has no cached string, convert it to string */
    710782    if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) {
    711         fmt_num(buf, MAXVARFMT, getvar_s(V[CONVFMT]), v->number, TRUE);
    712         v->string = bb_xstrdup(buf);
     783        fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[CONVFMT]), v->number, TRUE);
     784        v->string = xstrdup(g_buf);
    713785        v->type |= VF_CACHED;
    714786    }
     
    742814    if (dest != src) {
    743815        clrvar(dest);
    744         dest->type |= (src->type & ~VF_DONTTOUCH);
     816        dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR));
    745817        dest->number = src->number;
    746818        if (src->string)
    747             dest->string = bb_xstrdup(src->string);
     819            dest->string = xstrdup(src->string);
    748820    }
    749821    handle_special(dest);
     
    753825static var *incvar(var *v)
    754826{
    755     return setvar_i(v, getvar_i(v)+1.);
     827    return setvar_i(v, getvar_i(v) + 1.);
    756828}
    757829
     
    768840    if (is_numeric(v))
    769841        return (v->number == 0) ? 0 : 1;
    770     else
    771         return (v->string && *(v->string)) ? 1 : 0;
     842    return (v->string && *(v->string)) ? 1 : 0;
    772843}
    773844
     
    779850    int size;
    780851
    781     while (cb) {
    782         pb = cb;
    783         if ((cb->pos - cb->nv) + n <= cb->size) break;
    784         cb = cb->next;
    785     }
    786 
    787     if (! cb) {
     852    while (g_cb) {
     853        pb = g_cb;
     854        if ((g_cb->pos - g_cb->nv) + n <= g_cb->size) break;
     855        g_cb = g_cb->next;
     856    }
     857
     858    if (!g_cb) {
    788859        size = (n <= MINNVBLOCK) ? MINNVBLOCK : n;
    789         cb = (nvblock *)xmalloc(sizeof(nvblock) + size * sizeof(var));
    790         cb->size = size;
    791         cb->pos = cb->nv;
    792         cb->prev = pb;
    793         cb->next = NULL;
    794         if (pb) pb->next = cb;
    795     }
    796 
    797     v = r = cb->pos;
    798     cb->pos += n;
    799 
    800     while (v < cb->pos) {
     860        g_cb = xmalloc(sizeof(nvblock) + size * sizeof(var));
     861        g_cb->size = size;
     862        g_cb->pos = g_cb->nv;
     863        g_cb->prev = pb;
     864        g_cb->next = NULL;
     865        if (pb) pb->next = g_cb;
     866    }
     867
     868    v = r = g_cb->pos;
     869    g_cb->pos += n;
     870
     871    while (v < g_cb->pos) {
    801872        v->type = 0;
    802873        v->string = NULL;
     
    811882    var *p;
    812883
    813     if (v < cb->nv || v >= cb->pos)
    814         runtime_error(EMSG_INTERNAL_ERROR);
    815 
    816     for (p=v; p<cb->pos; p++) {
    817         if ((p->type & (VF_ARRAY|VF_CHILD)) == VF_ARRAY) {
     884    if (v < g_cb->nv || v >= g_cb->pos)
     885        syntax_error(EMSG_INTERNAL_ERROR);
     886
     887    for (p = v; p < g_cb->pos; p++) {
     888        if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) {
    818889            clear_array(iamarray(p));
    819890            free(p->x.array->items);
     
    826897    }
    827898
    828     cb->pos = v;
    829     while (cb->prev && cb->pos == cb->nv) {
    830         cb = cb->prev;
     899    g_cb->pos = v;
     900    while (g_cb->prev && g_cb->pos == g_cb->nv) {
     901        g_cb = g_cb->prev;
    831902    }
    832903}
     
    834905/* ------- awk program text parsing ------- */
    835906
    836 /* Parse next token pointed by global pos, place results into global t.
     907/* Parse next token pointed by global pos, place results into global ttt.
    837908 * If token isn't expected, give away. Return token class
    838909 */
    839910static uint32_t next_token(uint32_t expected)
    840911{
     912#define concat_inserted (G.next_token__concat_inserted)
     913#define save_tclass     (G.next_token__save_tclass)
     914#define save_info       (G.next_token__save_info)
     915/* Initialized to TC_OPTERM: */
     916#define ltclass         (G.next_token__ltclass)
     917
    841918    char *p, *pp, *s;
    842     char *tl;
     919    const char *tl;
    843920    uint32_t tc;
    844921    const uint32_t *ti;
    845922    int l;
    846     static int concat_inserted;
    847     static uint32_t save_tclass, save_info;
    848     static uint32_t ltclass = TC_OPTERM;
    849 
    850     if (t.rollback) {
    851 
    852         t.rollback = FALSE;
     923
     924    if (t_rollback) {
     925        t_rollback = FALSE;
    853926
    854927    } else if (concat_inserted) {
    855 
    856928        concat_inserted = FALSE;
    857         t.tclass = save_tclass;
    858         t.info = save_info;
     929        t_tclass = save_tclass;
     930        t_info = save_info;
    859931
    860932    } else {
    861 
    862         p = pos;
    863 
    864     readnext:
     933        p = g_pos;
     934 readnext:
    865935        skip_spaces(&p);
    866         lineno = t.lineno;
     936        g_lineno = t_lineno;
    867937        if (*p == '#')
    868             while (*p != '\n' && *p != '\0') p++;
     938            while (*p != '\n' && *p != '\0')
     939                p++;
    869940
    870941        if (*p == '\n')
    871             t.lineno++;
     942            t_lineno++;
    872943
    873944        if (*p == '\0') {
     
    876947        } else if (*p == '\"') {
    877948            /* it's a string */
    878             t.string = s = ++p;
     949            t_string = s = ++p;
    879950            while (*p != '\"') {
    880951                if (*p == '\0' || *p == '\n')
     
    888959        } else if ((expected & TC_REGEXP) && *p == '/') {
    889960            /* it's regexp */
    890             t.string = s = ++p;
     961            t_string = s = ++p;
    891962            while (*p != '/') {
    892963                if (*p == '\0' || *p == '\n')
    893964                    syntax_error(EMSG_UNEXP_EOS);
    894                 if ((*s++ = *p++) == '\\') {
     965                *s = *p++;
     966                if (*s++ == '\\') {
    895967                    pp = p;
    896968                    *(s-1) = bb_process_escape_sequence((const char **)&p);
    897                     if (*pp == '\\') *s++ = '\\';
    898                     if (p == pp) *s++ = *p++;
     969                    if (*pp == '\\')
     970                        *s++ = '\\';
     971                    if (p == pp)
     972                        *s++ = *p++;
    899973                }
    900974            }
     
    905979        } else if (*p == '.' || isdigit(*p)) {
    906980            /* it's a number */
    907             t.number = strtod(p, &p);
     981            t_double = strtod(p, &p);
    908982            if (*p == '.')
    909983                syntax_error(EMSG_UNEXP_TOKEN);
     
    925999                 * then this is what we are looking for
    9261000                 */
    927                 if ((tc & (expected | TC_WORD | TC_NEWLINE)) &&
    928                 *tl == *p && strncmp(p, tl, l) == 0 &&
    929                 !((tc & TC_WORD) && isalnum_(*(p + l)))) {
    930                     t.info = *ti;
     1001                if ((tc & (expected | TC_WORD | TC_NEWLINE))
     1002                 && *tl == *p && strncmp(p, tl, l) == 0
     1003                 && !((tc & TC_WORD) && isalnum_(p[l]))
     1004                ) {
     1005                    t_info = *ti;
    9311006                    p += l;
    9321007                    break;
     
    9361011            }
    9371012
    938             if (! *tl) {
     1013            if (!*tl) {
    9391014                /* it's a name (var/array/function),
    9401015                 * otherwise it's something wrong
    9411016                 */
    942                 if (! isalnum_(*p))
     1017                if (!isalnum_(*p))
    9431018                    syntax_error(EMSG_UNEXP_TOKEN);
    9441019
    945                 t.string = --p;
    946                 while(isalnum_(*(++p))) {
     1020                t_string = --p;
     1021                while (isalnum_(*(++p))) {
    9471022                    *(p-1) = *p;
    9481023                }
     
    9501025                tc = TC_VARIABLE;
    9511026                /* also consume whitespace between functionname and bracket */
    952                 if (! (expected & TC_VARIABLE)) skip_spaces(&p);
     1027                if (!(expected & TC_VARIABLE))
     1028                    skip_spaces(&p);
    9531029                if (*p == '(') {
    9541030                    tc = TC_FUNCTION;
     
    9611037            }
    9621038        }
    963         pos = p;
     1039        g_pos = p;
    9641040
    9651041        /* skipping newlines in some cases */
     
    9681044
    9691045        /* insert concatenation operator when needed */
    970         if ((ltclass&TC_CONCAT1) && (tc&TC_CONCAT2) && (expected&TC_BINOP)) {
     1046        if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) {
    9711047            concat_inserted = TRUE;
    9721048            save_tclass = tc;
    973             save_info = t.info;
     1049            save_info = t_info;
    9741050            tc = TC_BINOP;
    975             t.info = OC_CONCAT | SS | P(35);
    976         }
    977 
    978         t.tclass = tc;
    979     }
    980     ltclass = t.tclass;
     1051            t_info = OC_CONCAT | SS | P(35);
     1052        }
     1053
     1054        t_tclass = tc;
     1055    }
     1056    ltclass = t_tclass;
    9811057
    9821058    /* Are we ready for this? */
    983     if (! (ltclass & expected))
     1059    if (!(ltclass & expected))
    9841060        syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ?
    985                                 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
     1061                EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN);
    9861062
    9871063    return ltclass;
    988 }
    989 
    990 static void rollback_token(void) { t.rollback = TRUE; }
     1064#undef concat_inserted
     1065#undef save_tclass
     1066#undef save_info
     1067#undef ltclass
     1068}
     1069
     1070static void rollback_token(void)
     1071{
     1072    t_rollback = TRUE;
     1073}
    9911074
    9921075static node *new_node(uint32_t info)
    9931076{
    994     register node *n;
    995 
    996     n = (node *)xzalloc(sizeof(node));
     1077    node *n;
     1078
     1079    n = xzalloc(sizeof(node));
    9971080    n->info = info;
    998     n->lineno = lineno;
     1081    n->lineno = g_lineno;
    9991082    return n;
    10001083}
    10011084
    1002 static node *mk_re_node(char *s, node *n, regex_t *re)
     1085static node *mk_re_node(const char *s, node *n, regex_t *re)
    10031086{
    10041087    n->info = OC_REGEXP;
     
    10061089    n->r.ire = re + 1;
    10071090    xregcomp(re, s, REG_EXTENDED);
    1008     xregcomp(re+1, s, REG_EXTENDED | REG_ICASE);
     1091    xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE);
    10091092
    10101093    return n;
     
    10311114    xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp;
    10321115
    1033     while (! ((tc = next_token(xtc)) & iexp)) {
    1034         if (glptr && (t.info == (OC_COMPARE|VV|P(39)|2))) {
     1116    while (!((tc = next_token(xtc)) & iexp)) {
     1117        if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) {
    10351118            /* input redirection (<) attached to glptr node */
    1036             cn = glptr->l.n = new_node(OC_CONCAT|SS|P(37));
     1119            cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37));
    10371120            cn->a.n = glptr;
    10381121            xtc = TC_OPERAND | TC_UOPPRE;
     
    10431126             * previous operators with higher priority */
    10441127            vn = cn;
    1045             while ( ((t.info & PRIMASK) > (vn->a.n->info & PRIMASK2)) ||
    1046               ((t.info == vn->info) && ((t.info & OPCLSMASK) == OC_COLON)) )
     1128            while ( ((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2))
     1129             || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) )
    10471130                vn = vn->a.n;
    1048             if ((t.info & OPCLSMASK) == OC_TERNARY)
    1049                 t.info += P(6);
    1050             cn = vn->a.n->r.n = new_node(t.info);
     1131            if ((t_info & OPCLSMASK) == OC_TERNARY)
     1132                t_info += P(6);
     1133            cn = vn->a.n->r.n = new_node(t_info);
    10511134            cn->a.n = vn->a.n;
    10521135            if (tc & TC_BINOP) {
    10531136                cn->l.n = vn;
    10541137                xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
    1055                 if ((t.info & OPCLSMASK) == OC_PGETLINE) {
     1138                if ((t_info & OPCLSMASK) == OC_PGETLINE) {
    10561139                    /* it's a pipe */
    10571140                    next_token(TC_GETLINE);
     
    10701153             * to last node */
    10711154            vn = cn;
    1072             cn = vn->r.n = new_node(t.info);
     1155            cn = vn->r.n = new_node(t_info);
    10731156            cn->a.n = vn;
    10741157            xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP;
     
    10781161                 * only simple tclasses should be used! */
    10791162                switch (tc) {
    1080                   case TC_VARIABLE:
    1081                   case TC_ARRAY:
     1163                case TC_VARIABLE:
     1164                case TC_ARRAY:
    10821165                    cn->info = OC_VAR;
    1083                     if ((v = hash_search(ahash, t.string)) != NULL) {
     1166                    v = hash_search(ahash, t_string);
     1167                    if (v != NULL) {
    10841168                        cn->info = OC_FNARG;
    10851169                        cn->l.i = v->x.aidx;
    10861170                    } else {
    1087                         cn->l.v = newvar(t.string);
     1171                        cn->l.v = newvar(t_string);
    10881172                    }
    10891173                    if (tc & TC_ARRAY) {
     
    10931177                    break;
    10941178
    1095                   case TC_NUMBER:
    1096                   case TC_STRING:
     1179                case TC_NUMBER:
     1180                case TC_STRING:
    10971181                    cn->info = OC_VAR;
    10981182                    v = cn->l.v = xzalloc(sizeof(var));
    10991183                    if (tc & TC_NUMBER)
    1100                         setvar_i(v, t.number);
     1184                        setvar_i(v, t_double);
    11011185                    else
    1102                         setvar_s(v, t.string);
     1186                        setvar_s(v, t_string);
    11031187                    break;
    11041188
    1105                   case TC_REGEXP:
    1106                     mk_re_node(t.string, cn,
    1107                                     (regex_t *)xzalloc(sizeof(regex_t)*2));
     1189                case TC_REGEXP:
     1190                    mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2));
    11081191                    break;
    11091192
    1110                   case TC_FUNCTION:
     1193                case TC_FUNCTION:
    11111194                    cn->info = OC_FUNC;
    1112                     cn->r.f = newfunc(t.string);
     1195                    cn->r.f = newfunc(t_string);
    11131196                    cn->l.n = condition();
    11141197                    break;
    11151198
    1116                   case TC_SEQSTART:
     1199                case TC_SEQSTART:
    11171200                    cn = vn->r.n = parse_expr(TC_SEQTERM);
    11181201                    cn->a.n = vn;
    11191202                    break;
    11201203
    1121                   case TC_GETLINE:
     1204                case TC_GETLINE:
    11221205                    glptr = cn;
    11231206                    xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp;
    11241207                    break;
    11251208
    1126                   case TC_BUILTIN:
     1209                case TC_BUILTIN:
    11271210                    cn->l.n = condition();
    11281211                    break;
     
    11371220static node *chain_node(uint32_t info)
    11381221{
    1139     register node *n;
    1140 
    1141     if (! seq->first)
     1222    node *n;
     1223
     1224    if (!seq->first)
    11421225        seq->first = seq->last = new_node(0);
    11431226
    1144     if (seq->programname != programname) {
    1145         seq->programname = programname;
     1227    if (seq->programname != g_progname) {
     1228        seq->programname = g_progname;
    11461229        n = chain_node(OC_NEWSOURCE);
    1147         n->l.s = bb_xstrdup(programname);
     1230        n->l.s = xstrdup(g_progname);
    11481231    }
    11491232
     
    11611244    n = chain_node(info);
    11621245    n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM);
    1163     if (t.tclass & TC_GRPTERM)
     1246    if (t_tclass & TC_GRPTERM)
    11641247        rollback_token();
    11651248}
     
    11991282
    12001283    if (c & TC_GRPSTART) {
    1201         while(next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
    1202             if (t.tclass & TC_NEWLINE) continue;
     1284        while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) {
     1285            if (t_tclass & TC_NEWLINE) continue;
    12031286            rollback_token();
    12041287            chain_group();
     
    12081291        chain_expr(OC_EXEC | Vx);
    12091292    } else {                        /* TC_STATEMNT */
    1210         switch (t.info & OPCLSMASK) {
    1211             case ST_IF:
    1212                 n = chain_node(OC_BR | Vx);
    1213                 n->l.n = condition();
     1293        switch (t_info & OPCLSMASK) {
     1294        case ST_IF:
     1295            n = chain_node(OC_BR | Vx);
     1296            n->l.n = condition();
     1297            chain_group();
     1298            n2 = chain_node(OC_EXEC);
     1299            n->r.n = seq->last;
     1300            if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE) == TC_ELSE) {
    12141301                chain_group();
    1215                 n2 = chain_node(OC_EXEC);
    1216                 n->r.n = seq->last;
    1217                 if (next_token(TC_GRPSEQ | TC_GRPTERM | TC_ELSE)==TC_ELSE) {
    1218                     chain_group();
    1219                     n2->a.n = seq->last;
    1220                 } else {
    1221                     rollback_token();
    1222                 }
    1223                 break;
    1224 
    1225             case ST_WHILE:
    1226                 n2 = condition();
     1302                n2->a.n = seq->last;
     1303            } else {
     1304                rollback_token();
     1305            }
     1306            break;
     1307
     1308        case ST_WHILE:
     1309            n2 = condition();
     1310            n = chain_loop(NULL);
     1311            n->l.n = n2;
     1312            break;
     1313
     1314        case ST_DO:
     1315            n2 = chain_node(OC_EXEC);
     1316            n = chain_loop(NULL);
     1317            n2->a.n = n->a.n;
     1318            next_token(TC_WHILE);
     1319            n->l.n = condition();
     1320            break;
     1321
     1322        case ST_FOR:
     1323            next_token(TC_SEQSTART);
     1324            n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
     1325            if (t_tclass & TC_SEQTERM) {    /* for-in */
     1326                if ((n2->info & OPCLSMASK) != OC_IN)
     1327                    syntax_error(EMSG_UNEXP_TOKEN);
     1328                n = chain_node(OC_WALKINIT | VV);
     1329                n->l.n = n2->l.n;
     1330                n->r.n = n2->r.n;
    12271331                n = chain_loop(NULL);
     1332                n->info = OC_WALKNEXT | Vx;
     1333                n->l.n = n2->l.n;
     1334            } else {            /* for (;;) */
     1335                n = chain_node(OC_EXEC | Vx);
    12281336                n->l.n = n2;
    1229                 break;
    1230 
    1231             case ST_DO:
    1232                 n2 = chain_node(OC_EXEC);
    1233                 n = chain_loop(NULL);
    1234                 n2->a.n = n->a.n;
    1235                 next_token(TC_WHILE);
    1236                 n->l.n = condition();
    1237                 break;
    1238 
    1239             case ST_FOR:
    1240                 next_token(TC_SEQSTART);
    1241                 n2 = parse_expr(TC_SEMICOL | TC_SEQTERM);
    1242                 if (t.tclass & TC_SEQTERM) {                /* for-in */
    1243                     if ((n2->info & OPCLSMASK) != OC_IN)
    1244                         syntax_error(EMSG_UNEXP_TOKEN);
    1245                     n = chain_node(OC_WALKINIT | VV);
    1246                     n->l.n = n2->l.n;
    1247                     n->r.n = n2->r.n;
    1248                     n = chain_loop(NULL);
    1249                     n->info = OC_WALKNEXT | Vx;
    1250                     n->l.n = n2->l.n;
    1251                 } else {                                    /* for(;;) */
    1252                     n = chain_node(OC_EXEC | Vx);
    1253                     n->l.n = n2;
    1254                     n2 = parse_expr(TC_SEMICOL);
    1255                     n3 = parse_expr(TC_SEQTERM);
    1256                     n = chain_loop(n3);
    1257                     n->l.n = n2;
    1258                     if (! n2)
    1259                         n->info = OC_EXEC;
    1260                 }
    1261                 break;
    1262 
    1263             case OC_PRINT:
    1264             case OC_PRINTF:
    1265                 n = chain_node(t.info);
    1266                 n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
    1267                 if (t.tclass & TC_OUTRDR) {
    1268                     n->info |= t.info;
    1269                     n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
    1270                 }
    1271                 if (t.tclass & TC_GRPTERM)
    1272                     rollback_token();
    1273                 break;
    1274 
    1275             case OC_BREAK:
    1276                 n = chain_node(OC_EXEC);
    1277                 n->a.n = break_ptr;
    1278                 break;
    1279 
    1280             case OC_CONTINUE:
    1281                 n = chain_node(OC_EXEC);
    1282                 n->a.n = continue_ptr;
    1283                 break;
    1284 
    1285             /* delete, next, nextfile, return, exit */
    1286             default:
    1287                 chain_expr(t.info);
    1288 
     1337                n2 = parse_expr(TC_SEMICOL);
     1338                n3 = parse_expr(TC_SEQTERM);
     1339                n = chain_loop(n3);
     1340                n->l.n = n2;
     1341                if (!n2)
     1342                    n->info = OC_EXEC;
     1343            }
     1344            break;
     1345
     1346        case OC_PRINT:
     1347        case OC_PRINTF:
     1348            n = chain_node(t_info);
     1349            n->l.n = parse_expr(TC_OPTERM | TC_OUTRDR | TC_GRPTERM);
     1350            if (t_tclass & TC_OUTRDR) {
     1351                n->info |= t_info;
     1352                n->r.n = parse_expr(TC_OPTERM | TC_GRPTERM);
     1353            }
     1354            if (t_tclass & TC_GRPTERM)
     1355                rollback_token();
     1356            break;
     1357
     1358        case OC_BREAK:
     1359            n = chain_node(OC_EXEC);
     1360            n->a.n = break_ptr;
     1361            break;
     1362
     1363        case OC_CONTINUE:
     1364            n = chain_node(OC_EXEC);
     1365            n->a.n = continue_ptr;
     1366            break;
     1367
     1368        /* delete, next, nextfile, return, exit */
     1369        default:
     1370            chain_expr(t_info);
    12891371        }
    12901372    }
     
    12981380    var *v;
    12991381
    1300     pos = p;
    1301     t.lineno = 1;
    1302     while((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
    1303                 TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
     1382    g_pos = p;
     1383    t_lineno = 1;
     1384    while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |
     1385            TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) {
    13041386
    13051387        if (tclass & TC_OPTERM)
     
    13171399        } else if (tclass & TC_FUNCDECL) {
    13181400            next_token(TC_FUNCTION);
    1319             pos++;
    1320             f = newfunc(t.string);
     1401            g_pos++;
     1402            f = newfunc(t_string);
    13211403            f->body.first = NULL;
    13221404            f->nargs = 0;
    1323             while(next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
    1324                 v = findvar(ahash, t.string);
     1405            while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) {
     1406                v = findvar(ahash, t_string);
    13251407                v->x.aidx = (f->nargs)++;
    13261408
     
    13361418            cn = chain_node(OC_TEST);
    13371419            cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART);
    1338             if (t.tclass & TC_GRPSTART) {
     1420            if (t_tclass & TC_GRPSTART) {
    13391421                rollback_token();
    13401422                chain_group();
     
    13541436/* -------- program execution part -------- */
    13551437
    1356 static node *mk_splitter(char *s, tsplitter *spl)
    1357 {
    1358     register regex_t *re, *ire;
     1438static node *mk_splitter(const char *s, tsplitter *spl)
     1439{
     1440    regex_t *re, *ire;
    13591441    node *n;
    13601442
     
    13621444    ire = &spl->re[1];
    13631445    n = &spl->n;
    1364     if ((n->info && OPCLSMASK) == OC_REGEXP) {
     1446    if ((n->info & OPCLSMASK) == OC_REGEXP) {
    13651447        regfree(re);
    1366         regfree(ire);
     1448        regfree(ire); // TODO: nuke ire, use re+1?
    13671449    }
    13681450    if (strlen(s) > 1) {
     
    13821464{
    13831465    var *v;
    1384     char *s;
     1466    const char *s;
    13851467
    13861468    if ((op->info & OPCLSMASK) == OC_REGEXP) {
    13871469        return icase ? op->r.ire : op->l.re;
    1388     } else {
    1389         v = nvalloc(1);
    1390         s = getvar_s(evaluate(op, v));
    1391         xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
    1392         nvfree(v);
    1393         return preg;
    1394     }
     1470    }
     1471    v = nvalloc(1);
     1472    s = getvar_s(evaluate(op, v));
     1473    xregcomp(preg, s, icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED);
     1474    nvfree(v);
     1475    return preg;
    13951476}
    13961477
     
    13981479static void qrealloc(char **b, int n, int *size)
    13991480{
    1400     if (! *b || n >= *size)
     1481    if (!*b || n >= *size)
    14011482        *b = xrealloc(*b, *size = n + (n>>1) + 80);
    14021483}
     
    14051486static void fsrealloc(int size)
    14061487{
    1407     static int maxfields = 0;
    14081488    int i;
    14091489
     
    14111491        i = maxfields;
    14121492        maxfields = size + 16;
    1413         Fields = (var *)xrealloc(Fields, maxfields * sizeof(var));
    1414         for (; i<maxfields; i++) {
     1493        Fields = xrealloc(Fields, maxfields * sizeof(var));
     1494        for (; i < maxfields; i++) {
    14151495            Fields[i].type = VF_SPECIAL;
    14161496            Fields[i].string = NULL;
     
    14191499
    14201500    if (size < nfields) {
    1421         for (i=size; i<nfields; i++) {
    1422             clrvar(Fields+i);
     1501        for (i = size; i < nfields; i++) {
     1502            clrvar(Fields + i);
    14231503        }
    14241504    }
     
    14261506}
    14271507
    1428 static int awk_split(char *s, node *spl, char **slist)
    1429 {
    1430     int l, n=0;
     1508static int awk_split(const char *s, node *spl, char **slist)
     1509{
     1510    int l, n = 0;
    14311511    char c[4];
    14321512    char *s1;
    1433     regmatch_t pmatch[2];
     1513    regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
    14341514
    14351515    /* in worst case, each char would be a separate field */
    1436     *slist = s1 = bb_xstrndup(s, strlen(s) * 2 + 3);
     1516    *slist = s1 = xzalloc(strlen(s) * 2 + 3);
     1517    strcpy(s1, s);
    14371518
    14381519    c[0] = c[1] = (char)spl->info;
    14391520    c[2] = c[3] = '\0';
    1440     if (*getvar_s(V[RS]) == '\0') c[2] = '\n';
    1441 
    1442     if ((spl->info & OPCLSMASK) == OC_REGEXP) {     /* regex split */
    1443         while (*s) {
    1444             l = strcspn(s, c+2);
    1445             if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0 &&
    1446             pmatch[0].rm_so <= l) {
     1521    if (*getvar_s(intvar[RS]) == '\0')
     1522        c[2] = '\n';
     1523
     1524    if ((spl->info & OPCLSMASK) == OC_REGEXP) {  /* regex split */
     1525        if (!*s)
     1526            return n; /* "": zero fields */
     1527        n++; /* at least one field will be there */
     1528        do {
     1529            l = strcspn(s, c+2); /* len till next NUL or \n */
     1530            if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
     1531             && pmatch[0].rm_so <= l
     1532            ) {
    14471533                l = pmatch[0].rm_so;
    1448                 if (pmatch[0].rm_eo == 0) { l++; pmatch[0].rm_eo++; }
     1534                if (pmatch[0].rm_eo == 0) {
     1535                    l++;
     1536                    pmatch[0].rm_eo++;
     1537                }
     1538                n++; /* we saw yet another delimiter */
    14491539            } else {
    14501540                pmatch[0].rm_eo = l;
    1451                 if (*(s+l)) pmatch[0].rm_eo++;
    1452             }
    1453 
     1541                if (s[l]) pmatch[0].rm_eo++;
     1542            }
    14541543            memcpy(s1, s, l);
    1455             *(s1+l) = '\0';
     1544            s1[l] = '\0';
    14561545            nextword(&s1);
    14571546            s += pmatch[0].rm_eo;
     1547        } while (*s);
     1548        return n;
     1549    }
     1550    if (c[0] == '\0') {  /* null split */
     1551        while (*s) {
     1552            *s1++ = *s++;
     1553            *s1++ = '\0';
    14581554            n++;
    14591555        }
    1460     } else if (c[0] == '\0') {      /* null split */
    1461         while(*s) {
    1462             *(s1++) = *(s++);
    1463             *(s1++) = '\0';
    1464             n++;
    1465         }
    1466     } else if (c[0] != ' ') {       /* single-character split */
     1556        return n;
     1557    }
     1558    if (c[0] != ' ') {  /* single-character split */
    14671559        if (icase) {
    14681560            c[0] = toupper(c[0]);
     
    14711563        if (*s1) n++;
    14721564        while ((s1 = strpbrk(s1, c))) {
    1473             *(s1++) = '\0';
     1565            *s1++ = '\0';
    14741566            n++;
    14751567        }
    1476     } else {                /* space split */
    1477         while (*s) {
    1478             while (isspace(*s)) s++;
    1479             if (! *s) break;
    1480             n++;
    1481             while (*s && !isspace(*s))
    1482                 *(s1++) = *(s++);
    1483             *(s1++) = '\0';
    1484         }
     1568        return n;
     1569    }
     1570    /* space split */
     1571    while (*s) {
     1572        s = skip_whitespace(s);
     1573        if (!*s) break;
     1574        n++;
     1575        while (*s && !isspace(*s))
     1576            *s1++ = *s++;
     1577        *s1++ = '\0';
    14851578    }
    14861579    return n;
     
    14891582static void split_f0(void)
    14901583{
    1491     static char *fstrings = NULL;
     1584/* static char *fstrings; */
     1585#define fstrings (G.split_f0__fstrings)
     1586
    14921587    int i, n;
    14931588    char *s;
     
    14991594    free(fstrings);
    15001595    fsrealloc(0);
    1501     n = awk_split(getvar_s(V[F0]), &fsplitter.n, &fstrings);
     1596    n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings);
    15021597    fsrealloc(n);
    15031598    s = fstrings;
    1504     for (i=0; i<n; i++) {
     1599    for (i = 0; i < n; i++) {
    15051600        Fields[i].string = nextword(&s);
    15061601        Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY);
     
    15081603
    15091604    /* set NF manually to avoid side effects */
    1510     clrvar(V[NF]);
    1511     V[NF]->type = VF_NUMBER | VF_SPECIAL;
    1512     V[NF]->number = nfields;
     1605    clrvar(intvar[NF]);
     1606    intvar[NF]->type = VF_NUMBER | VF_SPECIAL;
     1607    intvar[NF]->number = nfields;
     1608#undef fstrings
    15131609}
    15141610
     
    15171613{
    15181614    int n;
    1519     char *b, *sep, *s;
     1615    char *b;
     1616    const char *sep, *s;
    15201617    int sl, l, len, i, bsize;
    15211618
    1522     if (! (v->type & VF_SPECIAL))
     1619    if (!(v->type & VF_SPECIAL))
    15231620        return;
    15241621
    1525     if (v == V[NF]) {
     1622    if (v == intvar[NF]) {
    15261623        n = (int)getvar_i(v);
    15271624        fsrealloc(n);
    15281625
    15291626        /* recalculate $0 */
    1530         sep = getvar_s(V[OFS]);
     1627        sep = getvar_s(intvar[OFS]);
    15311628        sl = strlen(sep);
    15321629        b = NULL;
    15331630        len = 0;
    1534         for (i=0; i<n; i++) {
     1631        for (i = 0; i < n; i++) {
    15351632            s = getvar_s(&Fields[i]);
    15361633            l = strlen(s);
     
    15431640            len += l;
    15441641        }
    1545         if (b) b[len] = '\0';
    1546         setvar_p(V[F0], b);
     1642        if (b)
     1643            b[len] = '\0';
     1644        setvar_p(intvar[F0], b);
    15471645        is_f0_split = TRUE;
    15481646
    1549     } else if (v == V[F0]) {
     1647    } else if (v == intvar[F0]) {
    15501648        is_f0_split = FALSE;
    15511649
    1552     } else if (v == V[FS]) {
     1650    } else if (v == intvar[FS]) {
    15531651        mk_splitter(getvar_s(v), &fsplitter);
    15541652
    1555     } else if (v == V[RS]) {
     1653    } else if (v == intvar[RS]) {
    15561654        mk_splitter(getvar_s(v), &rsplitter);
    15571655
    1558     } else if (v == V[IGNORECASE]) {
     1656    } else if (v == intvar[IGNORECASE]) {
    15591657        icase = istrue(v);
    15601658
    1561     } else {                        /* $n */
    1562         n = getvar_i(V[NF]);
    1563         setvar_i(V[NF], n > v-Fields ? n : v-Fields+1);
     1659    } else {                /* $n */
     1660        n = getvar_i(intvar[NF]);
     1661        setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1);
    15641662        /* right here v is invalid. Just to note... */
    15651663    }
     
    15911689
    15921690    v->type |= VF_WALK;
    1593     w = v->x.walker = (char **)xzalloc(2 + 2*sizeof(char *) + array->glen);
    1594     *w = *(w+1) = (char *)(w + 2);
    1595     for (i=0; i<array->csize; i++) {
     1691    w = v->x.walker = xzalloc(2 + 2*sizeof(char *) + array->glen);
     1692    w[0] = w[1] = (char *)(w + 2);
     1693    for (i = 0; i < array->csize; i++) {
    15961694        hi = array->items[i];
    1597         while(hi) {
     1695        while (hi) {
    15981696            strcpy(*w, hi->name);
    15991697            nextword(w);
     
    16081706
    16091707    w = v->x.walker;
    1610     if (*(w+1) == *w)
     1708    if (w[1] == w[0])
    16111709        return FALSE;
    16121710
     
    16181716static int ptest(node *pattern)
    16191717{
    1620     static var v;
    1621     return istrue(evaluate(pattern, &v));
     1718    /* ptest__v is "static": to save stack space? */
     1719    return istrue(evaluate(pattern, &G.ptest__v));
    16221720}
    16231721
     
    16421740    rp = 0;
    16431741
    1644     if (! m) qrealloc(&m, 256, &size);
     1742    if (!m) qrealloc(&m, 256, &size);
    16451743    do {
    16461744        b = m + a;
     
    16501748            if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) {
    16511749                if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re,
    1652                                                 b, 1, pmatch, 0) == 0) {
     1750                            b, 1, pmatch, 0) == 0) {
    16531751                    so = pmatch[0].rm_so;
    16541752                    eo = pmatch[0].rm_eo;
     
    16581756            } else if (c != '\0') {
    16591757                s = strchr(b+pp, c);
    1660                 if (! s) s = memchr(b+pp, '\0', p - pp);
     1758                if (!s) s = memchr(b+pp, '\0', p - pp);
    16611759                if (s) {
    16621760                    so = eo = s-b;
     
    16901788            p = 0;
    16911789            r = 0;
    1692             setvar_i(V[ERRNO], errno);
     1790            setvar_i(intvar[ERRNO], errno);
    16931791        }
    16941792        b[p] = '\0';
     
    17041802        b[so] = c;
    17051803        c = b[eo]; b[eo] = '\0';
    1706         setvar_s(V[RT], b+so);
     1804        setvar_s(intvar[RT], b+so);
    17071805        b[eo] = c;
    17081806    }
     
    17181816static int fmt_num(char *b, int size, const char *format, double n, int int_as_int)
    17191817{
    1720     int r=0;
     1818    int r = 0;
    17211819    char c;
    1722     const char *s=format;
     1820    const char *s = format;
    17231821
    17241822    if (int_as_int && n == (int)n) {
    17251823        r = snprintf(b, size, "%d", (int)n);
    17261824    } else {
    1727         do { c = *s; } while (*s && *++s);
     1825        do { c = *s; } while (c && *++s);
    17281826        if (strchr("diouxX", c)) {
    17291827            r = snprintf(b, size, format, (int)n);
     
    17311829            r = snprintf(b, size, format, n);
    17321830        } else {
    1733             runtime_error(EMSG_INV_FMT);
     1831            syntax_error(EMSG_INV_FMT);
    17341832        }
    17351833    }
     
    17421840{
    17431841    char *b = NULL;
    1744     char *fmt, *s, *s1, *f;
     1842    char *fmt, *s, *f;
     1843    const char *s1;
    17451844    int i, j, incr, bsize;
    17461845    char c, c1;
     
    17481847
    17491848    v = nvalloc(1);
    1750     fmt = f = bb_xstrdup(getvar_s(evaluate(nextarg(&n), v)));
     1849    fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v)));
    17511850
    17521851    i = 0;
     
    17551854        while (*f && (*f != '%' || *(++f) == '%'))
    17561855            f++;
    1757         while (*f && !isalpha(*f))
     1856        while (*f && !isalpha(*f)) {
     1857            if (*f == '*')
     1858                syntax_error("%*x formats are not supported");
    17581859            f++;
     1860        }
    17591861
    17601862        incr = (f - s) + MAXVARFMT;
    1761         qrealloc(&b, incr+i, &bsize);
    1762         c = *f; if (c != '\0') f++;
    1763         c1 = *f ; *f = '\0';
     1863        qrealloc(&b, incr + i, &bsize);
     1864        c = *f;
     1865        if (c != '\0') f++;
     1866        c1 = *f;
     1867        *f = '\0';
    17641868        arg = evaluate(nextarg(&n), v);
    17651869
    17661870        j = i;
    17671871        if (c == 'c' || !c) {
    1768             i += sprintf(b+i, s,
    1769                     is_numeric(arg) ? (char)getvar_i(arg) : *getvar_s(arg));
    1770 
     1872            i += sprintf(b+i, s, is_numeric(arg) ?
     1873                    (char)getvar_i(arg) : *getvar_s(arg));
    17711874        } else if (c == 's') {
    1772             s1 = getvar_s(arg);
     1875            s1 = getvar_s(arg);
    17731876            qrealloc(&b, incr+i+strlen(s1), &bsize);
    17741877            i += sprintf(b+i, s, s1);
    1775 
    17761878        } else {
    17771879            i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE);
     
    17811883        /* if there was an error while sprintf, return value is negative */
    17821884        if (i < j) i = j;
    1783 
    1784     }
    1785 
    1786     b = xrealloc(b, i+1);
     1885    }
     1886
     1887    b = xrealloc(b, i + 1);
    17871888    free(fmt);
    17881889    nvfree(v);
     
    17971898 * subexpression matching (\1-\9)
    17981899 */
    1799 static int awk_sub(node *rn, char *repl, int nm, var *src, var *dest, int ex)
     1900static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex)
    18001901{
    18011902    char *ds = NULL;
    1802     char *sp, *s;
     1903    const char *s;
     1904    const char *sp;
    18031905    int c, i, j, di, rl, so, eo, nbs, n, dssize;
    18041906    regmatch_t pmatch[10];
     
    18061908
    18071909    re = as_regex(rn, &sreg);
    1808     if (! src) src = V[F0];
    1809     if (! dest) dest = V[F0];
     1910    if (!src) src = intvar[F0];
     1911    if (!dest) dest = intvar[F0];
    18101912
    18111913    i = di = 0;
    18121914    sp = getvar_s(src);
    18131915    rl = strlen(repl);
    1814     while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0:REG_NOTBOL) == 0) {
     1916    while (regexec(re, sp, 10, pmatch, sp==getvar_s(src) ? 0 : REG_NOTBOL) == 0) {
    18151917        so = pmatch[0].rm_so;
    18161918        eo = pmatch[0].rm_eo;
     
    18521954        if (i == nm) break;
    18531955        if (eo == so) {
    1854             if (! (ds[di++] = *sp++)) break;
     1956            ds[di] = *sp++;
     1957            if (!ds[di++]) break;
    18551958        }
    18561959    }
     
    18651968static var *exec_builtin(node *op, var *res)
    18661969{
     1970#define tspl (G.exec_builtin__tspl)
     1971
    18671972    int (*to_xxx)(int);
    18681973    var *tv;
    18691974    node *an[4];
    1870     var  *av[4];
    1871     char *as[4];
     1975    var *av[4];
     1976    const char *as[4];
    18721977    regmatch_t pmatch[2];
    18731978    regex_t sreg, *re;
    1874     static tsplitter tspl;
    18751979    node *spl;
    18761980    uint32_t isr, info;
     
    18851989
    18861990    av[2] = av[3] = NULL;
    1887     for (i=0 ; i<4 && op ; i++) {
     1991    for (i = 0; i < 4 && op; i++) {
    18881992        an[i] = nextarg(&op);
    18891993        if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]);
     
    18941998    nargs = i;
    18951999    if (nargs < (info >> 30))
    1896         runtime_error(EMSG_TOO_FEW_ARGS);
     2000        syntax_error(EMSG_TOO_FEW_ARGS);
    18972001
    18982002    switch (info & OPNMASK) {
    18992003
    1900       case B_a2:
    1901 #ifdef CONFIG_FEATURE_AWK_MATH
     2004    case B_a2:
     2005#if ENABLE_FEATURE_AWK_MATH
    19022006        setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1])));
    19032007#else
    1904         runtime_error(EMSG_NO_MATH);
     2008        syntax_error(EMSG_NO_MATH);
    19052009#endif
    19062010        break;
    19072011
    1908       case B_sp:
     2012    case B_sp:
    19092013        if (nargs > 2) {
    19102014            spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ?
     
    19232027        break;
    19242028
    1925       case B_ss:
     2029    case B_ss:
    19262030        l = strlen(as[0]);
    19272031        i = getvar_i(av[1]) - 1;
    1928         if (i>l) i=l; if (i<0) i=0;
     2032        if (i > l) i = l;
     2033        if (i < 0) i = 0;
    19292034        n = (nargs > 2) ? getvar_i(av[2]) : l-i;
    1930         if (n<0) n=0;
     2035        if (n < 0) n = 0;
    19312036        s = xmalloc(n+1);
    19322037        strncpy(s, as[0]+i, n);
     
    19352040        break;
    19362041
    1937       case B_lo:
     2042    case B_an:
     2043        setvar_i(res, (long)getvar_i(av[0]) & (long)getvar_i(av[1]));
     2044        break;
     2045
     2046    case B_co:
     2047        setvar_i(res, ~(long)getvar_i(av[0]));
     2048        break;
     2049
     2050    case B_ls:
     2051        setvar_i(res, (long)getvar_i(av[0]) << (long)getvar_i(av[1]));
     2052        break;
     2053
     2054    case B_or:
     2055        setvar_i(res, (long)getvar_i(av[0]) | (long)getvar_i(av[1]));
     2056        break;
     2057
     2058    case B_rs:
     2059        setvar_i(res, (long)((unsigned long)getvar_i(av[0]) >> (unsigned long)getvar_i(av[1])));
     2060        break;
     2061
     2062    case B_xo:
     2063        setvar_i(res, (long)getvar_i(av[0]) ^ (long)getvar_i(av[1]));
     2064        break;
     2065
     2066    case B_lo:
    19382067        to_xxx = tolower;
    19392068        goto lo_cont;
    19402069
    1941       case B_up:
     2070    case B_up:
    19422071        to_xxx = toupper;
    1943 lo_cont:
    1944         s1 = s = bb_xstrdup(as[0]);
     2072 lo_cont:
     2073        s1 = s = xstrdup(as[0]);
    19452074        while (*s1) {
    19462075            *s1 = (*to_xxx)(*s1);
     
    19502079        break;
    19512080
    1952       case B_ix:
     2081    case B_ix:
    19532082        n = 0;
    19542083        ll = strlen(as[1]);
    19552084        l = strlen(as[0]) - ll;
    19562085        if (ll > 0 && l >= 0) {
    1957             if (! icase) {
     2086            if (!icase) {
    19582087                s = strstr(as[0], as[1]);
    19592088                if (s) n = (s - as[0]) + 1;
     
    19732102        break;
    19742103
    1975       case B_ti:
     2104    case B_ti:
    19762105        if (nargs > 1)
    19772106            tt = getvar_i(av[1]);
    19782107        else
    19792108            time(&tt);
    1980         s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
    1981         i = strftime(buf, MAXVARFMT, s, localtime(&tt));
    1982         buf[i] = '\0';
    1983         setvar_s(res, buf);
     2109        //s = (nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y";
     2110        i = strftime(g_buf, MAXVARFMT,
     2111            ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"),
     2112            localtime(&tt));
     2113        g_buf[i] = '\0';
     2114        setvar_s(res, g_buf);
    19842115        break;
    19852116
    1986       case B_ma:
     2117    case B_ma:
    19872118        re = as_regex(an[1], &sreg);
    19882119        n = regexec(re, as[0], 1, pmatch, 0);
     
    20002131        break;
    20012132
    2002       case B_ge:
     2133    case B_ge:
    20032134        awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE);
    20042135        break;
    20052136
    2006       case B_gs:
     2137    case B_gs:
    20072138        setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE));
    20082139        break;
    20092140
    2010       case B_su:
     2141    case B_su:
    20112142        setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE));
    20122143        break;
     
    20152146    nvfree(tv);
    20162147    return res;
     2148#undef tspl
    20172149}
    20182150
     
    20252157static var *evaluate(node *op, var *res)
    20262158{
    2027     /* This procedure is recursive so we should count every byte */
    2028     static var *fnargs = NULL;
    2029     static unsigned int seed = 1;
    2030     static regex_t sreg;
     2159/* This procedure is recursive so we should count every byte */
     2160#define fnargs (G.evaluate__fnargs)
     2161/* seed is initialized to 1 */
     2162#define seed   (G.evaluate__seed)
     2163#define sreg   (G.evaluate__sreg)
     2164
    20312165    node *op1;
    20322166    var *v1;
    20332167    union {
    20342168        var *v;
    2035         char *s;
     2169        const char *s;
    20362170        double d;
    20372171        int i;
    20382172    } L, R;
    20392173    uint32_t opinfo;
    2040     short opn;
     2174    int opn;
    20412175    union {
    20422176        char *s;
     
    20482182    } X;
    20492183
    2050     if (! op)
     2184    if (!op)
    20512185        return setvar_s(res, NULL);
    20522186
     
    20542188
    20552189    while (op) {
    2056 
    20572190        opinfo = op->info;
    2058         opn = (short)(opinfo & OPNMASK);
    2059         lineno = op->lineno;
     2191        opn = (opinfo & OPNMASK);
     2192        g_lineno = op->lineno;
    20602193
    20612194        /* execute inevitable things */
     
    20692202        switch (XC(opinfo & OPCLSMASK)) {
    20702203
    2071           /* -- iterative node type -- */
    2072 
    2073           /* test pattern */
    2074           case XC( OC_TEST ):
     2204        /* -- iterative node type -- */
     2205
     2206        /* test pattern */
     2207        case XC( OC_TEST ):
    20752208            if ((op1->info & OPCLSMASK) == OC_COMMA) {
    20762209                /* it's range pattern */
     
    20892222            break;
    20902223
    2091           /* just evaluate an expression, also used as unconditional jump */
    2092           case XC( OC_EXEC ):
    2093             break;
    2094 
    2095           /* branch, used in if-else and various loops */
    2096           case XC( OC_BR ):
     2224        /* just evaluate an expression, also used as unconditional jump */
     2225        case XC( OC_EXEC ):
     2226            break;
     2227
     2228        /* branch, used in if-else and various loops */
     2229        case XC( OC_BR ):
    20972230            op = istrue(L.v) ? op->a.n : op->r.n;
    20982231            break;
    20992232
    2100           /* initialize for-in loop */
    2101           case XC( OC_WALKINIT ):
     2233        /* initialize for-in loop */
     2234        case XC( OC_WALKINIT ):
    21022235            hashwalk_init(L.v, iamarray(R.v));
    21032236            break;
    21042237
    2105           /* get next array item */
    2106           case XC( OC_WALKNEXT ):
     2238        /* get next array item */
     2239        case XC( OC_WALKNEXT ):
    21072240            op = hashwalk_next(L.v) ? op->a.n : op->r.n;
    21082241            break;
    21092242
    2110           case XC( OC_PRINT ):
    2111           case XC( OC_PRINTF ):
     2243        case XC( OC_PRINT ):
     2244        case XC( OC_PRINTF ):
    21122245            X.F = stdout;
    21132246            if (op->r.n) {
    21142247                X.rsm = newfile(R.s);
    2115                 if (! X.rsm->F) {
     2248                if (!X.rsm->F) {
    21162249                    if (opn == '|') {
    2117                         if((X.rsm->F = popen(R.s, "w")) == NULL)
     2250                        X.rsm->F = popen(R.s, "w");
     2251                        if (X.rsm->F == NULL)
    21182252                            bb_perror_msg_and_die("popen");
    21192253                        X.rsm->is_pipe = 1;
    21202254                    } else {
    2121                         X.rsm->F = bb_xfopen(R.s, opn=='w' ? "w" : "a");
     2255                        X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a");
    21222256                    }
    21232257                }
     
    21262260
    21272261            if ((opinfo & OPCLSMASK) == OC_PRINT) {
    2128                 if (! op1) {
    2129                     fputs(getvar_s(V[F0]), X.F);
     2262                if (!op1) {
     2263                    fputs(getvar_s(intvar[F0]), X.F);
    21302264                } else {
    21312265                    while (op1) {
    21322266                        L.v = evaluate(nextarg(&op1), v1);
    21332267                        if (L.v->type & VF_NUMBER) {
    2134                             fmt_num(buf, MAXVARFMT, getvar_s(V[OFMT]),
    2135                                                         getvar_i(L.v), TRUE);
    2136                             fputs(buf, X.F);
     2268                            fmt_num(g_buf, MAXVARFMT, getvar_s(intvar[OFMT]),
     2269                                    getvar_i(L.v), TRUE);
     2270                            fputs(g_buf, X.F);
    21372271                        } else {
    21382272                            fputs(getvar_s(L.v), X.F);
    21392273                        }
    21402274
    2141                         if (op1) fputs(getvar_s(V[OFS]), X.F);
     2275                        if (op1) fputs(getvar_s(intvar[OFS]), X.F);
    21422276                    }
    21432277                }
    2144                 fputs(getvar_s(V[ORS]), X.F);
     2278                fputs(getvar_s(intvar[ORS]), X.F);
    21452279
    21462280            } else {    /* OC_PRINTF */
    21472281                L.s = awk_printf(op1);
    21482282                fputs(L.s, X.F);
    2149                 free(L.s);
     2283                free((char*)L.s);
    21502284            }
    21512285            fflush(X.F);
    21522286            break;
    21532287
    2154           case XC( OC_DELETE ):
     2288        case XC( OC_DELETE ):
    21552289            X.info = op1->info & OPCLSMASK;
    21562290            if (X.info == OC_VAR) {
     
    21592293                R.v = &fnargs[op1->l.i];
    21602294            } else {
    2161                 runtime_error(EMSG_NOT_ARRAY);
     2295                syntax_error(EMSG_NOT_ARRAY);
    21622296            }
    21632297
     
    21712305            break;
    21722306
    2173           case XC( OC_NEWSOURCE ):
    2174             programname = op->l.s;
    2175             break;
    2176 
    2177           case XC( OC_RETURN ):
     2307        case XC( OC_NEWSOURCE ):
     2308            g_progname = op->l.s;
     2309            break;
     2310
     2311        case XC( OC_RETURN ):
    21782312            copyvar(res, L.v);
    21792313            break;
    21802314
    2181           case XC( OC_NEXTFILE ):
     2315        case XC( OC_NEXTFILE ):
    21822316            nextfile = TRUE;
    2183           case XC( OC_NEXT ):
     2317        case XC( OC_NEXT ):
    21842318            nextrec = TRUE;
    2185           case XC( OC_DONE ):
     2319        case XC( OC_DONE ):
    21862320            clrvar(res);
    21872321            break;
    21882322
    2189           case XC( OC_EXIT ):
     2323        case XC( OC_EXIT ):
    21902324            awk_exit(L.d);
    21912325
    2192           /* -- recursive node type -- */
    2193 
    2194           case XC( OC_VAR ):
     2326        /* -- recursive node type -- */
     2327
     2328        case XC( OC_VAR ):
    21952329            L.v = op->l.v;
    2196             if (L.v == V[NF])
     2330            if (L.v == intvar[NF])
    21972331                split_f0();
    21982332            goto v_cont;
    21992333
    2200           case XC( OC_FNARG ):
     2334        case XC( OC_FNARG ):
    22012335            L.v = &fnargs[op->l.i];
    2202 
    2203 v_cont:
    2204             res = (op->r.n) ? findvar(iamarray(L.v), R.s) : L.v;
    2205             break;
    2206 
    2207           case XC( OC_IN ):
     2336 v_cont:
     2337            res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v;
     2338            break;
     2339
     2340        case XC( OC_IN ):
    22082341            setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0);
    22092342            break;
    22102343
    2211           case XC( OC_REGEXP ):
     2344        case XC( OC_REGEXP ):
    22122345            op1 = op;
    2213             L.s = getvar_s(V[F0]);
     2346            L.s = getvar_s(intvar[F0]);
    22142347            goto re_cont;
    22152348
    2216           case XC( OC_MATCH ):
     2349        case XC( OC_MATCH ):
    22172350            op1 = op->r.n;
    2218 re_cont:
     2351 re_cont:
    22192352            X.re = as_regex(op1, &sreg);
    22202353            R.i = regexec(X.re, L.s, 0, NULL, 0);
     
    22232356            break;
    22242357
    2225           case XC( OC_MOVE ):
     2358        case XC( OC_MOVE ):
    22262359            /* if source is a temporary string, jusk relink it to dest */
    22272360            if (R.v == v1+1 && R.v->string) {
     
    22332366            break;
    22342367
    2235           case XC( OC_TERNARY ):
     2368        case XC( OC_TERNARY ):
    22362369            if ((op->r.n->info & OPCLSMASK) != OC_COLON)
    2237                 runtime_error(EMSG_POSSIBLE_ERROR);
     2370                syntax_error(EMSG_POSSIBLE_ERROR);
    22382371            res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res);
    22392372            break;
    22402373
    2241           case XC( OC_FUNC ):
    2242             if (! op->r.f->body.first)
    2243                 runtime_error(EMSG_UNDEF_FUNC);
     2374        case XC( OC_FUNC ):
     2375            if (!op->r.f->body.first)
     2376                syntax_error(EMSG_UNDEF_FUNC);
    22442377
    22452378            X.v = R.v = nvalloc(op->r.f->nargs+1);
     
    22562389            fnargs = X.v;
    22572390
    2258             L.s = programname;
     2391            L.s = g_progname;
    22592392            res = evaluate(op->r.f->body.first, res);
    2260             programname = L.s;
     2393            g_progname = L.s;
    22612394
    22622395            nvfree(fnargs);
     
    22642397            break;
    22652398
    2266           case XC( OC_GETLINE ):
    2267           case XC( OC_PGETLINE ):
     2399        case XC( OC_GETLINE ):
     2400        case XC( OC_PGETLINE ):
    22682401            if (op1) {
    22692402                X.rsm = newfile(L.s);
    2270                 if (! X.rsm->F) {
     2403                if (!X.rsm->F) {
    22712404                    if ((opinfo & OPCLSMASK) == OC_PGETLINE) {
    22722405                        X.rsm->F = popen(L.s, "r");
    22732406                        X.rsm->is_pipe = TRUE;
    22742407                    } else {
    2275                         X.rsm->F = fopen(L.s, "r");     /* not bb_xfopen! */
     2408                        X.rsm->F = fopen(L.s, "r");     /* not xfopen! */
    22762409                    }
    22772410                }
    22782411            } else {
    2279                 if (! iF) iF = next_input_file();
     2412                if (!iF) iF = next_input_file();
    22802413                X.rsm = iF;
    22812414            }
    22822415
    2283             if (! X.rsm->F) {
    2284                 setvar_i(V[ERRNO], errno);
     2416            if (!X.rsm->F) {
     2417                setvar_i(intvar[ERRNO], errno);
    22852418                setvar_i(res, -1);
    22862419                break;
    22872420            }
    22882421
    2289             if (! op->r.n)
    2290                 R.v = V[F0];
     2422            if (!op->r.n)
     2423                R.v = intvar[F0];
    22912424
    22922425            L.i = awk_getline(X.rsm, R.v);
    22932426            if (L.i > 0) {
    2294                 if (! op1) {
    2295                     incvar(V[FNR]);
    2296                     incvar(V[NR]);
     2427                if (!op1) {
     2428                    incvar(intvar[FNR]);
     2429                    incvar(intvar[NR]);
    22972430                }
    22982431            }
     
    23002433            break;
    23012434
    2302           /* simple builtins */
    2303           case XC( OC_FBLTIN ):
     2435        /* simple builtins */
     2436        case XC( OC_FBLTIN ):
    23042437            switch (opn) {
    23052438
    2306               case F_in:
     2439            case F_in:
    23072440                R.d = (int)L.d;
    23082441                break;
    23092442
    2310               case F_rn:
    2311                 R.d =  (double)rand() / (double)RAND_MAX;
     2443            case F_rn:
     2444                R.d = (double)rand() / (double)RAND_MAX;
    23122445                break;
    2313 
    2314 #ifdef CONFIG_FEATURE_AWK_MATH
    2315               case F_co:
     2446#if ENABLE_FEATURE_AWK_MATH
     2447            case F_co:
    23162448                R.d = cos(L.d);
    23172449                break;
    23182450
    2319               case F_ex:
     2451            case F_ex:
    23202452                R.d = exp(L.d);
    23212453                break;
    23222454
    2323               case F_lg:
     2455            case F_lg:
    23242456                R.d = log(L.d);
    23252457                break;
    23262458
    2327               case F_si:
     2459            case F_si:
    23282460                R.d = sin(L.d);
    23292461                break;
    23302462
    2331               case F_sq:
     2463            case F_sq:
    23322464                R.d = sqrt(L.d);
    23332465                break;
    23342466#else
    2335               case F_co:
    2336               case F_ex:
    2337               case F_lg:
    2338               case F_si:
    2339               case F_sq:
    2340                 runtime_error(EMSG_NO_MATH);
     2467            case F_co:
     2468            case F_ex:
     2469            case F_lg:
     2470            case F_si:
     2471            case F_sq:
     2472                syntax_error(EMSG_NO_MATH);
    23412473                break;
    23422474#endif
    2343 
    2344               case F_sr:
     2475            case F_sr:
    23452476                R.d = (double)seed;
    2346                 seed = op1 ? (unsigned int)L.d : (unsigned int)time(NULL);
     2477                seed = op1 ? (unsigned)L.d : (unsigned)time(NULL);
    23472478                srand(seed);
    23482479                break;
    23492480
    2350               case F_ti:
     2481            case F_ti:
    23512482                R.d = time(NULL);
    23522483                break;
    23532484
    2354               case F_le:
    2355                 if (! op1)
    2356                     L.s = getvar_s(V[F0]);
     2485            case F_le:
     2486                if (!op1)
     2487                    L.s = getvar_s(intvar[F0]);
    23572488                R.d = strlen(L.s);
    23582489                break;
    23592490
    2360               case F_sy:
     2491            case F_sy:
    23612492                fflush(NULL);
    2362                 R.d = (L.s && *L.s) ? (system(L.s) >> 8) : 0;
     2493                R.d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s)
     2494                        ? (system(L.s) >> 8) : 0;
    23632495                break;
    23642496
    2365               case F_ff:
    2366                 if (! op1)
     2497            case F_ff:
     2498                if (!op1)
    23672499                    fflush(stdout);
    23682500                else {
     
    23762508                break;
    23772509
    2378               case F_cl:
     2510            case F_cl:
    23792511                X.rsm = (rstream *)hash_search(fdhash, L.s);
    23802512                if (X.rsm) {
     
    23842516                }
    23852517                if (R.i != 0)
    2386                     setvar_i(V[ERRNO], errno);
     2518                    setvar_i(intvar[ERRNO], errno);
    23872519                R.d = (double)R.i;
    23882520                break;
     
    23912523            break;
    23922524
    2393           case XC( OC_BUILTIN ):
     2525        case XC( OC_BUILTIN ):
    23942526            res = exec_builtin(op, res);
    23952527            break;
    23962528
    2397           case XC( OC_SPRINTF ):
     2529        case XC( OC_SPRINTF ):
    23982530            setvar_p(res, awk_printf(op1));
    23992531            break;
    24002532
    2401           case XC( OC_UNARY ):
     2533        case XC( OC_UNARY ):
    24022534            X.v = R.v;
    24032535            L.d = R.d = getvar_i(R.v);
    24042536            switch (opn) {
    2405               case 'P':
     2537            case 'P':
    24062538                L.d = ++R.d;
    24072539                goto r_op_change;
    2408               case 'p':
     2540            case 'p':
    24092541                R.d++;
    24102542                goto r_op_change;
    2411               case 'M':
     2543            case 'M':
    24122544                L.d = --R.d;
    24132545                goto r_op_change;
    2414               case 'm':
     2546            case 'm':
    24152547                R.d--;
    24162548                goto r_op_change;
    2417               case '!':
    2418                 L.d = istrue(X.v) ? 0 : 1;
     2549            case '!':
     2550                L.d = istrue(X.v) ? 0 : 1;
    24192551                break;
    2420               case '-':
     2552            case '-':
    24212553                L.d = -R.d;
    24222554                break;
    2423             r_op_change:
     2555 r_op_change:
    24242556                setvar_i(X.v, R.d);
    24252557            }
     
    24272559            break;
    24282560
    2429           case XC( OC_FIELD ):
     2561        case XC( OC_FIELD ):
    24302562            R.i = (int)getvar_i(R.v);
    24312563            if (R.i == 0) {
    2432                 res = V[F0];
     2564                res = intvar[F0];
    24332565            } else {
    24342566                split_f0();
    24352567                if (R.i > nfields)
    24362568                    fsrealloc(R.i);
    2437 
    2438                 res = &Fields[R.i-1];
    2439             }
    2440             break;
    2441 
    2442           /* concatenation (" ") and index joining (",") */
    2443           case XC( OC_CONCAT ):
    2444           case XC( OC_COMMA ):
     2569                res = &Fields[R.i - 1];
     2570            }
     2571            break;
     2572
     2573        /* concatenation (" ") and index joining (",") */
     2574        case XC( OC_CONCAT ):
     2575        case XC( OC_COMMA ):
    24452576            opn = strlen(L.s) + strlen(R.s) + 2;
    2446             X.s = (char *)xmalloc(opn);
     2577            X.s = xmalloc(opn);
    24472578            strcpy(X.s, L.s);
    24482579            if ((opinfo & OPCLSMASK) == OC_COMMA) {
    2449                 L.s = getvar_s(V[SUBSEP]);
    2450                 X.s = (char *)xrealloc(X.s, opn + strlen(L.s));
     2580                L.s = getvar_s(intvar[SUBSEP]);
     2581                X.s = xrealloc(X.s, opn + strlen(L.s));
    24512582                strcat(X.s, L.s);
    24522583            }
     
    24552586            break;
    24562587
    2457           case XC( OC_LAND ):
     2588        case XC( OC_LAND ):
    24582589            setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0);
    24592590            break;
    24602591
    2461           case XC( OC_LOR ):
     2592        case XC( OC_LOR ):
    24622593            setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n));
    24632594            break;
    24642595
    2465           case XC( OC_BINARY ):
    2466           case XC( OC_REPLACE ):
     2596        case XC( OC_BINARY ):
     2597        case XC( OC_REPLACE ):
    24672598            R.d = getvar_i(R.v);
    24682599            switch (opn) {
    2469               case '+':
     2600            case '+':
    24702601                L.d += R.d;
    24712602                break;
    2472               case '-':
     2603            case '-':
    24732604                L.d -= R.d;
    24742605                break;
    2475               case '*':
     2606            case '*':
    24762607                L.d *= R.d;
    24772608                break;
    2478               case '/':
    2479                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
     2609            case '/':
     2610                if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
    24802611                L.d /= R.d;
    24812612                break;
    2482               case '&':
    2483 #ifdef CONFIG_FEATURE_AWK_MATH
     2613            case '&':
     2614#if ENABLE_FEATURE_AWK_MATH
    24842615                L.d = pow(L.d, R.d);
    24852616#else
    2486                 runtime_error(EMSG_NO_MATH);
     2617                syntax_error(EMSG_NO_MATH);
    24872618#endif
    24882619                break;
    2489               case '%':
    2490                 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);
     2620            case '%':
     2621                if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO);
    24912622                L.d -= (int)(L.d / R.d) * R.d;
    24922623                break;
    24932624            }
    2494             res = setvar_i(((opinfo&OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
    2495             break;
    2496 
    2497           case XC( OC_COMPARE ):
     2625            res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);
     2626            break;
     2627
     2628        case XC( OC_COMPARE ):
    24982629            if (is_numeric(L.v) && is_numeric(R.v)) {
    24992630                L.d = getvar_i(L.v) - getvar_i(R.v);
     
    25042635            }
    25052636            switch (opn & 0xfe) {
    2506               case 0:
     2637            case 0:
    25072638                R.i = (L.d > 0);
    25082639                break;
    2509               case 2:
     2640            case 2:
    25102641                R.i = (L.d >= 0);
    25112642                break;
    2512               case 4:
     2643            case 4:
    25132644                R.i = (L.d == 0);
    25142645                break;
     
    25172648            break;
    25182649
    2519           default:
    2520             runtime_error(EMSG_POSSIBLE_ERROR);
     2650        default:
     2651            syntax_error(EMSG_POSSIBLE_ERROR);
    25212652        }
    25222653        if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS)
     
    25292660    nvfree(v1);
    25302661    return res;
     2662#undef fnargs
     2663#undef seed
     2664#undef sreg
    25312665}
    25322666
     
    25362670static int awk_exit(int r)
    25372671{
    2538     unsigned int i;
     2672    var tv;
     2673    unsigned i;
    25392674    hash_item *hi;
    2540     static var tv;
    2541 
    2542     if (! exiting) {
     2675
     2676    zero_out_var(&tv);
     2677
     2678    if (!exiting) {
    25432679        exiting = TRUE;
    25442680        nextrec = FALSE;
     
    25472683
    25482684    /* waiting for children */
    2549     for (i=0; i<fdhash->csize; i++) {
     2685    for (i = 0; i < fdhash->csize; i++) {
    25502686        hi = fdhash->items[i];
    2551         while(hi) {
     2687        while (hi) {
    25522688            if (hi->data.rs.F && hi->data.rs.is_pipe)
    25532689                pclose(hi->data.rs.F);
     
    25652701    char *exprc, *s, *s0, *s1;
    25662702
    2567     exprc = bb_xstrdup(expr);
     2703    exprc = xstrdup(expr);
    25682704    if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
    25692705        free(exprc);
     
    25852721static rstream *next_input_file(void)
    25862722{
    2587     static rstream rsm;
     2723#define rsm          (G.next_input_file__rsm)
     2724#define files_happen (G.next_input_file__files_happen)
     2725
    25882726    FILE *F = NULL;
    2589     char *fname, *ind;
    2590     static int files_happen = FALSE;
     2727    const char *fname, *ind;
    25912728
    25922729    if (rsm.F) fclose(rsm.F);
     
    25952732
    25962733    do {
    2597         if (getvar_i(V[ARGIND])+1 >= getvar_i(V[ARGC])) {
     2734        if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) {
    25982735            if (files_happen)
    25992736                return NULL;
     
    26012738            F = stdin;
    26022739        } else {
    2603             ind = getvar_s(incvar(V[ARGIND]));
    2604             fname = getvar_s(findvar(iamarray(V[ARGV]), ind));
     2740            ind = getvar_s(incvar(intvar[ARGIND]));
     2741            fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind));
    26052742            if (fname && *fname && !is_assignment(fname))
    26062743                F = afopen(fname, "r");
     
    26092746
    26102747    files_happen = TRUE;
    2611     setvar_s(V[FILENAME], fname);
     2748    setvar_s(intvar[FILENAME], fname);
    26122749    rsm.F = F;
    26132750    return &rsm;
    2614 }
    2615 
     2751#undef rsm
     2752#undef files_happen
     2753}
     2754
     2755int awk_main(int argc, char **argv);
    26162756int awk_main(int argc, char **argv)
    26172757{
    2618     char *s, *s1;
    2619     int i, j, c, flen;
     2758    unsigned opt;
     2759    char *opt_F, *opt_W;
     2760    llist_t *opt_v = NULL;
     2761    int i, j, flen;
    26202762    var *v;
    2621     static var tv;
     2763    var tv;
    26222764    char **envp;
    2623     static int from_file = FALSE;
    2624     rstream *rsm;
    2625     FILE *F, *stdfiles[3];
    2626     static char * stdnames = "/dev/stdin\0/dev/stdout\0/dev/stderr";
     2765    char *vnames = (char *)vNames; /* cheat */
     2766    char *vvalues = (char *)vValues;
     2767
     2768    INIT_G();
     2769
     2770    /* Undo busybox.c, or else strtod may eat ','! This breaks parsing:
     2771     * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */
     2772    if (ENABLE_LOCALE_SUPPORT)
     2773        setlocale(LC_NUMERIC, "C");
     2774
     2775    zero_out_var(&tv);
    26272776
    26282777    /* allocate global buffer */
    2629     buf = xmalloc(MAXVARFMT+1);
     2778    g_buf = xmalloc(MAXVARFMT + 1);
    26302779
    26312780    vhash = hash_init();
     
    26352784
    26362785    /* initialize variables */
    2637     for (i=0;  *vNames; i++) {
    2638         V[i] = v = newvar(nextword(&vNames));
    2639         if (*vValues != '\377')
    2640             setvar_s(v, nextword(&vValues));
     2786    for (i = 0; *vnames; i++) {
     2787        intvar[i] = v = newvar(nextword(&vnames));
     2788        if (*vvalues != '\377')
     2789            setvar_s(v, nextword(&vvalues));
    26412790        else
    26422791            setvar_i(v, 0);
    26432792
    2644         if (*vNames == '*') {
     2793        if (*vnames == '*') {
    26452794            v->type |= VF_SPECIAL;
    2646             vNames++;
    2647         }
    2648     }
    2649 
    2650     handle_special(V[FS]);
    2651     handle_special(V[RS]);
    2652 
    2653     stdfiles[0] = stdin;
    2654     stdfiles[1] = stdout;
    2655     stdfiles[2] = stderr;
    2656     for (i=0; i<3; i++) {
    2657         rsm = newfile(nextword(&stdnames));
    2658         rsm->F = stdfiles[i];
    2659     }
    2660 
    2661     for (envp=environ; *envp; envp++) {
    2662         s = bb_xstrdup(*envp);
    2663         s1 = strchr(s, '=');
    2664         if (!s1) {
    2665             goto keep_going;
    2666         }
    2667         *(s1++) = '\0';
    2668         setvar_u(findvar(iamarray(V[ENVIRON]), s), s1);
    2669 keep_going:
     2795            vnames++;
     2796        }
     2797    }
     2798
     2799    handle_special(intvar[FS]);
     2800    handle_special(intvar[RS]);
     2801
     2802    newfile("/dev/stdin")->F = stdin;
     2803    newfile("/dev/stdout")->F = stdout;
     2804    newfile("/dev/stderr")->F = stderr;
     2805
     2806    /* Huh, people report that sometimes environ is NULL. Oh well. */
     2807    if (environ) for (envp = environ; *envp; envp++) {
     2808        /* environ is writable, thus we don't strdup it needlessly */
     2809        char *s = *envp;
     2810        char *s1 = strchr(s, '=');
     2811        if (s1) {
     2812            *s1 = '\0';
     2813            /* Both findvar and setvar_u take const char*
     2814             * as 2nd arg -> environment is not trashed */
     2815            setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
     2816            *s1 = '=';
     2817        }
     2818    }
     2819    opt_complementary = "v::";
     2820    opt = getopt32(argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
     2821    argv += optind;
     2822    argc -= optind;
     2823    if (opt & 0x1)
     2824        setvar_s(intvar[FS], opt_F); // -F
     2825    while (opt_v) { /* -v */
     2826        if (!is_assignment(llist_pop(&opt_v)))
     2827            bb_show_usage();
     2828    }
     2829    if (opt & 0x4) { // -f
     2830        char *s = s; /* die, gcc, die */
     2831        FILE *from_file = afopen(g_progname, "r");
     2832        /* one byte is reserved for some trick in next_token */
     2833        if (fseek(from_file, 0, SEEK_END) == 0) {
     2834            flen = ftell(from_file);
     2835            s = xmalloc(flen + 4);
     2836            fseek(from_file, 0, SEEK_SET);
     2837            i = 1 + fread(s + 1, 1, flen, from_file);
     2838        } else {
     2839            for (i = j = 1; j > 0; i += j) {
     2840                s = xrealloc(s, i + 4096);
     2841                j = fread(s + i, 1, 4094, from_file);
     2842            }
     2843        }
     2844        s[i] = '\0';
     2845        fclose(from_file);
     2846        parse_program(s + 1);
    26702847        free(s);
    2671     }
    2672 
    2673     while((c = getopt(argc, argv, "F:v:f:W:")) != EOF) {
    2674         switch (c) {
    2675             case 'F':
    2676                 setvar_s(V[FS], optarg);
    2677                 break;
    2678             case 'v':
    2679                 if (! is_assignment(optarg))
    2680                     bb_show_usage();
    2681                 break;
    2682             case 'f':
    2683                 from_file = TRUE;
    2684                 F = afopen(programname = optarg, "r");
    2685                 s = NULL;
    2686                 /* one byte is reserved for some trick in next_token */
    2687                 if (fseek(F, 0, SEEK_END) == 0) {
    2688                     flen = ftell(F);
    2689                     s = (char *)xmalloc(flen+4);
    2690                     fseek(F, 0, SEEK_SET);
    2691                     i = 1 + fread(s+1, 1, flen, F);
    2692                 } else {
    2693                     for (i=j=1; j>0; i+=j) {
    2694                         s = (char *)xrealloc(s, i+4096);
    2695                         j = fread(s+i, 1, 4094, F);
    2696                     }
    2697                 }
    2698                 s[i] = '\0';
    2699                 fclose(F);
    2700                 parse_program(s+1);
    2701                 free(s);
    2702                 break;
    2703             case 'W':
    2704                 bb_error_msg("Warning: unrecognized option '-W %s' ignored\n", optarg);
    2705                 break;
    2706 
    2707             default:
    2708                 bb_show_usage();
    2709         }
    2710     }
    2711 
    2712     if (!from_file) {
    2713         if (argc == optind)
     2848    } else { // no -f: take program from 1st parameter
     2849        if (!argc)
    27142850            bb_show_usage();
    2715         programname="cmd. line";
    2716         parse_program(argv[optind++]);
    2717 
    2718     }
     2851        g_progname = "cmd. line";
     2852        parse_program(*argv++);
     2853        argc--;
     2854    }
     2855    if (opt & 0x8) // -W
     2856        bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W);
    27192857
    27202858    /* fill in ARGV array */
    2721     setvar_i(V[ARGC], argc - optind + 1);
    2722     setari_u(V[ARGV], 0, "awk");
    2723     for(i=optind; i < argc; i++)
    2724         setari_u(V[ARGV], i+1-optind, argv[i]);
     2859    setvar_i(intvar[ARGC], argc + 1);
     2860    setari_u(intvar[ARGV], 0, "awk");
     2861    i = 0;
     2862    while (*argv)
     2863        setari_u(intvar[ARGV], ++i, *argv++);
    27252864
    27262865    evaluate(beginseq.first, &tv);
    2727     if (! mainseq.first && ! endseq.first)
     2866    if (!mainseq.first && !endseq.first)
    27282867        awk_exit(EXIT_SUCCESS);
    27292868
    27302869    /* input file could already be opened in BEGIN block */
    2731     if (! iF) iF = next_input_file();
     2870    if (!iF) iF = next_input_file();
    27322871
    27332872    /* passing through input files */
    27342873    while (iF) {
    2735 
    27362874        nextfile = FALSE;
    2737         setvar_i(V[FNR], 0);
    2738 
    2739         while ((c = awk_getline(iF, V[F0])) > 0) {
    2740 
     2875        setvar_i(intvar[FNR], 0);
     2876
     2877        while ((i = awk_getline(iF, intvar[F0])) > 0) {
    27412878            nextrec = FALSE;
    2742             incvar(V[NR]);
    2743             incvar(V[FNR]);
     2879            incvar(intvar[NR]);
     2880            incvar(intvar[FNR]);
    27442881            evaluate(mainseq.first, &tv);
    27452882
     
    27482885        }
    27492886
    2750         if (c < 0)
    2751             runtime_error(strerror(errno));
     2887        if (i < 0)
     2888            syntax_error(strerror(errno));
    27522889
    27532890        iF = next_input_file();
    2754 
    27552891    }
    27562892
    27572893    awk_exit(EXIT_SUCCESS);
    2758 
    2759     return 0;
    2760 }
    2761 
     2894    /*return 0;*/
     2895}
  • branches/2.2.5/mindi-busybox/editors/ed.c

    r821 r1765  
    88 */
    99
    10 #include <stdio.h>
    11 #include <stdlib.h>
    12 #include <unistd.h>
    13 #include <fcntl.h>
    14 #include <string.h>
    15 #include <time.h>
    16 #include <ctype.h>
    17 #include <sys/param.h>
    18 #include "busybox.h"
    19 
    20 #define USERSIZE    1024    /* max line length typed in by user */
    21 #define INITBUF_SIZE    1024    /* initial buffer size */
     10#include "libbb.h"
     11
     12#define searchString bb_common_bufsiz1
     13
     14enum {
     15    USERSIZE = sizeof(searchString) > 1024 ? 1024
     16             : sizeof(searchString) - 1, /* max line length typed in by user */
     17    INITBUF_SIZE = 1024, /* initial buffer size */
     18};
     19
    2220typedef struct LINE {
    2321    struct LINE *next;
     
    2927static LINE lines, *curLine;
    3028static int curNum, lastNum, marks[26], dirty;
    31 static char *bufBase, *bufPtr, *fileName, searchString[USERSIZE];
     29static char *bufBase, *bufPtr, *fileName;
    3230static int bufUsed, bufSize;
    3331
     
    4947static int findString(const LINE *lp, const char * str, int len, int offset);
    5048
     49int ed_main(int argc, char **argv);
    5150int ed_main(int argc, char **argv)
    5251{
     
    5857
    5958        if (fileName == NULL) {
    60             bb_error_msg("No memory");
     59            bb_error_msg("no memory");
    6160            termEdit();
    6261            return EXIT_SUCCESS;
     
    8988    int len, num1, num2, have1, have2;
    9089
    91     while (TRUE)
    92     {
     90    while (TRUE) {
    9391        printf(": ");
    9492        fflush(stdout);
     
    104102        endbuf = &buf[len - 1];
    105103
    106         if (*endbuf != '\n')
    107         {
    108             bb_error_msg("Command line too long");
    109 
    110             do
    111             {
     104        if (*endbuf != '\n') {
     105            bb_error_msg("command line too long");
     106
     107            do {
    112108                len = fgetc(stdin);
    113             }
    114             while ((len != EOF) && (len != '\n'));
     109            } while ((len != EOF) && (len != '\n'));
    115110
    116111            continue;
     
    130125        have2 = FALSE;
    131126
    132         if ((curNum == 0) && (lastNum > 0))
    133         {
     127        if ((curNum == 0) && (lastNum > 0)) {
    134128            curNum = 1;
    135129            curLine = lines.next;
     
    142136            cp++;
    143137
    144         if (*cp == ',')
    145         {
     138        if (*cp == ',') {
    146139            cp++;
    147140
     
    165158            num2 = num1;
    166159
    167         switch (*cp++)
    168         {
     160        switch (*cp++) {
    169161            case 'a':
    170162                addLines(num1 + 1);
     
    181173
    182174            case 'f':
    183                 if (*cp && !isblank(*cp))
    184                 {
    185                     bb_error_msg("Bad file command");
     175                if (*cp && !isblank(*cp)) {
     176                    bb_error_msg("bad file command");
    186177                    break;
    187178                }
     
    190181                    cp++;
    191182
    192                 if (*cp == '\0')
    193                 {
     183                if (*cp == '\0') {
    194184                    if (fileName)
    195185                        printf("\"%s\"\n", fileName);
    196186                    else
    197187                        printf("No file name\n");
    198 
    199188                    break;
    200189                }
     
    202191                newname = strdup(cp);
    203192
    204                 if (newname == NULL)
    205                 {
    206                     bb_error_msg("No memory for file name");
     193                if (newname == NULL) {
     194                    bb_error_msg("no memory for file name");
    207195                    break;
    208196                }
     
    222210                    cp++;
    223211
    224                 if ((*cp < 'a') || (*cp > 'a') || cp[1])
    225                 {
    226                     bb_error_msg("Bad mark name");
     212                if ((*cp < 'a') || (*cp > 'a') || cp[1]) {
     213                    bb_error_msg("bad mark name");
    227214                    break;
    228215                }
     
    243230                    cp++;
    244231
    245                 if (have1 || *cp)
    246                 {
    247                     bb_error_msg("Bad quit command");
     232                if (have1 || *cp) {
     233                    bb_error_msg("bad quit command");
    248234                    break;
    249235                }
     
    268254
    269255            case 'r':
    270                 if (*cp && !isblank(*cp))
    271                 {
    272                     bb_error_msg("Bad read command");
     256                if (*cp && !isblank(*cp)) {
     257                    bb_error_msg("bad read command");
    273258                    break;
    274259                }
     
    277262                    cp++;
    278263
    279                 if (*cp == '\0')
    280                 {
    281                     bb_error_msg("No file name");
     264                if (*cp == '\0') {
     265                    bb_error_msg("no file name");
    282266                    break;
    283267                }
     
    299283
    300284            case 'w':
    301                 if (*cp && !isblank(*cp))
    302                 {
    303                     bb_error_msg("Bad write command");
     285                if (*cp && !isblank(*cp)) {
     286                    bb_error_msg("bad write command");
    304287                    break;
    305288                }
     
    316299                    cp = fileName;
    317300
    318                 if (cp == NULL)
    319                 {
    320                     bb_error_msg("No file name specified");
     301                if (cp == NULL) {
     302                    bb_error_msg("no file name specified");
    321303                    break;
    322304                }
     
    326308
    327309            case 'z':
    328                 switch (*cp)
    329                 {
     310                switch (*cp) {
    330311                case '-':
    331312                    printLines(curNum-21, curNum, FALSE);
     
    341322
    342323            case '.':
    343                 if (have1)
    344                 {
    345                     bb_error_msg("No arguments allowed");
     324                if (have1) {
     325                    bb_error_msg("no arguments allowed");
    346326                    break;
    347327                }
     
    361341
    362342            case '\0':
    363                 if (have1)
    364                 {
     343                if (have1) {
    365344                    printLines(num2, num2, FALSE);
    366345                    break;
     
    373352
    374353            default:
    375                 bb_error_msg("Unimplemented command");
     354                bb_error_msg("unimplemented command");
    376355                break;
    377356        }
     
    387366{
    388367    char *cp, *oldStr, *newStr, buf[USERSIZE];
    389     int delim, oldLen, newLen, deltaLen, offset;
     368    int delim, oldLen, newLen, deltaLen, offset;
    390369    LINE *lp, *nlp;
    391370    int globalFlag, printFlag, didSub, needPrint;
    392371
    393     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
    394     {
    395         bb_error_msg("Bad line range for substitute");
    396 
     372    if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
     373        bb_error_msg("bad line range for substitute");
    397374        return;
    398375    }
     
    409386    cp = buf;
    410387
    411     if (isblank(*cp) || (*cp == '\0'))
    412     {
    413         bb_error_msg("Bad delimiter for substitute");
    414 
     388    if (isblank(*cp) || (*cp == '\0')) {
     389        bb_error_msg("bad delimiter for substitute");
    415390        return;
    416391    }
     
    421396    cp = strchr(cp, delim);
    422397
    423     if (cp == NULL)
    424     {
    425         bb_error_msg("Missing 2nd delimiter for substitute");
    426 
     398    if (cp == NULL) {
     399        bb_error_msg("missing 2nd delimiter for substitute");
    427400        return;
    428401    }
     
    436409        *cp++ = '\0';
    437410    else
    438         cp = "";
    439 
    440     while (*cp) switch (*cp++)
    441     {
     411        cp = (char*)"";
     412
     413    while (*cp) switch (*cp++) {
    442414        case 'g':
    443415            globalFlag = TRUE;
     
    449421
    450422        default:
    451             bb_error_msg("Unknown option for substitute");
    452 
     423            bb_error_msg("unknown option for substitute");
    453424            return;
    454425    }
    455426
    456     if (*oldStr == '\0')
    457     {
    458         if (searchString[0] == '\0')
    459         {
    460             bb_error_msg("No previous search string");
    461 
     427    if (*oldStr == '\0') {
     428        if (searchString[0] == '\0') {
     429            bb_error_msg("no previous search string");
    462430            return;
    463431        }
     
    480448    nlp = NULL;
    481449
    482     while (num1 <= num2)
    483     {
     450    while (num1 <= num2) {
    484451        offset = findString(lp, oldStr, oldLen, offset);
    485452
    486         if (offset < 0)
    487         {
    488             if (needPrint)
    489             {
     453        if (offset < 0) {
     454            if (needPrint) {
    490455                printLines(num1, num1, FALSE);
    491456                needPrint = FALSE;
     
    507472         * than the old string, then the substitution is easy.
    508473         */
    509         if (deltaLen <= 0)
    510         {
     474        if (deltaLen <= 0) {
    511475            memcpy(&lp->data[offset], newStr, newLen);
    512476
    513             if (deltaLen)
    514             {
     477            if (deltaLen) {
    515478                memcpy(&lp->data[offset + newLen],
    516479                    &lp->data[offset + oldLen],
     
    525488                continue;
    526489
    527             if (needPrint)
    528             {
     490            if (needPrint) {
    529491                printLines(num1, num1, FALSE);
    530492                needPrint = FALSE;
     
    544506        nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen);
    545507
    546         if (nlp == NULL)
    547         {
    548             bb_error_msg("Cannot get memory for line");
    549 
     508        if (nlp == NULL) {
     509            bb_error_msg("cannot get memory for line");
    550510            return;
    551511        }
     
    577537            continue;
    578538
    579         if (needPrint)
    580         {
     539        if (needPrint) {
    581540            printLines(num1, num1, FALSE);
    582541            needPrint = FALSE;
     
    588547
    589548    if (!didSub)
    590         bb_error_msg("No substitutions found for \"%s\"", oldStr);
     549        bb_error_msg("no substitutions found for \"%s\"", oldStr);
    591550}
    592551
     
    604563    left = lp->len - offset;
    605564
    606     while (left >= len)
    607     {
     565    while (left >= len) {
    608566        ncp = memchr(cp, *str, left);
    609567
     
    637595static void addLines(int num)
    638596{
    639     int len;
    640     char    buf[USERSIZE + 1];
    641 
    642     while (fgets(buf, sizeof(buf), stdin))
    643     {
     597    int len;
     598    char buf[USERSIZE + 1];
     599
     600    while (fgets(buf, sizeof(buf), stdin)) {
    644601        if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0'))
    645602            return;
     
    650607            return;
    651608
    652         if (buf[len - 1] != '\n')
    653         {
    654             bb_error_msg("Line too long");
    655 
    656             do
    657             {
     609        if (buf[len - 1] != '\n') {
     610            bb_error_msg("line too long");
     611            do {
    658612                len = fgetc(stdin);
    659             }
    660             while ((len != EOF) && (len != '\n'));
    661 
     613            } while ((len != EOF) && (len != '\n'));
    662614            return;
    663615        }
     
    688640    sign = 1;
    689641
    690     while (TRUE)
    691     {
     642    while (TRUE) {
    692643        while (isblank(*cp))
    693644            cp++;
    694645
    695         switch (*cp)
    696         {
     646        switch (*cp) {
    697647            case '.':
    698648                haveNum = TRUE;
     
    710660                cp++;
    711661
    712                 if ((*cp < 'a') || (*cp > 'z'))
    713                 {
    714                     bb_error_msg("Bad mark name");
    715 
     662                if ((*cp < 'a') || (*cp > 'z')) {
     663                    bb_error_msg("bad mark name");
    716664                    return FALSE;
    717665                }
     
    725673                endStr = strchr(str, '/');
    726674
    727                 if (endStr)
    728                 {
     675                if (endStr) {
    729676                    *endStr++ = '\0';
    730677                    cp += (endStr - str);
     
    742689
    743690            default:
    744                 if (!isdigit(*cp))
    745                 {
     691                if (!isdigit(*cp)) {
    746692                    *retcp = cp;
    747693                    *retHaveNum = haveNum;
    748694                    *retNum = value;
    749 
    750695                    return TRUE;
    751696                }
     
    765710            cp++;
    766711
    767         switch (*cp)
    768         {
     712        switch (*cp) {
    769713            case '-':
    770714                sign = -1;
     
    781725                *retHaveNum = haveNum;
    782726                *retNum = value;
    783 
    784727                return TRUE;
    785728        }
     
    793736static int initEdit(void)
    794737{
    795     int i;
     738    int i;
    796739
    797740    bufSize = INITBUF_SIZE;
    798741    bufBase = malloc(bufSize);
    799742
    800     if (bufBase == NULL)
    801     {
    802         bb_error_msg("No memory for buffer");
    803 
     743    if (bufBase == NULL) {
     744        bb_error_msg("no memory for buffer");
    804745        return FALSE;
    805746    }
     
    860801static int readLines(const char * file, int num)
    861802{
    862     int fd, cc;
     803    int fd, cc;
    863804    int len, lineCount, charCount;
    864805    char *cp;
    865806
    866     if ((num < 1) || (num > lastNum + 1))
    867     {
    868         bb_error_msg("Bad line for read");
    869 
     807    if ((num < 1) || (num > lastNum + 1)) {
     808        bb_error_msg("bad line for read");
    870809        return FALSE;
    871810    }
     
    873812    fd = open(file, 0);
    874813
    875     if (fd < 0)
    876     {
     814    if (fd < 0) {
    877815        perror(file);
    878 
    879816        return FALSE;
    880817    }
     
    889826    fflush(stdout);
    890827
    891     do
    892     {
     828    do {
    893829        cp = memchr(bufPtr, '\n', bufUsed);
    894830
    895         if (cp)
    896         {
     831        if (cp) {
    897832            len = (cp - bufPtr) + 1;
    898833
    899             if (!insertLine(num, bufPtr, len))
    900             {
     834            if (!insertLine(num, bufPtr, len)) {
    901835                close(fd);
    902 
    903836                return FALSE;
    904837            }
     
    913846        }
    914847
    915         if (bufPtr != bufBase)
    916         {
     848        if (bufPtr != bufBase) {
    917849            memcpy(bufBase, bufPtr, bufUsed);
    918850            bufPtr = bufBase + bufUsed;
    919851        }
    920852
    921         if (bufUsed >= bufSize)
    922         {
     853        if (bufUsed >= bufSize) {
    923854            len = (bufSize * 3) / 2;
    924855            cp = realloc(bufBase, len);
    925856
    926             if (cp == NULL)
    927             {
    928                 bb_error_msg("No memory for buffer");
     857            if (cp == NULL) {
     858                bb_error_msg("no memory for buffer");
    929859                close(fd);
    930 
    931860                return FALSE;
    932861            }
     
    941870        bufPtr = bufBase;
    942871
    943     }
    944     while (cc > 0);
    945 
    946     if (cc < 0)
    947     {
     872    } while (cc > 0);
     873
     874    if (cc < 0) {
    948875        perror(file);
    949876        close(fd);
    950 
    951         return FALSE;
    952     }
    953 
    954     if (bufUsed)
    955     {
    956         if (!insertLine(num, bufPtr, bufUsed))
    957         {
     877        return FALSE;
     878    }
     879
     880    if (bufUsed) {
     881        if (!insertLine(num, bufPtr, bufUsed)) {
    958882            close(fd);
    959 
    960883            return -1;
    961884        }
     
    981904{
    982905    LINE *lp;
    983     int fd, lineCount, charCount;
    984 
    985     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
    986     {
    987         bb_error_msg("Bad line range for write");
    988 
     906    int fd, lineCount, charCount;
     907
     908    if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
     909        bb_error_msg("bad line range for write");
    989910        return FALSE;
    990911    }
     
    997918    if (fd < 0) {
    998919        perror(file);
    999 
    1000920        return FALSE;
    1001921    }
     
    1006926    lp = findLine(num1);
    1007927
    1008     if (lp == NULL)
    1009     {
     928    if (lp == NULL) {
    1010929        close(fd);
    1011 
    1012         return FALSE;
    1013     }
    1014 
    1015     while (num1++ <= num2)
    1016     {
    1017         if (write(fd, lp->data, lp->len) != lp->len)
    1018         {
     930        return FALSE;
     931    }
     932
     933    while (num1++ <= num2) {
     934        if (write(fd, lp->data, lp->len) != lp->len) {
    1019935            perror(file);
    1020936            close(fd);
    1021 
    1022937            return FALSE;
    1023938        }
     
    1028943    }
    1029944
    1030     if (close(fd) < 0)
    1031     {
     945    if (close(fd) < 0) {
    1032946        perror(file);
    1033 
    1034947        return FALSE;
    1035948    }
    1036949
    1037950    printf("%d lines, %d chars\n", lineCount, charCount);
    1038 
    1039951    return TRUE;
    1040952}
     
    1053965    int ch, count;
    1054966
    1055     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
    1056     {
    1057         bb_error_msg("Bad line range for print");
    1058 
     967    if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
     968        bb_error_msg("bad line range for print");
    1059969        return FALSE;
    1060970    }
     
    1065975        return FALSE;
    1066976
    1067     while (num1 <= num2)
    1068     {
    1069         if (!expandFlag)
    1070         {
     977    while (num1 <= num2) {
     978        if (!expandFlag) {
    1071979            write(1, lp->data, lp->len);
    1072980            setCurNum(num1++);
     
    1086994            count--;
    1087995
    1088         while (count-- > 0)
    1089         {
     996        while (count-- > 0) {
    1090997            ch = *cp++;
    1091998
    1092             if (ch & 0x80)
    1093             {
     999            if (ch & 0x80) {
    10941000                fputs("M-", stdout);
    10951001                ch &= 0x7f;
    10961002            }
    10971003
    1098             if (ch < ' ')
    1099             {
     1004            if (ch < ' ') {
    11001005                fputc('^', stdout);
    11011006                ch += '@';
    11021007            }
    11031008
    1104             if (ch == 0x7f)
    1105             {
     1009            if (ch == 0x7f) {
    11061010                fputc('^', stdout);
    11071011                ch = '?';
     
    11321036    LINE *newLp, *lp;
    11331037
    1134     if ((num < 1) || (num > lastNum + 1))
    1135     {
    1136         bb_error_msg("Inserting at bad line number");
    1137 
    1138         return FALSE;
    1139     }
    1140 
    1141     newLp = (LINE *) malloc(sizeof(LINE) + len - 1);
    1142 
    1143     if (newLp == NULL)
    1144     {
    1145         bb_error_msg("Failed to allocate memory for line");
    1146 
     1038    if ((num < 1) || (num > lastNum + 1)) {
     1039        bb_error_msg("inserting at bad line number");
     1040        return FALSE;
     1041    }
     1042
     1043    newLp = malloc(sizeof(LINE) + len - 1);
     1044
     1045    if (newLp == NULL) {
     1046        bb_error_msg("failed to allocate memory for line");
    11471047        return FALSE;
    11481048    }
     
    11531053    if (num > lastNum)
    11541054        lp = &lines;
    1155     else
    1156     {
     1055    else {
    11571056        lp = findLine(num);
    11581057
    1159         if (lp == NULL)
    1160         {
     1058        if (lp == NULL) {
    11611059            free((char *) newLp);
    1162 
    11631060            return FALSE;
    11641061        }
     
    11721069    lastNum++;
    11731070    dirty = TRUE;
    1174 
    11751071    return setCurNum(num);
    11761072}
     
    11851081    int count;
    11861082
    1187     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
    1188     {
    1189         bb_error_msg("Bad line numbers for delete");
    1190 
     1083    if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
     1084        bb_error_msg("bad line numbers for delete");
    11911085        return FALSE;
    11921086    }
     
    11971091        return FALSE;
    11981092
    1199     if ((curNum >= num1) && (curNum <= num2))
    1200     {
     1093    if ((curNum >= num1) && (curNum <= num2)) {
    12011094        if (num2 < lastNum)
    12021095            setCurNum(num2 + 1);
     
    12141107    lastNum -= count;
    12151108
    1216     while (count-- > 0)
    1217     {
     1109    while (count-- > 0) {
    12181110        nlp = lp->next;
    12191111        plp = lp->prev;
     
    12451137    int len;
    12461138
    1247     if ((num1 < 1) || (num2 > lastNum) || (num1 > num2))
    1248     {
    1249         bb_error_msg("Bad line numbers for search");
    1250 
     1139    if ((num1 < 1) || (num2 > lastNum) || (num1 > num2)) {
     1140        bb_error_msg("bad line numbers for search");
    12511141        return 0;
    12521142    }
    12531143
    1254     if (*str == '\0')
    1255     {
    1256         if (searchString[0] == '\0')
    1257         {
    1258             bb_error_msg("No previous search string");
    1259 
     1144    if (*str == '\0') {
     1145        if (searchString[0] == '\0') {
     1146            bb_error_msg("no previous search string");
    12601147            return 0;
    12611148        }
     
    12741161        return 0;
    12751162
    1276     while (num1 <= num2)
    1277     {
     1163    while (num1 <= num2) {
    12781164        if (findString(lp, str, len, 0) >= 0)
    12791165            return num1;
     
    12831169    }
    12841170
    1285     bb_error_msg("Cannot find string \"%s\"", str);
    1286 
     1171    bb_error_msg("cannot find string \"%s\"", str);
    12871172    return 0;
    12881173}
     
    12971182    int lnum;
    12981183
    1299     if ((num < 1) || (num > lastNum))
    1300     {
    1301         bb_error_msg("Line number %d does not exist", num);
    1302 
     1184    if ((num < 1) || (num > lastNum)) {
     1185        bb_error_msg("line number %d does not exist", num);
    13031186        return NULL;
    13041187    }
    13051188
    1306     if (curNum <= 0)
    1307     {
     1189    if (curNum <= 0) {
    13081190        curNum = 1;
    13091191        curLine = lines.next;
     
    13161198    lnum = curNum;
    13171199
    1318     if (num < (curNum / 2))
    1319     {
     1200    if (num < (curNum / 2)) {
    13201201        lp = lines.next;
    13211202        lnum = 1;
    13221203    }
    1323     else if (num > ((curNum + lastNum) / 2))
    1324     {
     1204    else if (num > ((curNum + lastNum) / 2)) {
    13251205        lp = lines.prev;
    13261206        lnum = lastNum;
    13271207    }
    13281208
    1329     while (lnum < num)
    1330     {
     1209    while (lnum < num) {
    13311210        lp = lp->next;
    13321211        lnum++;
    13331212    }
    13341213
    1335     while (lnum > num)
    1336     {
     1214    while (lnum > num) {
    13371215        lp = lp->prev;
    13381216        lnum--;
    13391217    }
    1340 
    13411218    return lp;
    13421219}
     
    13581235    curNum = num;
    13591236    curLine = lp;
    1360 
    13611237    return TRUE;
    13621238}
  • branches/2.2.5/mindi-busybox/editors/patch.c

    r821 r1765  
    1616 *  Issues
    1717 *   - Non-interactive
    18  *   - Patches must apply cleanly or the hunk will fail.
     18 *   - Patches must apply cleanly or patch (not just one hunk) will fail.
    1919 *   - Reject file isnt saved
    20  *   -
    2120 */
    2221
    2322#include <getopt.h>
    24 #include <string.h>
    25 #include <stdlib.h>
    26 #include <unistd.h>
    27 #include "busybox.h"
     23
     24#include "libbb.h"
    2825
    2926static unsigned int copy_lines(FILE *src_stream, FILE *dest_stream, const unsigned int lines_count)
     
    3330    while (src_stream && (i < lines_count)) {
    3431        char *line;
    35         line = bb_get_line_from_file(src_stream);
     32        line = xmalloc_fgets(src_stream);
    3633        if (line == NULL) {
    3734            break;
    3835        }
    3936        if (fputs(line, dest_stream) == EOF) {
    40             bb_perror_msg_and_die("Error writing to new file");
     37            bb_perror_msg_and_die("error writing to new file");
    4138        }
    4239        free(line);
     
    4441        i++;
    4542    }
    46     return(i);
     43    return i;
    4744}
    4845
     
    5956
    6057    /* Terminate string at end of source filename */
    61     temp = strchr(filename_start_ptr, '\t');
    62     if (temp) *temp = 0;
    63 
    64     /* skip over (patch_level) number of leading directories */
     58    temp = strchrnul(filename_start_ptr, '\t');
     59    *temp = '\0';
     60
     61    /* Skip over (patch_level) number of leading directories */
     62    if (patch_level == -1)
     63        patch_level = INT_MAX;
    6564    for (i = 0; i < patch_level; i++) {
    66         if(!(temp = strchr(filename_start_ptr, '/'))) break;
     65        temp = strchr(filename_start_ptr, '/');
     66        if (!temp)
     67            break;
    6768        filename_start_ptr = temp + 1;
    6869    }
    6970
    70     return(bb_xstrdup(filename_start_ptr));
     71    return xstrdup(filename_start_ptr);
    7172}
    7273
     
    7475{
    7576    struct stat statbuf;
    76     return(stat(filename, &statbuf));
    77 }
    78 
     77    return stat(filename, &statbuf);
     78}
     79
     80int patch_main(int argc, char **argv);
    7981int patch_main(int argc, char **argv)
    8082{
     
    8688    {
    8789        char *p, *i;
    88         ret = bb_getopt_ulflags(argc, argv, "p:i:", &p, &i);
     90        ret = getopt32(argv, "p:i:", &p, &i);
    8991        if (ret & 1)
    90             patch_level = bb_xgetlarg(p, 10, -1, USHRT_MAX);
     92            patch_level = xatol_range(p, -1, USHRT_MAX);
    9193        if (ret & 2) {
    92             patch_file = bb_xfopen(i, "r");
     94            patch_file = xfopen(i, "r");
    9395        } else {
    9496            patch_file = stdin;
     
    9799    }
    98100
    99     patch_line = bb_get_line_from_file(patch_file);
     101    patch_line = xmalloc_getline(patch_file);
    100102    while (patch_line) {
    101103        FILE *src_stream;
     
    116118        while (patch_line && strncmp(patch_line, "--- ", 4) != 0) {
    117119            free(patch_line);
    118             patch_line = bb_get_line_from_file(patch_file);
    119         }
     120            patch_line = xmalloc_getline(patch_file);
     121        }
     122        /* FIXME: patch_line NULL check?? */
    120123
    121124        /* Extract the filename used before the patch was generated */
     
    123126        free(patch_line);
    124127
    125         patch_line = bb_get_line_from_file(patch_file);
     128        patch_line = xmalloc_getline(patch_file);
     129        /* FIXME: NULL check?? */
    126130        if (strncmp(patch_line, "+++ ", 4) != 0) {
    127131            ret = 2;
    128             bb_error_msg("Invalid patch");
     132            bb_error_msg("invalid patch");
    129133            continue;
    130134        }
     
    141145                *line_ptr = '/';
    142146            }
    143             dst_stream = bb_xfopen(new_filename, "w+");
     147            dst_stream = xfopen(new_filename, "w+");
    144148            backup_filename = NULL;
    145149        } else {
     
    148152            strcat(backup_filename, ".orig");
    149153            if (rename(new_filename, backup_filename) == -1) {
    150                 bb_perror_msg_and_die("Couldnt create file %s",
     154                bb_perror_msg_and_die("cannot create file %s",
    151155                        backup_filename);
    152156            }
    153             dst_stream = bb_xfopen(new_filename, "w");
     157            dst_stream = xfopen(new_filename, "w");
    154158        }
    155159
     
    158162        } else {
    159163            if (strcmp(original_filename, new_filename) == 0) {
    160                 src_stream = bb_xfopen(backup_filename, "r");
     164                src_stream = xfopen(backup_filename, "r");
    161165            } else {
    162                 src_stream = bb_xfopen(original_filename, "r");
     166                src_stream = xfopen(original_filename, "r");
    163167            }
    164168        }
     
    167171
    168172        /* Handle each hunk */
    169         patch_line = bb_get_line_from_file(patch_file);
     173        patch_line = xmalloc_fgets(patch_file);
    170174        while (patch_line) {
    171175            unsigned int count;
     
    190194                count = src_beg_line - src_cur_line;
    191195                if (copy_lines(src_stream, dst_stream, count) != count) {
    192                     bb_error_msg_and_die("Bad src file");
     196                    bb_error_msg_and_die("bad src file");
    193197                }
    194198                src_cur_line += count;
     
    198202            hunk_offset_start = src_cur_line;
    199203
    200             while ((patch_line = bb_get_line_from_file(patch_file)) != NULL) {
     204            while ((patch_line = xmalloc_fgets(patch_file)) != NULL) {
    201205                if ((*patch_line == '-') || (*patch_line == ' ')) {
    202206                    char *src_line = NULL;
    203207                    if (src_stream) {
    204                         src_line = bb_get_line_from_file(src_stream);
     208                        src_line = xmalloc_fgets(src_stream);
    205209                        if (!src_line) {
    206210                            hunk_error++;
     
    210214                        }
    211215                        if (strcmp(src_line, patch_line + 1) != 0) {
    212                             bb_error_msg("Hunk #%d FAILED at %d.", hunk_count, hunk_offset_start);
     216                            bb_error_msg("hunk #%d FAILED at %d", hunk_count, hunk_offset_start);
    213217                            hunk_error++;
    214218                            free(patch_line);
     219                            /* Probably need to find next hunk, etc... */
     220                            /* but for now we just bail out */
     221                            patch_line = NULL;
    215222                            break;
    216223                        }
     
    256263            if ((dest_cur_line == 0) || (dest_beg_line == 0)) {
    257264                /* The new patched file is empty, remove it */
    258                 if (unlink(new_filename) == -1) {
    259                     bb_perror_msg_and_die("Couldnt remove file %s", new_filename);
    260                 }
    261                 if (unlink(original_filename) == -1) {
    262                     bb_perror_msg_and_die("Couldnt remove original file %s", new_filename);
    263                 }
     265                xunlink(new_filename);
     266                if (strcmp(new_filename, original_filename) != 0)
     267                    xunlink(original_filename);
    264268            }
    265269        }
     
    270274     * 2 = More serious problems
    271275     */
    272     return(ret);
    273 }
     276    return ret;
     277}
  • branches/2.2.5/mindi-busybox/editors/sed.c

    r902 r1765  
    1111 * MAINTAINER: Rob Landley <rob@landley.net>
    1212 *
    13  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
     13 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
    1414 */
    1515
     
    2222  the command line).  It calls get_address() and parse_cmd_args().  The
    2323  resulting sed_cmd_t structures are appended to a linked list
    24   (bbg.sed_cmd_head/bbg.sed_cmd_tail).
     24  (G.sed_cmd_head/G.sed_cmd_tail).
    2525
    2626  add_input_file() adds a FILE * to the list of input files.  We need to
     
    5959*/
    6060
    61 #include "busybox.h"
     61#include "libbb.h"
    6262#include "xregex.h"
    6363
    6464/* Each sed command turns into one of these structures. */
    6565typedef struct sed_cmd_s {
    66     /* Ordered by alignment requirements: currently 36 bytes on x86 */
    67 
    68     /* address storage */
    69     regex_t *beg_match; /* sed -e '/match/cmd' */
    70     regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */
    71     regex_t *sub_match; /* For 's/sub_match/string/' */
    72     int beg_line;       /* 'sed 1p'   0 == apply commands to all lines */
    73     int end_line;       /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
    74 
    75     FILE *file;         /* File (sw) command writes to, -1 for none. */
    76     char *string;       /* Data string for (saicytb) commands. */
    77 
    78     unsigned short which_match;     /* (s) Which match to replace (0 for all) */
    79 
    80     /* Bitfields (gcc won't group them if we don't) */
    81     unsigned int invert:1;          /* the '!' after the address */
    82     unsigned int in_match:1;        /* Next line also included in match? */
    83     unsigned int no_newline:1;      /* Last line written by (sw) had no '\n' */
    84     unsigned int sub_p:1;           /* (s) print option */
    85 
    86     /* GENERAL FIELDS */
    87     char cmd;               /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
    88     struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
     66    /* Ordered by alignment requirements: currently 36 bytes on x86 */
     67    struct sed_cmd_s *next; /* Next command (linked list, NULL terminated) */
     68
     69    /* address storage */
     70    regex_t *beg_match;     /* sed -e '/match/cmd' */
     71    regex_t *end_match;     /* sed -e '/match/,/end_match/cmd' */
     72    regex_t *sub_match;     /* For 's/sub_match/string/' */
     73    int beg_line;           /* 'sed 1p'   0 == apply commands to all lines */
     74    int end_line;           /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */
     75
     76    FILE *sw_file;          /* File (sw) command writes to, -1 for none. */
     77    char *string;           /* Data string for (saicytb) commands. */
     78
     79    unsigned short which_match; /* (s) Which match to replace (0 for all) */
     80
     81    /* Bitfields (gcc won't group them if we don't) */
     82    unsigned invert:1;      /* the '!' after the address */
     83    unsigned in_match:1;    /* Next line also included in match? */
     84    unsigned sub_p:1;       /* (s) print option */
     85
     86    char sw_last_char;      /* Last line written by (sw) had no '\n' */
     87
     88    /* GENERAL FIELDS */
     89    char cmd;               /* The command char: abcdDgGhHilnNpPqrstwxy:={} */
    8990} sed_cmd_t;
    9091
    91 static const char *const semicolon_whitespace = "; \n\r\t\v";
    92 
    93 struct sed_globals
    94 {
     92static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v";
     93
     94struct globals {
    9595    /* options */
    96     int be_quiet, in_place, regex_type;
     96    int be_quiet, regex_type;
    9797    FILE *nonstdout;
    9898    char *outname, *hold_space;
    9999
    100100    /* List of input files */
    101     int input_file_count,current_input_file;
     101    int input_file_count, current_input_file;
    102102    FILE **input_file_list;
    103103
    104104    regmatch_t regmatch[10];
    105105    regex_t *previous_regex_ptr;
    106    
     106
    107107    /* linked list of sed commands */
    108108    sed_cmd_t sed_cmd_head, *sed_cmd_tail;
     
    118118        int len;    /* Space allocated */
    119119    } pipeline;
    120 } bbg;
    121 
    122 
    123 void sed_free_and_close_stuff(void);
     120};
     121#define G (*(struct globals*)&bb_common_bufsiz1)
     122void BUG_sed_globals_too_big(void);
     123#define INIT_G() do { \
     124    if (sizeof(struct globals) > COMMON_BUFSIZE) \
     125        BUG_sed_globals_too_big(); \
     126    G.sed_cmd_tail = &G.sed_cmd_head; \
     127} while (0)
     128
     129
    124130#if ENABLE_FEATURE_CLEAN_UP
    125 void sed_free_and_close_stuff(void)
    126 {
    127     sed_cmd_t *sed_cmd = bbg.sed_cmd_head.next;
    128 
    129     llist_free(bbg.append_head, free);
     131static void sed_free_and_close_stuff(void)
     132{
     133    sed_cmd_t *sed_cmd = G.sed_cmd_head.next;
     134
     135    llist_free(G.append_head, free);
    130136
    131137    while (sed_cmd) {
    132138        sed_cmd_t *sed_cmd_next = sed_cmd->next;
    133139
    134         if(sed_cmd->file)
    135             bb_xprint_and_close_file(sed_cmd->file);
     140        if (sed_cmd->sw_file)
     141            xprint_and_close_file(sed_cmd->sw_file);
    136142
    137143        if (sed_cmd->beg_match) {
     
    152158    }
    153159
    154     if(bbg.hold_space) free(bbg.hold_space);
    155 
    156     while(bbg.current_input_file<bbg.input_file_count)
    157         fclose(bbg.input_file_list[bbg.current_input_file++]);
    158 }
     160    if (G.hold_space) free(G.hold_space);
     161
     162    while (G.current_input_file < G.input_file_count)
     163        fclose(G.input_file_list[G.current_input_file++]);
     164}
     165#else
     166void sed_free_and_close_stuff(void);
    159167#endif
    160168
     
    163171static void cleanup_outname(void)
    164172{
    165   if(bbg.outname) unlink(bbg.outname);
     173    if (G.outname) unlink(G.outname);
    166174}
    167175
    168176/* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */
    169177
    170 static void parse_escapes(char *dest, char *string, int len, char from, char to)
    171 {
    172     int i=0;
    173 
    174     while(i<len) {
    175         if(string[i] == '\\') {
    176             if(!to || string[i+1] == from) {
    177                 *(dest++) = to ? to : string[i+1];
    178                 i+=2;
     178static void parse_escapes(char *dest, const char *string, int len, char from, char to)
     179{
     180    int i = 0;
     181
     182    while (i < len) {
     183        if (string[i] == '\\') {
     184            if (!to || string[i+1] == from) {
     185                *dest++ = to ? to : string[i+1];
     186                i += 2;
    179187                continue;
    180             } else *(dest++)=string[i++];
    181         }
    182         *(dest++) = string[i++];
    183     }
    184     *dest=0;
    185 }
    186 
    187 static char *copy_parsing_escapes(char *string, int len)
    188 {
    189     char *dest=xmalloc(len+1);
    190 
    191     parse_escapes(dest,string,len,'n','\n');
     188            }
     189            *dest++ = string[i++];
     190        }
     191        *dest++ = string[i++];
     192    }
     193    *dest = 0;
     194}
     195
     196static char *copy_parsing_escapes(const char *string, int len)
     197{
     198    char *dest = xmalloc(len + 1);
     199
     200    parse_escapes(dest, string, len, 'n', '\n');
    192201    return dest;
    193202}
     
    200209 * a backslash ('\').  A negative delimiter disables square bracket checking.
    201210 */
    202 static int index_of_next_unescaped_regexp_delim(int delimiter, char *str)
     211static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str)
    203212{
    204213    int bracket = -1;
     
    209218    if (delimiter < 0) {
    210219        bracket--;
    211         delimiter *= -1;
     220        delimiter = -delimiter;
    212221    }
    213222
     
    228237
    229238    /* if we make it to here, we've hit the end of the string */
    230     bb_error_msg_and_die("unmatched '%c'",delimiter);
     239    bb_error_msg_and_die("unmatched '%c'", delimiter);
    231240}
    232241
     
    234243 *  Returns the index of the third delimiter
    235244 */
    236 static int parse_regex_delim(char *cmdstr, char **match, char **replace)
    237 {
    238     char *cmdstr_ptr = cmdstr;
     245static int parse_regex_delim(const char *cmdstr, char **match, char **replace)
     246{
     247    const char *cmdstr_ptr = cmdstr;
    239248    char delimiter;
    240249    int idx = 0;
     
    244253    if (*cmdstr == '\0')
    245254        bb_error_msg_and_die("bad format in substitution expression");
    246     delimiter = *(cmdstr_ptr++);
     255    delimiter = *cmdstr_ptr++;
    247256
    248257    /* save the match string */
     
    261270 * returns the index in the string just past where the address ends.
    262271 */
    263 static int get_address(char *my_str, int *linenum, regex_t ** regex)
    264 {
    265     char *pos = my_str;
     272static int get_address(const char *my_str, int *linenum, regex_t ** regex)
     273{
     274    const char *pos = my_str;
    266275
    267276    if (isdigit(*my_str)) {
    268         *linenum = strtol(my_str, &pos, 10);
     277        *linenum = strtol(my_str, (char**)&pos, 10);
    269278        /* endstr shouldnt ever equal NULL */
    270279    } else if (*my_str == '$') {
     
    276285        char *temp;
    277286
    278         if (*my_str == '\\') delimiter = *(++pos);
    279         else delimiter = '/';
     287        delimiter = '/';
     288        if (*my_str == '\\') delimiter = *++pos;
    280289        next = index_of_next_unescaped_regexp_delim(delimiter, ++pos);
    281         temp = copy_parsing_escapes(pos,next);
    282         *regex = (regex_t *) xmalloc(sizeof(regex_t));
    283         xregcomp(*regex, temp, bbg.regex_type|REG_NEWLINE);
     290        temp = copy_parsing_escapes(pos, next);
     291        *regex = xmalloc(sizeof(regex_t));
     292        xregcomp(*regex, temp, G.regex_type|REG_NEWLINE);
    284293        free(temp);
    285294        /* Move position to next character after last delimiter */
     
    290299
    291300/* Grab a filename.  Whitespace at start is skipped, then goes to EOL. */
    292 static int parse_file_cmd(sed_cmd_t *sed_cmd, char *filecmdstr, char **retval)
    293 {
    294     int start = 0, idx, hack=0;
     301static int parse_file_cmd(sed_cmd_t *sed_cmd, const char *filecmdstr, char **retval)
     302{
     303    int start = 0, idx, hack = 0;
    295304
    296305    /* Skip whitespace, then grab filename to end of line */
    297     while (isspace(filecmdstr[start])) start++;
    298     idx=start;
    299     while(filecmdstr[idx] && filecmdstr[idx]!='\n') idx++;
     306    while (isspace(filecmdstr[start]))
     307        start++;
     308    idx = start;
     309    while (filecmdstr[idx] && filecmdstr[idx] != '\n')
     310        idx++;
     311
    300312    /* If lines glued together, put backslash back. */
    301     if(filecmdstr[idx]=='\n') hack=1;
    302     if(idx==start) bb_error_msg_and_die("Empty filename");
    303     *retval = bb_xstrndup(filecmdstr+start, idx-start+hack+1);
    304     if(hack) *(idx+*retval)='\\';
     313    if (filecmdstr[idx] == '\n')
     314        hack = 1;
     315    if (idx == start)
     316        bb_error_msg_and_die("empty filename");
     317    *retval = xstrndup(filecmdstr+start, idx-start+hack+1);
     318    if (hack)
     319        (*retval)[idx] = '\\';
    305320
    306321    return idx;
    307322}
    308323
    309 static int parse_subst_cmd(sed_cmd_t *sed_cmd, char *substr)
    310 {
    311     int cflags = bbg.regex_type;
     324static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr)
     325{
     326    int cflags = G.regex_type;
    312327    char *match;
    313     int idx = 0;
     328    int idx;
    314329
    315330    /*
     
    328343    /* process the flags */
    329344
    330     sed_cmd->which_match=1;
     345    sed_cmd->which_match = 1;
    331346    while (substr[++idx]) {
    332347        /* Parse match number */
    333         if(isdigit(substr[idx])) {
    334             if(match[0]!='^') {
     348        if (isdigit(substr[idx])) {
     349            if (match[0] != '^') {
    335350                /* Match 0 treated as all, multiple matches we take the last one. */
    336                 char *pos=substr+idx;
    337                 sed_cmd->which_match=(unsigned short)strtol(substr+idx,&pos,10);
    338                 idx=pos-substr;
     351                const char *pos = substr + idx;
     352/* FIXME: error check? */
     353                sed_cmd->which_match = (unsigned short)strtol(substr+idx, (char**) &pos, 10);
     354                idx = pos - substr;
    339355            }
    340356            continue;
    341357        }
    342358        /* Skip spaces */
    343         if(isspace(substr[idx])) continue;
     359        if (isspace(substr[idx])) continue;
    344360
    345361        switch (substr[idx]) {
    346             /* Replace all occurrences */
    347             case 'g':
    348                 if (match[0] != '^') sed_cmd->which_match = 0;
    349                 break;
    350             /* Print pattern space */
    351             case 'p':
    352                 sed_cmd->sub_p = 1;
    353                 break;
    354             /* Write to file */
    355             case 'w':
    356             {
    357                 char *temp;
    358                 idx+=parse_file_cmd(sed_cmd,substr+idx,&temp);
    359 
    360                 break;
    361             }
    362             /* Ignore case (gnu exension) */
    363             case 'I':
    364                 cflags |= REG_ICASE;
    365                 break;
    366             /* Comment */
    367             case '#':
    368                 while(substr[++idx]);
    369                 /* Fall through */
    370             /* End of command */
    371             case ';':
    372             case '}':
    373                 goto out;
    374             default:
    375                 bb_error_msg_and_die("bad option in substitution expression");
     362        /* Replace all occurrences */
     363        case 'g':
     364            if (match[0] != '^') sed_cmd->which_match = 0;
     365            break;
     366        /* Print pattern space */
     367        case 'p':
     368            sed_cmd->sub_p = 1;
     369            break;
     370        /* Write to file */
     371        case 'w':
     372        {
     373            char *temp;
     374            idx += parse_file_cmd(sed_cmd, substr+idx, &temp);
     375            break;
     376        }
     377        /* Ignore case (gnu exension) */
     378        case 'I':
     379            cflags |= REG_ICASE;
     380            break;
     381        /* Comment */
     382        case '#':
     383            while (substr[++idx]) /*skip all*/;
     384            /* Fall through */
     385        /* End of command */
     386        case ';':
     387        case '}':
     388            goto out;
     389        default:
     390            bb_error_msg_and_die("bad option in substitution expression");
    376391        }
    377392    }
     
    380395    if (*match != '\0') {
    381396        /* If match is empty, we use last regex used at runtime */
    382         sed_cmd->sub_match = (regex_t *) xmalloc(sizeof(regex_t));
     397        sed_cmd->sub_match = xmalloc(sizeof(regex_t));
    383398        xregcomp(sed_cmd->sub_match, match, cflags);
    384399    }
     
    391406 *  Process the commands arguments
    392407 */
    393 static char *parse_cmd_args(sed_cmd_t *sed_cmd, char *cmdstr)
     408static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr)
    394409{
    395410    /* handle (s)ubstitution command */
    396     if (sed_cmd->cmd == 's') cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
     411    if (sed_cmd->cmd == 's')
     412        cmdstr += parse_subst_cmd(sed_cmd, cmdstr);
    397413    /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */
    398414    else if (strchr("aic", sed_cmd->cmd)) {
     
    400416            bb_error_msg_and_die
    401417                ("only a beginning address can be specified for edit commands");
    402         for(;;) {
    403             if(*cmdstr=='\n' || *cmdstr=='\\') {
     418        for (;;) {
     419            if (*cmdstr == '\n' || *cmdstr == '\\') {
    404420                cmdstr++;
    405421                break;
    406             } else if(isspace(*cmdstr)) cmdstr++;
    407             else break;
    408         }
    409         sed_cmd->string = bb_xstrdup(cmdstr);
    410         parse_escapes(sed_cmd->string,sed_cmd->string,strlen(cmdstr),0,0);
     422            } else if (isspace(*cmdstr))
     423                cmdstr++;
     424            else
     425                break;
     426        }
     427        sed_cmd->string = xstrdup(cmdstr);
     428        parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), 0, 0);
    411429        cmdstr += strlen(cmdstr);
    412430    /* handle file cmds: (r)ead */
    413     } else if(strchr("rw", sed_cmd->cmd)) {
     431    } else if (strchr("rw", sed_cmd->cmd)) {
    414432        if (sed_cmd->end_line || sed_cmd->end_match)
    415             bb_error_msg_and_die("Command only uses one address");
     433            bb_error_msg_and_die("command only uses one address");
    416434        cmdstr += parse_file_cmd(sed_cmd, cmdstr, &sed_cmd->string);
    417         if(sed_cmd->cmd=='w')
    418             sed_cmd->file=bb_xfopen(sed_cmd->string,"w");
     435        if (sed_cmd->cmd == 'w') {
     436            sed_cmd->sw_file = xfopen(sed_cmd->string, "w");
     437            sed_cmd->sw_last_char = '\n';
     438        }
    419439    /* handle branch commands */
    420440    } else if (strchr(":btT", sed_cmd->cmd)) {
    421441        int length;
    422442
    423         while(isspace(*cmdstr)) cmdstr++;
     443        cmdstr = skip_whitespace(cmdstr);
    424444        length = strcspn(cmdstr, semicolon_whitespace);
    425445        if (length) {
    426             sed_cmd->string = bb_xstrndup(cmdstr, length);
     446            sed_cmd->string = xstrndup(cmdstr, length);
    427447            cmdstr += length;
    428448        }
     
    431451    else if (sed_cmd->cmd == 'y') {
    432452        char *match, *replace;
    433         int i=cmdstr[0];
    434 
    435         cmdstr+=parse_regex_delim(cmdstr, &match, &replace)+1;
     453        int i = cmdstr[0];
     454
     455        cmdstr += parse_regex_delim(cmdstr, &match, &replace)+1;
    436456        /* \n already parsed, but \delimiter needs unescaping. */
    437         parse_escapes(match,match,strlen(match),i,i);
    438         parse_escapes(replace,replace,strlen(replace),i,i);
     457        parse_escapes(match, match, strlen(match), i, i);
     458        parse_escapes(replace, replace, strlen(replace), i, i);
    439459
    440460        sed_cmd->string = xzalloc((strlen(match) + 1) * 2);
    441461        for (i = 0; match[i] && replace[i]; i++) {
    442             sed_cmd->string[i * 2] = match[i];
    443             sed_cmd->string[(i * 2) + 1] = replace[i];
     462            sed_cmd->string[i*2] = match[i];
     463            sed_cmd->string[i*2+1] = replace[i];
    444464        }
    445465        free(match);
     
    450470     */
    451471    else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) {
    452         bb_error_msg_and_die("Unsupported command %c", sed_cmd->cmd);
     472        bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd);
    453473    }
    454474
    455475    /* give back whatever's left over */
    456     return (cmdstr);
     476    return cmdstr;
    457477}
    458478
     
    460480/* Parse address+command sets, skipping comment lines. */
    461481
    462 static void add_cmd(char *cmdstr)
     482static void add_cmd(const char *cmdstr)
    463483{
    464484    sed_cmd_t *sed_cmd;
     
    466486
    467487    /* Append this line to any unfinished line from last time. */
    468     if (bbg.add_cmd_line) {
    469         cmdstr = bb_xasprintf("%s\n%s", bbg.add_cmd_line, cmdstr);
    470         free(bbg.add_cmd_line);
    471         bbg.add_cmd_line = cmdstr;
     488    if (G.add_cmd_line) {
     489        char *tp = xasprintf("%s\n%s", G.add_cmd_line, cmdstr);
     490        free(G.add_cmd_line);
     491        cmdstr = G.add_cmd_line = tp;
    472492    }
    473493
    474494    /* If this line ends with backslash, request next line. */
    475     temp=strlen(cmdstr);
    476     if(temp && cmdstr[temp-1]=='\\') {
    477         if (!bbg.add_cmd_line) bbg.add_cmd_line = bb_xstrdup(cmdstr);
    478         bbg.add_cmd_line[temp-1] = 0;
     495    temp = strlen(cmdstr);
     496    if (temp && cmdstr[--temp] == '\\') {
     497        if (!G.add_cmd_line)
     498            G.add_cmd_line = xstrdup(cmdstr);
     499        G.add_cmd_line[temp] = '\0';
    479500        return;
    480501    }
    481502
    482503    /* Loop parsing all commands in this line. */
    483     while(*cmdstr) {
     504    while (*cmdstr) {
    484505        /* Skip leading whitespace and semicolons */
    485506        cmdstr += strspn(cmdstr, semicolon_whitespace);
    486507
    487508        /* If no more commands, exit. */
    488         if(!*cmdstr) break;
     509        if (!*cmdstr) break;
    489510
    490511        /* if this is a comment, jump past it and keep going */
    491512        if (*cmdstr == '#') {
    492513            /* "#n" is the same as using -n on the command line */
    493             if (cmdstr[1] == 'n') bbg.be_quiet++;
    494             if(!(cmdstr=strpbrk(cmdstr, "\n\r"))) break;
     514            if (cmdstr[1] == 'n')
     515                G.be_quiet++;
     516            cmdstr = strpbrk(cmdstr, "\n\r");
     517            if (!cmdstr) break;
    495518            continue;
    496519        }
     
    513536            cmdstr++;
    514537            idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match);
    515             if (!idx) bb_error_msg_and_die("no address after comma\n");
     538            if (!idx)
     539                bb_error_msg_and_die("no address after comma");
    516540            cmdstr += idx;
    517541        }
    518542
    519543        /* skip whitespace before the command */
    520         while (isspace(*cmdstr)) cmdstr++;
     544        cmdstr = skip_whitespace(cmdstr);
    521545
    522546        /* Check for inversion flag */
     
    526550
    527551            /* skip whitespace before the command */
    528             while (isspace(*cmdstr)) cmdstr++;
     552            cmdstr = skip_whitespace(cmdstr);
    529553        }
    530554
    531555        /* last part (mandatory) will be a command */
    532         if (!*cmdstr) bb_error_msg_and_die("missing command");
     556        if (!*cmdstr)
     557            bb_error_msg_and_die("missing command");
    533558        sed_cmd->cmd = *(cmdstr++);
    534559        cmdstr = parse_cmd_args(sed_cmd, cmdstr);
    535560
    536561        /* Add the command to the command array */
    537         bbg.sed_cmd_tail->next = sed_cmd;
    538         bbg.sed_cmd_tail = bbg.sed_cmd_tail->next;
     562        G.sed_cmd_tail->next = sed_cmd;
     563        G.sed_cmd_tail = G.sed_cmd_tail->next;
    539564    }
    540565
    541566    /* If we glued multiple lines together, free the memory. */
    542     free(bbg.add_cmd_line);
    543     bbg.add_cmd_line = NULL;
     567    free(G.add_cmd_line);
     568    G.add_cmd_line = NULL;
    544569}
    545570
     
    550575static void pipe_putc(char c)
    551576{
    552     if(bbg.pipeline.idx==bbg.pipeline.len) {
    553         bbg.pipeline.buf = xrealloc(bbg.pipeline.buf,
    554                                 bbg.pipeline.len + PIPE_GROW);
    555         bbg.pipeline.len+=PIPE_GROW;
    556     }
    557     bbg.pipeline.buf[bbg.pipeline.idx++] = c;
     577    if (G.pipeline.idx == G.pipeline.len) {
     578        G.pipeline.buf = xrealloc(G.pipeline.buf,
     579                G.pipeline.len + PIPE_GROW);
     580        G.pipeline.len += PIPE_GROW;
     581    }
     582    G.pipeline.buf[G.pipeline.idx++] = c;
    558583}
    559584
     
    565590    for (i = 0; replace[i]; i++) {
    566591        /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */
    567         if (replace[i] == '\\' && replace[i+1]>='0' && replace[i+1]<='9') {
    568             int backref=replace[++i]-'0';
    569 
    570             /* print out the text held in bbg.regmatch[backref] */
    571             if(bbg.regmatch[backref].rm_so != -1)
    572                 for (j = bbg.regmatch[backref].rm_so;
    573                     j < bbg.regmatch[backref].rm_eo; j++) pipe_putc(line[j]);
    574         }
    575 
    576         /* if we find a backslash escaped character, print the character */
    577         else if (replace[i] == '\\') pipe_putc(replace[++i]);
    578 
     592        if (replace[i] == '\\') {
     593            unsigned backref = replace[++i] - '0';
     594            if (backref <= 9) {
     595                /* print out the text held in G.regmatch[backref] */
     596                if (G.regmatch[backref].rm_so != -1) {
     597                    j = G.regmatch[backref].rm_so;
     598                    while (j < G.regmatch[backref].rm_eo)
     599                        pipe_putc(line[j++]);
     600                }
     601                continue;
     602            }
     603            /* I _think_ it is impossible to get '\' to be
     604             * the last char in replace string. Thus we dont check
     605             * for replace[i] == NUL. (counterexample anyone?) */
     606            /* if we find a backslash escaped character, print the character */
     607            pipe_putc(replace[i]);
     608            continue;
     609        }
    579610        /* if we find an unescaped '&' print out the whole matched text. */
    580         else if (replace[i] == '&')
    581             for (j = bbg.regmatch[0].rm_so; j < bbg.regmatch[0].rm_eo; j++)
    582                 pipe_putc(line[j]);
     611        if (replace[i] == '&') {
     612            j = G.regmatch[0].rm_so;
     613            while (j < G.regmatch[0].rm_eo)
     614                pipe_putc(line[j++]);
     615            continue;
     616        }
    583617        /* Otherwise just output the character. */
    584         else pipe_putc(replace[i]);
     618        pipe_putc(replace[i]);
    585619    }
    586620}
     
    590624    char *oldline = *line;
    591625    int altered = 0;
    592     int match_count=0;
     626    int match_count = 0;
    593627    regex_t *current_regex;
    594628
    595629    /* Handle empty regex. */
    596630    if (sed_cmd->sub_match == NULL) {
    597         current_regex = bbg.previous_regex_ptr;
    598         if(!current_regex)
    599             bb_error_msg_and_die("No previous regexp.");
    600     } else bbg.previous_regex_ptr = current_regex = sed_cmd->sub_match;
     631        current_regex = G.previous_regex_ptr;
     632        if (!current_regex)
     633            bb_error_msg_and_die("no previous regexp");
     634    } else
     635        G.previous_regex_ptr = current_regex = sed_cmd->sub_match;
    601636
    602637    /* Find the first match */
    603     if(REG_NOMATCH==regexec(current_regex, oldline, 10, bbg.regmatch, 0))
     638    if (REG_NOMATCH == regexec(current_regex, oldline, 10, G.regmatch, 0))
    604639        return 0;
    605640
    606641    /* Initialize temporary output buffer. */
    607     bbg.pipeline.buf=xmalloc(PIPE_GROW);
    608     bbg.pipeline.len=PIPE_GROW;
    609     bbg.pipeline.idx=0;
     642    G.pipeline.buf = xmalloc(PIPE_GROW);
     643    G.pipeline.len = PIPE_GROW;
     644    G.pipeline.idx = 0;
    610645
    611646    /* Now loop through, substituting for matches */
     
    617652           The match_count check is so not to break
    618653           echo "hi" | busybox sed 's/^/!/g' */
    619         if(!bbg.regmatch[0].rm_so && !bbg.regmatch[0].rm_eo && match_count) {
    620             pipe_putc(*(oldline++));
     654        if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) {
     655            pipe_putc(*oldline++);
    621656            continue;
    622657        }
     
    626661        /* If we aren't interested in this match, output old line to
    627662           end of match and continue */
    628         if(sed_cmd->which_match && sed_cmd->which_match!=match_count) {
    629             for(i=0;i<bbg.regmatch[0].rm_eo;i++)
    630                 pipe_putc(*(oldline++));
     663        if (sed_cmd->which_match && sed_cmd->which_match != match_count) {
     664            for (i = 0; i < G.regmatch[0].rm_eo; i++)
     665                pipe_putc(*oldline++);
    631666            continue;
    632667        }
    633668
    634669        /* print everything before the match */
    635         for (i = 0; i < bbg.regmatch[0].rm_so; i++) pipe_putc(oldline[i]);
     670        for (i = 0; i < G.regmatch[0].rm_so; i++)
     671            pipe_putc(oldline[i]);
    636672
    637673        /* then print the substitution string */
     
    639675
    640676        /* advance past the match */
    641         oldline += bbg.regmatch[0].rm_eo;
     677        oldline += G.regmatch[0].rm_eo;
    642678        /* flag that something has changed */
    643679        altered++;
     
    645681        /* if we're not doing this globally, get out now */
    646682        if (sed_cmd->which_match) break;
    647     } while (*oldline && (regexec(current_regex, oldline, 10, bbg.regmatch, 0) != REG_NOMATCH));
     683    } while (*oldline && (regexec(current_regex, oldline, 10, G.regmatch, 0) != REG_NOMATCH));
    648684
    649685    /* Copy rest of string into output pipeline */
    650686
    651     while(*oldline) pipe_putc(*(oldline++));
     687    while (*oldline)
     688        pipe_putc(*oldline++);
    652689    pipe_putc(0);
    653690
    654691    free(*line);
    655     *line = bbg.pipeline.buf;
     692    *line = G.pipeline.buf;
    656693    return altered;
    657694}
     
    662699    sed_cmd_t *sed_cmd;
    663700
    664     for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
    665         if ((sed_cmd->cmd == ':') && (sed_cmd->string) && (strcmp(sed_cmd->string, label) == 0)) {
    666             return (sed_cmd);
    667         }
    668     }
    669     bb_error_msg_and_die("Can't find label for jump to `%s'", label);
     701    for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     702        if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) {
     703            return sed_cmd;
     704        }
     705    }
     706    bb_error_msg_and_die("can't find label for jump to '%s'", label);
    670707}
    671708
    672709static void append(char *s)
    673710{
    674     llist_add_to_end(&bbg.append_head, bb_xstrdup(s));
     711    llist_add_to_end(&G.append_head, xstrdup(s));
    675712}
    676713
     
    680717
    681718    /* Output appended lines. */
    682     while((data = (char *)llist_pop(&bbg.append_head))) {
    683         fprintf(bbg.nonstdout,"%s\n",data);
     719    while ((data = (char *)llist_pop(&G.append_head))) {
     720        fprintf(G.nonstdout, "%s\n", data);
    684721        free(data);
    685722    }
     
    688725static void add_input_file(FILE *file)
    689726{
    690     bbg.input_file_list=xrealloc(bbg.input_file_list,
    691             (bbg.input_file_count + 1) * sizeof(FILE *));
    692     bbg.input_file_list[bbg.input_file_count++] = file;
    693 }
    694 
    695 /* Get next line of input from bbg.input_file_list, flushing append buffer and
     727    G.input_file_list = xrealloc(G.input_file_list,
     728            (G.input_file_count + 1) * sizeof(FILE *));
     729    G.input_file_list[G.input_file_count++] = file;
     730}
     731
     732/* Get next line of input from G.input_file_list, flushing append buffer and
    696733 * noting if we ran out of files without a newline on the last line we read.
    697734 */
    698 static char *get_next_line(int *no_newline)
    699 {
    700     char *temp=NULL;
     735enum {
     736    NO_EOL_CHAR = 1,
     737    LAST_IS_NUL = 2,
     738};
     739static char *get_next_line(char *gets_char)
     740{
     741    char *temp = NULL;
    701742    int len;
     743    char gc;
    702744
    703745    flush_append();
    704     while (bbg.current_input_file<bbg.input_file_count) {
    705         temp = bb_get_chunk_from_file(bbg.input_file_list[bbg.current_input_file],&len);
     746
     747    /* will be returned if last line in the file
     748     * doesn't end with either '\n' or '\0' */
     749    gc = NO_EOL_CHAR;
     750    while (G.current_input_file < G.input_file_count) {
     751        FILE *fp = G.input_file_list[G.current_input_file];
     752        /* Read line up to a newline or NUL byte, inclusive,
     753         * return malloc'ed char[]. length of the chunk read
     754         * is stored in len. NULL if EOF/error */
     755        temp = bb_get_chunk_from_file(fp, &len);
    706756        if (temp) {
    707             *no_newline = !(len && temp[len-1]=='\n');
    708             if (!*no_newline) temp[len-1] = 0;
     757            /* len > 0 here, it's ok to do temp[len-1] */
     758            char c = temp[len-1];
     759            if (c == '\n' || c == '\0') {
     760                temp[len-1] = '\0';
     761                gc = c;
     762                if (c == '\0') {
     763                    int ch = fgetc(fp);
     764                    if (ch != EOF)
     765                        ungetc(ch, fp);
     766                    else
     767                        gc = LAST_IS_NUL;
     768                }
     769            }
     770            /* else we put NO_EOL_CHAR into *gets_char */
    709771            break;
    710         // Close this file and advance to next one
    711         } else fclose(bbg.input_file_list[bbg.current_input_file++]);
    712     }
    713 
     772
     773        /* NB: I had the idea of peeking next file(s) and returning
     774         * NO_EOL_CHAR only if it is the *last* non-empty
     775         * input file. But there is a case where this won't work:
     776         * file1: "a woo\nb woo"
     777         * file2: "c no\nd no"
     778         * sed -ne 's/woo/bang/p' input1 input2 => "a bang\nb bang"
     779         * (note: *no* newline after "b bang"!) */
     780        }
     781        /* Close this file and advance to next one */
     782        fclose(fp);
     783        G.current_input_file++;
     784    }
     785    *gets_char = gc;
    714786    return temp;
    715787}
    716788
    717 /* Output line of text.  missing_newline means the last line output did not
    718    end with a newline.  no_newline means this line does not end with a
    719    newline. */
    720 
    721 static int puts_maybe_newline(char *s, FILE *file, int missing_newline, int no_newline)
    722 {
    723     if(missing_newline) fputc('\n',file);
    724     fputs(s,file);
    725     if(!no_newline) fputc('\n',file);
    726 
    727     if(ferror(file)) {
    728         bb_default_error_retval = 4;  /* It's what gnu sed exits with... */
     789/* Output line of text. */
     790/* Note:
     791 * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed.
     792 * Without them, we had this:
     793 * echo -n thingy >z1
     794 * echo -n again >z2
     795 * >znull
     796 * sed "s/i/z/" z1 z2 znull | hexdump -vC
     797 * output:
     798 * gnu sed 4.1.5:
     799 * 00000000  74 68 7a 6e 67 79 0a 61  67 61 7a 6e              |thzngy.agazn|
     800 * bbox:
     801 * 00000000  74 68 7a 6e 67 79 61 67  61 7a 6e                 |thzngyagazn|
     802 */
     803static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char)
     804{
     805    char lpc = *last_puts_char;
     806
     807    /* Need to insert a '\n' between two files because first file's
     808     * last line wasn't terminated? */
     809    if (lpc != '\n' && lpc != '\0') {
     810        fputc('\n', file);
     811        lpc = '\n';
     812    }
     813    fputs(s, file);
     814
     815    /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */
     816    if (s[0])
     817        lpc = 'x';
     818
     819    /* had trailing '\0' and it was last char of file? */
     820    if (last_gets_char == LAST_IS_NUL) {
     821        fputc('\0', file);
     822        lpc = 'x'; /* */
     823    } else
     824    /* had trailing '\n' or '\0'? */
     825    if (last_gets_char != NO_EOL_CHAR) {
     826        fputc(last_gets_char, file);
     827        lpc = last_gets_char;
     828    }
     829
     830    if (ferror(file)) {
     831        xfunc_error_retval = 4;  /* It's what gnu sed exits with... */
    729832        bb_error_msg_and_die(bb_msg_write_error);
    730833    }
    731 
    732     return no_newline;
    733 }
    734 
    735 #define sed_puts(s,n) missing_newline=puts_maybe_newline(s,bbg.nonstdout,missing_newline,n)
     834    *last_puts_char = lpc;
     835}
     836
     837#define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n))
     838
     839static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space)
     840{
     841    int retval = sed_cmd->beg_match && !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0);
     842    if (retval)
     843        G.previous_regex_ptr = sed_cmd->beg_match;
     844    return retval;
     845}
    736846
    737847/* Process all the lines in all the files */
     
    740850{
    741851    char *pattern_space, *next_line;
    742     int linenum = 0, missing_newline=0;
    743     int no_newline,next_no_newline=0;
     852    int linenum = 0;
     853    char last_puts_char = '\n';
     854    char last_gets_char, next_gets_char;
     855    sed_cmd_t *sed_cmd;
     856    int substituted;
    744857
    745858    /* Prime the pump */
    746     next_line = get_next_line(&next_no_newline);
     859    next_line = get_next_line(&next_gets_char);
    747860
    748861    /* go through every line in each file */
    749     for(;;) {
    750         sed_cmd_t *sed_cmd;
    751         int substituted=0;
    752 
    753         /* Advance to next line.  Stop if out of lines. */
    754         if(!(pattern_space=next_line)) break;
    755         no_newline=next_no_newline;
    756 
    757         /* Read one line in advance so we can act on the last line,
    758         * the '$' address */
    759         next_line = get_next_line(&next_no_newline);
    760         linenum++;
     862again:
     863    substituted = 0;
     864
     865    /* Advance to next line.  Stop if out of lines. */
     866    pattern_space = next_line;
     867    if (!pattern_space) return;
     868    last_gets_char = next_gets_char;
     869
     870    /* Read one line in advance so we can act on the last line,
     871    * the '$' address */
     872    next_line = get_next_line(&next_gets_char);
     873    linenum++;
    761874restart:
    762         /* for every line, go through all the commands */
    763         for (sed_cmd = bbg.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next)
    764         {
    765             int old_matched, matched;
    766 
    767             old_matched = sed_cmd->in_match;
    768 
    769             /* Determine if this command matches this line: */
    770 
    771             /* Are we continuing a previous multi-line match? */
    772 
    773             sed_cmd->in_match = sed_cmd->in_match
    774 
     875    /* for every line, go through all the commands */
     876    for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) {
     877        int old_matched, matched;
     878
     879        old_matched = sed_cmd->in_match;
     880
     881        /* Determine if this command matches this line: */
     882
     883        /* Are we continuing a previous multi-line match? */
     884        sed_cmd->in_match = sed_cmd->in_match
    775885            /* Or is no range necessary? */
    776                 || (!sed_cmd->beg_line && !sed_cmd->end_line
    777                     && !sed_cmd->beg_match && !sed_cmd->end_match)
    778 
     886            || (!sed_cmd->beg_line && !sed_cmd->end_line
     887                && !sed_cmd->beg_match && !sed_cmd->end_match)
    779888            /* Or did we match the start of a numerical range? */
    780                 || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
    781 
     889            || (sed_cmd->beg_line > 0 && (sed_cmd->beg_line == linenum))
    782890            /* Or does this line match our begin address regex? */
    783                     || (sed_cmd->beg_match &&
    784                     !regexec(sed_cmd->beg_match, pattern_space, 0, NULL, 0))
    785 
     891            || (beg_match(sed_cmd, pattern_space))
    786892            /* Or did we match last line of input? */
    787                 || (sed_cmd->beg_line == -1 && next_line == NULL);
    788 
    789             /* Snapshot the value */
    790 
    791             matched = sed_cmd->in_match;
    792 
    793             /* Is this line the end of the current match? */
    794 
    795             if(matched) {
    796                 sed_cmd->in_match = !(
    797                     /* has the ending line come, or is this a single address command? */
    798                     (sed_cmd->end_line ?
    799                         sed_cmd->end_line==-1 ?
    800                             !next_line
    801                             : sed_cmd->end_line<=linenum
    802                         : !sed_cmd->end_match)
    803                     /* or does this line matches our last address regex */
    804                     || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, pattern_space, 0, NULL, 0) == 0))
    805                 );
    806             }
    807 
    808             /* Skip blocks of commands we didn't match. */
    809             if (sed_cmd->cmd == '{') {
    810                 if(sed_cmd->invert ? matched : !matched)
    811                     while(sed_cmd && sed_cmd->cmd!='}') sed_cmd=sed_cmd->next;
    812                 if(!sed_cmd) bb_error_msg_and_die("Unterminated {");
    813                 continue;
    814             }
    815 
    816             /* Okay, so did this line match? */
    817             if (sed_cmd->invert ? !matched : matched) {
    818                 /* Update last used regex in case a blank substitute BRE is found */
    819                 if (sed_cmd->beg_match) {
    820                     bbg.previous_regex_ptr = sed_cmd->beg_match;
     893            || (sed_cmd->beg_line == -1 && next_line == NULL);
     894
     895        /* Snapshot the value */
     896
     897        matched = sed_cmd->in_match;
     898
     899        /* Is this line the end of the current match? */
     900
     901        if (matched) {
     902            sed_cmd->in_match = !(
     903                /* has the ending line come, or is this a single address command? */
     904                (sed_cmd->end_line ?
     905                    sed_cmd->end_line == -1 ?
     906                        !next_line
     907                        : (sed_cmd->end_line <= linenum)
     908                    : !sed_cmd->end_match
     909                )
     910                /* or does this line matches our last address regex */
     911                || (sed_cmd->end_match && old_matched
     912                     && (regexec(sed_cmd->end_match,
     913                                 pattern_space, 0, NULL, 0) == 0))
     914            );
     915        }
     916
     917        /* Skip blocks of commands we didn't match. */
     918        if (sed_cmd->cmd == '{') {
     919            if (sed_cmd->invert ? matched : !matched) {
     920                while (sed_cmd->cmd != '}') {
     921                    sed_cmd = sed_cmd->next;
     922                    if (!sed_cmd)
     923                        bb_error_msg_and_die("unterminated {");
    821924                }
    822 
    823                 /* actual sedding */
    824                 switch (sed_cmd->cmd) {
    825 
    826                     /* Print line number */
    827                     case '=':
    828                         fprintf(bbg.nonstdout,"%d\n", linenum);
    829                         break;
    830 
    831                     /* Write the current pattern space up to the first newline */
    832                     case 'P':
    833                     {
    834                         char *tmp = strchr(pattern_space, '\n');
    835 
    836                         if (tmp) {
    837                             *tmp = '\0';
    838                             sed_puts(pattern_space,1);
    839                             *tmp = '\n';
     925            }
     926            continue;
     927        }
     928
     929        /* Okay, so did this line match? */
     930        if (sed_cmd->invert ? !matched : matched) {
     931            /* Update last used regex in case a blank substitute BRE is found */
     932            if (sed_cmd->beg_match) {
     933                G.previous_regex_ptr = sed_cmd->beg_match;
     934            }
     935
     936            /* actual sedding */
     937            switch (sed_cmd->cmd) {
     938
     939            /* Print line number */
     940            case '=':
     941                fprintf(G.nonstdout, "%d\n", linenum);
     942                break;
     943
     944            /* Write the current pattern space up to the first newline */
     945            case 'P':
     946            {
     947                char *tmp = strchr(pattern_space, '\n');
     948
     949                if (tmp) {
     950                    *tmp = '\0';
     951                    /* TODO: explain why '\n' below */
     952                    sed_puts(pattern_space, '\n');
     953                    *tmp = '\n';
     954                    break;
     955                }
     956                /* Fall Through */
     957            }
     958
     959            /* Write the current pattern space to output */
     960            case 'p':
     961                /* NB: we print this _before_ the last line
     962                 * (of current file) is printed. Even if
     963                 * that line is nonterminated, we print
     964                 * '\n' here (gnu sed does the same) */
     965                sed_puts(pattern_space, '\n');
     966                break;
     967            /* Delete up through first newline */
     968            case 'D':
     969            {
     970                char *tmp = strchr(pattern_space, '\n');
     971
     972                if (tmp) {
     973                    tmp = xstrdup(tmp+1);
     974                    free(pattern_space);
     975                    pattern_space = tmp;
     976                    goto restart;
     977                }
     978            }
     979            /* discard this line. */
     980            case 'd':
     981                goto discard_line;
     982
     983            /* Substitute with regex */
     984            case 's':
     985                if (!do_subst_command(sed_cmd, &pattern_space))
     986                    break;
     987                substituted |= 1;
     988
     989                /* handle p option */
     990                if (sed_cmd->sub_p)
     991                    sed_puts(pattern_space, last_gets_char);
     992                /* handle w option */
     993                if (sed_cmd->sw_file)
     994                    puts_maybe_newline(
     995                        pattern_space, sed_cmd->sw_file,
     996                        &sed_cmd->sw_last_char, last_gets_char);
     997                break;
     998
     999            /* Append line to linked list to be printed later */
     1000            case 'a':
     1001                append(sed_cmd->string);
     1002                break;
     1003
     1004            /* Insert text before this line */
     1005            case 'i':
     1006                sed_puts(sed_cmd->string, '\n');
     1007                break;
     1008
     1009            /* Cut and paste text (replace) */
     1010            case 'c':
     1011                /* Only triggers on last line of a matching range. */
     1012                if (!sed_cmd->in_match)
     1013                    sed_puts(sed_cmd->string, NO_EOL_CHAR);
     1014                goto discard_line;
     1015
     1016            /* Read file, append contents to output */
     1017            case 'r':
     1018            {
     1019                FILE *rfile;
     1020
     1021                rfile = fopen(sed_cmd->string, "r");
     1022                if (rfile) {
     1023                    char *line;
     1024
     1025                    while ((line = xmalloc_getline(rfile))
     1026                            != NULL)
     1027                        append(line);
     1028                    xprint_and_close_file(rfile);
     1029                }
     1030
     1031                break;
     1032            }
     1033
     1034            /* Write pattern space to file. */
     1035            case 'w':
     1036                puts_maybe_newline(
     1037                    pattern_space, sed_cmd->sw_file,
     1038                    &sed_cmd->sw_last_char, last_gets_char);
     1039                break;
     1040
     1041            /* Read next line from input */
     1042            case 'n':
     1043                if (!G.be_quiet)
     1044                    sed_puts(pattern_space, last_gets_char);
     1045                if (next_line) {
     1046                    free(pattern_space);
     1047                    pattern_space = next_line;
     1048                    last_gets_char = next_gets_char;
     1049                    next_line = get_next_line(&next_gets_char);
     1050                    linenum++;
     1051                    break;
     1052                }
     1053                /* fall through */
     1054
     1055            /* Quit.  End of script, end of input. */
     1056            case 'q':
     1057                /* Exit the outer while loop */
     1058                free(next_line);
     1059                next_line = NULL;
     1060                goto discard_commands;
     1061
     1062            /* Append the next line to the current line */
     1063            case 'N':
     1064            {
     1065                int len;
     1066                /* If no next line, jump to end of script and exit. */
     1067                if (next_line == NULL) {
     1068                    /* Jump to end of script and exit */
     1069                    free(next_line);
     1070                    next_line = NULL;
     1071                    goto discard_line;
     1072                /* append next_line, read new next_line. */
     1073                }
     1074                len = strlen(pattern_space);
     1075                pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
     1076                pattern_space[len] = '\n';
     1077                strcpy(pattern_space + len+1, next_line);
     1078                last_gets_char = next_gets_char;
     1079                next_line = get_next_line(&next_gets_char);
     1080                linenum++;
     1081                break;
     1082            }
     1083
     1084            /* Test/branch if substitution occurred */
     1085            case 't':
     1086                if (!substituted) break;
     1087                substituted = 0;
     1088                /* Fall through */
     1089            /* Test/branch if substitution didn't occur */
     1090            case 'T':
     1091                if (substituted) break;
     1092                /* Fall through */
     1093            /* Branch to label */
     1094            case 'b':
     1095                if (!sed_cmd->string) goto discard_commands;
     1096                else sed_cmd = branch_to(sed_cmd->string);
     1097                break;
     1098            /* Transliterate characters */
     1099            case 'y':
     1100            {
     1101                int i, j;
     1102
     1103                for (i = 0; pattern_space[i]; i++) {
     1104                    for (j = 0; sed_cmd->string[j]; j += 2) {
     1105                        if (pattern_space[i] == sed_cmd->string[j]) {
     1106                            pattern_space[i] = sed_cmd->string[j + 1];
    8401107                            break;
    8411108                        }
    842                         /* Fall Through */
    843                     }
    844 
    845                     /* Write the current pattern space to output */
    846                     case 'p':
    847                         sed_puts(pattern_space,no_newline);
    848                         break;
    849                     /* Delete up through first newline */
    850                     case 'D':
    851                     {
    852                         char *tmp = strchr(pattern_space,'\n');
    853 
    854                         if(tmp) {
    855                             tmp=bb_xstrdup(tmp+1);
    856                             free(pattern_space);
    857                             pattern_space=tmp;
    858                             goto restart;
    859                         }
    860                     }
    861                     /* discard this line. */
    862                     case 'd':
    863                         goto discard_line;
    864 
    865                     /* Substitute with regex */
    866                     case 's':
    867                         if(do_subst_command(sed_cmd, &pattern_space)) {
    868                             substituted|=1;
    869 
    870                             /* handle p option */
    871                             if(sed_cmd->sub_p)
    872                                 sed_puts(pattern_space,no_newline);
    873                             /* handle w option */
    874                             if(sed_cmd->file)
    875                                 sed_cmd->no_newline=puts_maybe_newline(pattern_space, sed_cmd->file, sed_cmd->no_newline, no_newline);
    876 
    877                         }
    878                         break;
    879 
    880                     /* Append line to linked list to be printed later */
    881                     case 'a':
    882                     {
    883                         append(sed_cmd->string);
    884                         break;
    885                     }
    886 
    887                     /* Insert text before this line */
    888                     case 'i':
    889                         sed_puts(sed_cmd->string,1);
    890                         break;
    891 
    892                     /* Cut and paste text (replace) */
    893                     case 'c':
    894                         /* Only triggers on last line of a matching range. */
    895                         if (!sed_cmd->in_match) sed_puts(sed_cmd->string,0);
    896                         goto discard_line;
    897 
    898                     /* Read file, append contents to output */
    899                     case 'r':
    900                     {
    901                         FILE *rfile;
    902 
    903                         rfile = fopen(sed_cmd->string, "r");
    904                         if (rfile) {
    905                             char *line;
    906 
    907                             while ((line = bb_get_chomped_line_from_file(rfile))
    908                                     != NULL)
    909                                 append(line);
    910                             bb_xprint_and_close_file(rfile);
    911                         }
    912 
    913                         break;
    914                     }
    915 
    916                     /* Write pattern space to file. */
    917                     case 'w':
    918                         sed_cmd->no_newline=puts_maybe_newline(pattern_space,sed_cmd->file, sed_cmd->no_newline,no_newline);
    919                         break;
    920 
    921                     /* Read next line from input */
    922                     case 'n':
    923                         if (!bbg.be_quiet)
    924                             sed_puts(pattern_space,no_newline);
    925                         if (next_line) {
    926                             free(pattern_space);
    927                             pattern_space = next_line;
    928                             no_newline=next_no_newline;
    929                             next_line = get_next_line(&next_no_newline);
    930                             linenum++;
    931                             break;
    932                         }
    933                         /* fall through */
    934 
    935                     /* Quit.  End of script, end of input. */
    936                     case 'q':
    937                         /* Exit the outer while loop */
    938                         free(next_line);
    939                         next_line = NULL;
    940                         goto discard_commands;
    941 
    942                     /* Append the next line to the current line */
    943                     case 'N':
    944                     {
    945                         /* If no next line, jump to end of script and exit. */
    946                         if (next_line == NULL) {
    947                             /* Jump to end of script and exit */
    948                             free(next_line);
    949                             next_line = NULL;
    950                             goto discard_line;
    951                         /* append next_line, read new next_line. */
    952                         } else {
    953                             int len=strlen(pattern_space);
    954 
    955                             pattern_space = realloc(pattern_space, len + strlen(next_line) + 2);
    956                             pattern_space[len]='\n';
    957                             strcpy(pattern_space+len+1, next_line);
    958                             no_newline=next_no_newline;
    959                             next_line = get_next_line(&next_no_newline);
    960                             linenum++;
    961                         }
    962                         break;
    963                     }
    964 
    965                     /* Test/branch if substitution occurred */
    966                     case 't':
    967                         if(!substituted) break;
    968                         substituted=0;
    969                         /* Fall through */
    970                     /* Test/branch if substitution didn't occur */
    971                     case 'T':
    972                         if (substituted) break;
    973                         /* Fall through */
    974                     /* Branch to label */
    975                     case 'b':
    976                         if (!sed_cmd->string) goto discard_commands;
    977                         else sed_cmd = branch_to(sed_cmd->string);
    978                         break;
    979                     /* Transliterate characters */
    980                     case 'y':
    981                     {
    982                         int i;
    983 
    984                         for (i = 0; pattern_space[i]; i++) {
    985                             int j;
    986 
    987                             for (j = 0; sed_cmd->string[j]; j += 2) {
    988                                 if (pattern_space[i] == sed_cmd->string[j]) {
    989                                     pattern_space[i] = sed_cmd->string[j + 1];
    990                                     break;
    991                                 }
    992                             }
    993                         }
    994 
    995                         break;
    996                     }
    997                     case 'g':   /* Replace pattern space with hold space */
    998                         free(pattern_space);
    999                         pattern_space = bb_xstrdup(bbg.hold_space ? bbg.hold_space : "");
    1000                         break;
    1001                     case 'G':   /* Append newline and hold space to pattern space */
    1002                     {
    1003                         int pattern_space_size = 2;
    1004                         int hold_space_size = 0;
    1005 
    1006                         if (pattern_space)
    1007                             pattern_space_size += strlen(pattern_space);
    1008                         if (bbg.hold_space)
    1009                             hold_space_size = strlen(bbg.hold_space);
    1010                         pattern_space = xrealloc(pattern_space,
    1011                                 pattern_space_size + hold_space_size);
    1012                         if (pattern_space_size == 2) pattern_space[0]=0;
    1013                         strcat(pattern_space, "\n");
    1014                         if (bbg.hold_space)
    1015                             strcat(pattern_space, bbg.hold_space);
    1016                         no_newline=0;
    1017 
    1018                         break;
    1019                     }
    1020                     case 'h':   /* Replace hold space with pattern space */
    1021                         free(bbg.hold_space);
    1022                         bbg.hold_space = bb_xstrdup(pattern_space);
    1023                         break;
    1024                     case 'H':   /* Append newline and pattern space to hold space */
    1025                     {
    1026                         int hold_space_size = 2;
    1027                         int pattern_space_size = 0;
    1028 
    1029                         if (bbg.hold_space)
    1030                             hold_space_size += strlen(bbg.hold_space);
    1031                         if (pattern_space)
    1032                             pattern_space_size = strlen(pattern_space);
    1033                         bbg.hold_space = xrealloc(bbg.hold_space,
    1034                                             hold_space_size + pattern_space_size);
    1035 
    1036                         if (hold_space_size == 2) *bbg.hold_space=0;
    1037                         strcat(bbg.hold_space, "\n");
    1038                         if (pattern_space) strcat(bbg.hold_space, pattern_space);
    1039 
    1040                         break;
    1041                     }
    1042                     case 'x': /* Exchange hold and pattern space */
    1043                     {
    1044                         char *tmp = pattern_space;
    1045                         pattern_space = bbg.hold_space ? : xzalloc(1);
    1046                         no_newline=0;
    1047                         bbg.hold_space = tmp;
    1048                         break;
    10491109                    }
    10501110                }
    1051             }
    1052         }
    1053 
    1054         /*
    1055          * exit point from sedding...
    1056          */
    1057 discard_commands:
    1058         /* we will print the line unless we were told to be quiet ('-n')
    1059            or if the line was suppressed (ala 'd'elete) */
    1060         if (!bbg.be_quiet) sed_puts(pattern_space,no_newline);
    1061 
    1062         /* Delete and such jump here. */
    1063 discard_line:
    1064         flush_append();
    1065         free(pattern_space);
    1066     }
     1111
     1112                break;
     1113            }
     1114            case 'g':   /* Replace pattern space with hold space */
     1115                free(pattern_space);
     1116                pattern_space = xstrdup(G.hold_space ? G.hold_space : "");
     1117                break;
     1118            case 'G':   /* Append newline and hold space to pattern space */
     1119            {
     1120                int pattern_space_size = 2;
     1121                int hold_space_size = 0;
     1122
     1123                if (pattern_space)
     1124                    pattern_space_size += strlen(pattern_space);
     1125                if (G.hold_space)
     1126                    hold_space_size = strlen(G.hold_space);
     1127                pattern_space = xrealloc(pattern_space,
     1128                        pattern_space_size + hold_space_size);
     1129                if (pattern_space_size == 2)
     1130                    pattern_space[0] = 0;
     1131                strcat(pattern_space, "\n");
     1132                if (G.hold_space)
     1133                    strcat(pattern_space, G.hold_space);
     1134                last_gets_char = '\n';
     1135
     1136                break;
     1137            }
     1138            case 'h':   /* Replace hold space with pattern space */
     1139                free(G.hold_space);
     1140                G.hold_space = xstrdup(pattern_space);
     1141                break;
     1142            case 'H':   /* Append newline and pattern space to hold space */
     1143            {
     1144                int hold_space_size = 2;
     1145                int pattern_space_size = 0;
     1146
     1147                if (G.hold_space)
     1148                    hold_space_size += strlen(G.hold_space);
     1149                if (pattern_space)
     1150                    pattern_space_size = strlen(pattern_space);
     1151                G.hold_space = xrealloc(G.hold_space,
     1152                        hold_space_size + pattern_space_size);
     1153
     1154                if (hold_space_size == 2)
     1155                    *G.hold_space = 0;
     1156                strcat(G.hold_space, "\n");
     1157                if (pattern_space)
     1158                    strcat(G.hold_space, pattern_space);
     1159
     1160                break;
     1161            }
     1162            case 'x': /* Exchange hold and pattern space */
     1163            {
     1164                char *tmp = pattern_space;
     1165                pattern_space = G.hold_space ? : xzalloc(1);
     1166                last_gets_char = '\n';
     1167                G.hold_space = tmp;
     1168                break;
     1169            }
     1170            }
     1171        }
     1172    }
     1173
     1174    /*
     1175     * exit point from sedding...
     1176     */
     1177 discard_commands:
     1178    /* we will print the line unless we were told to be quiet ('-n')
     1179       or if the line was suppressed (ala 'd'elete) */
     1180    if (!G.be_quiet)
     1181        sed_puts(pattern_space, last_gets_char);
     1182
     1183    /* Delete and such jump here. */
     1184 discard_line:
     1185    flush_append();
     1186    free(pattern_space);
     1187
     1188    goto again;
    10671189}
    10681190
    10691191/* It is possible to have a command line argument with embedded
    1070    newlines.  This counts as multiple command lines. */
     1192 * newlines.  This counts as multiple command lines.
     1193 * However, newline can be escaped: 's/e/z\<newline>z/'
     1194 * We check for this.
     1195 */
    10711196
    10721197static void add_cmd_block(char *cmdstr)
    10731198{
    1074     int go=1;
    1075     char *temp=bb_xstrdup(cmdstr),*temp2=temp;
    1076 
    1077     while(go) {
    1078         int len=strcspn(temp2,"\n");
    1079         if(!temp2[len]) go=0;
    1080         else temp2[len]=0;
    1081         add_cmd(temp2);
    1082         temp2+=len+1;
    1083     }
    1084     free(temp);
    1085 }
    1086 
     1199    char *sv, *eol;
     1200
     1201    cmdstr = sv = xstrdup(cmdstr);
     1202    do {
     1203        eol = strchr(cmdstr, '\n');
     1204 next:
     1205        if (eol) {
     1206            /* Count preceding slashes */
     1207            int slashes = 0;
     1208            char *sl = eol;
     1209
     1210            while (sl != cmdstr && *--sl == '\\')
     1211                slashes++;
     1212            /* Odd number of preceding slashes - newline is escaped */
     1213            if (slashes & 1) {
     1214                strcpy(eol-1, eol);
     1215                eol = strchr(eol, '\n');
     1216                goto next;
     1217            }
     1218            *eol = '\0';
     1219        }
     1220        add_cmd(cmdstr);
     1221        cmdstr = eol + 1;
     1222    } while (eol);
     1223    free(sv);
     1224}
     1225
     1226int sed_main(int argc, char **argv);
    10871227int sed_main(int argc, char **argv)
    10881228{
    1089     int status = EXIT_SUCCESS, opt, getpat = 1;
    1090 
    1091     bbg.sed_cmd_tail=&bbg.sed_cmd_head;
     1229    enum {
     1230        OPT_in_place = 1 << 0,
     1231    };
     1232    unsigned opt;
     1233    llist_t *opt_e, *opt_f;
     1234    int status = EXIT_SUCCESS;
     1235
     1236    INIT_G();
    10921237
    10931238    /* destroy command strings on exit */
     
    10951240
    10961241    /* Lie to autoconf when it starts asking stupid questions. */
    1097     if(argc==2 && !strcmp(argv[1],"--version")) {
    1098         printf("This is not GNU sed version 4.0\n");
    1099         exit(0);
     1242    if (argc == 2 && !strcmp(argv[1], "--version")) {
     1243        puts("This is not GNU sed version 4.0");
     1244        return 0;
    11001245    }
    11011246
    11021247    /* do normal option parsing */
    1103     while ((opt = getopt(argc, argv, "irne:f:")) > 0) {
    1104         switch (opt) {
    1105         case 'i':
    1106             bbg.in_place++;
    1107             atexit(cleanup_outname);
    1108             break;
    1109         case 'r':
    1110             bbg.regex_type|=REG_EXTENDED;
    1111             break;
    1112         case 'n':
    1113             bbg.be_quiet++;
    1114             break;
    1115         case 'e':
    1116             add_cmd_block(optarg);
    1117             getpat=0;
    1118             break;
    1119         case 'f':
    1120         {
    1121             FILE *cmdfile;
    1122             char *line;
    1123 
    1124             cmdfile = bb_xfopen(optarg, "r");
    1125 
    1126             while ((line = bb_get_chomped_line_from_file(cmdfile)) != NULL) {
    1127                 add_cmd(line);
    1128                 getpat=0;
    1129                 free(line);
    1130             }
    1131             bb_xprint_and_close_file(cmdfile);
    1132 
    1133             break;
    1134         }
    1135         default:
     1248    opt_e = opt_f = NULL;
     1249    opt_complementary = "e::f::" /* can occur multiple times */
     1250                        "nn"; /* count -n */
     1251    opt = getopt32(argv, "irne:f:", &opt_e, &opt_f,
     1252                &G.be_quiet); /* counter for -n */
     1253    argc -= optind;
     1254    argv += optind;
     1255    if (opt & OPT_in_place) { // -i
     1256        atexit(cleanup_outname);
     1257    }
     1258    if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r
     1259    //if (opt & 0x4) G.be_quiet++; // -n
     1260    while (opt_e) { // -e
     1261        add_cmd_block(opt_e->data);
     1262        opt_e = opt_e->link;
     1263        /* we leak opt_e here... */
     1264    }
     1265    while (opt_f) { // -f
     1266        char *line;
     1267        FILE *cmdfile;
     1268        cmdfile = xfopen(opt_f->data, "r");
     1269        while ((line = xmalloc_getline(cmdfile)) != NULL) {
     1270            add_cmd(line);
     1271            free(line);
     1272        }
     1273        fclose(cmdfile);
     1274        opt_f = opt_f->link;
     1275        /* we leak opt_f here... */
     1276    }
     1277    /* if we didn't get a pattern from -e or -f, use argv[0] */
     1278    if (!(opt & 0x18)) {
     1279        if (!argc)
    11361280            bb_show_usage();
    1137         }
    1138     }
    1139 
    1140     /* if we didn't get a pattern from -e or -f, use argv[optind] */
    1141     if(getpat) {
    1142         if (argv[optind] == NULL)
    1143             bb_show_usage();
    1144         else
    1145             add_cmd_block(argv[optind++]);
     1281        add_cmd_block(*argv++);
     1282        argc--;
    11461283    }
    11471284    /* Flush any unfinished commands. */
     
    11491286
    11501287    /* By default, we write to stdout */
    1151     bbg.nonstdout=stdout;
    1152 
    1153     /* argv[(optind)..(argc-1)] should be names of file to process. If no
     1288    G.nonstdout = stdout;
     1289
     1290    /* argv[0..(argc-1)] should be names of file to process. If no
    11541291     * files were specified or '-' was specified, take input from stdin.
    11551292     * Otherwise, we process all the files specified. */
    1156     if (argv[optind] == NULL) {
    1157         if(bbg.in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i");
     1293    if (argv[0] == NULL) {
     1294        if (opt & OPT_in_place)
     1295            bb_error_msg_and_die(bb_msg_requires_arg, "-i");
    11581296        add_input_file(stdin);
    11591297        process_files();
     
    11621300        FILE *file;
    11631301
    1164         for (i = optind; i < argc; i++) {
    1165             if(!strcmp(argv[i], "-") && !bbg.in_place) {
     1302        for (i = 0; i < argc; i++) {
     1303            struct stat statbuf;
     1304            int nonstdoutfd;
     1305
     1306            if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) {
    11661307                add_input_file(stdin);
    11671308                process_files();
    1168             } else {
    1169                 file = bb_wfopen(argv[i], "r");
    1170                 if (file) {
    1171                     if(bbg.in_place) {
    1172                         struct stat statbuf;
    1173                         int nonstdoutfd;
    1174 
    1175                         bbg.outname=bb_xstrndup(argv[i],strlen(argv[i])+6);
    1176                         strcat(bbg.outname,"XXXXXX");
    1177                         if(-1==(nonstdoutfd=mkstemp(bbg.outname)))
    1178                             bb_error_msg_and_die("no temp file");
    1179                         bbg.nonstdout=fdopen(nonstdoutfd,"w");
    1180 
    1181                         /* Set permissions of output file */
    1182 
    1183                         fstat(fileno(file),&statbuf);
    1184                         fchmod(nonstdoutfd,statbuf.st_mode);
    1185                         add_input_file(file);
    1186                         process_files();
    1187                         fclose(bbg.nonstdout);
    1188 
    1189                         bbg.nonstdout=stdout;
    1190                         unlink(argv[i]);
    1191                         rename(bbg.outname,argv[i]);
    1192                         free(bbg.outname);
    1193                         bbg.outname=0;
    1194                     } else add_input_file(file);
    1195                 } else {
    1196                     status = EXIT_FAILURE;
    1197                 }
    1198             }
    1199         }
    1200         if(bbg.input_file_count>bbg.current_input_file) process_files();
     1309                continue;
     1310            }
     1311            file = fopen_or_warn(argv[i], "r");
     1312            if (!file) {
     1313                status = EXIT_FAILURE;
     1314                continue;
     1315            }
     1316            if (!(opt & OPT_in_place)) {
     1317                add_input_file(file);
     1318                continue;
     1319            }
     1320
     1321            G.outname = xasprintf("%sXXXXXX", argv[i]);
     1322            nonstdoutfd = mkstemp(G.outname);
     1323            if (-1 == nonstdoutfd)
     1324                bb_perror_msg_and_die("cannot create temp file %s", G.outname);
     1325            G.nonstdout = fdopen(nonstdoutfd, "w");
     1326
     1327            /* Set permissions of output file */
     1328
     1329            fstat(fileno(file), &statbuf);
     1330            fchmod(nonstdoutfd, statbuf.st_mode);
     1331            add_input_file(file);
     1332            process_files();
     1333            fclose(G.nonstdout);
     1334
     1335            G.nonstdout = stdout;
     1336            /* unlink(argv[i]); */
     1337            // FIXME: error check / message?
     1338            rename(G.outname, argv[i]);
     1339            free(G.outname);
     1340            G.outname = 0;
     1341        }
     1342        if (G.input_file_count > G.current_input_file)
     1343            process_files();
    12011344    }
    12021345
  • branches/2.2.5/mindi-busybox/editors/vi.c

    r821 r1765  
    1414 *  add :help command
    1515 *  :map macros
    16  *  how about mode lines:   vi: set sw=8 ts=8:
    1716 *  if mark[] values were line numbers rather than pointers
    1817 *     it would be easier to change the mark when add/delete lines
     
    2322 */
    2423
    25 
    26 #include "busybox.h"
    27 #include <string.h>
    28 #include <strings.h>
    29 #include <unistd.h>
    30 #include <sys/ioctl.h>
    31 #include <time.h>
    32 #include <fcntl.h>
    33 #include <signal.h>
    34 #include <setjmp.h>
    35 #include <regex.h>
    36 #include <ctype.h>
    37 #include <errno.h>
    38 #define vi_Version BB_VER " " BB_BT
    39 
    40 #ifdef CONFIG_LOCALE_SUPPORT
     24#include "libbb.h"
     25
     26#define ENABLE_FEATURE_VI_CRASHME 0
     27
     28#if ENABLE_LOCALE_SUPPORT
    4129#define Isprint(c) isprint((c))
    4230#else
    43 #define Isprint(c) ( (c) >= ' ' && (c) != 127 && (c) != ((unsigned char)'\233') )
    44 #endif
    45 
    46 #define MAX_SCR_COLS        BUFSIZ
     31/* 0x9b is Meta-ESC */
     32#define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b)
     33#endif
     34
     35enum {
     36    MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN,
     37    MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN,
     38};
    4739
    4840// Misc. non-Ascii keys that report an escape sequence
    49 #define VI_K_UP         128 // cursor key Up
    50 #define VI_K_DOWN       129 // cursor key Down
    51 #define VI_K_RIGHT      130 // Cursor Key Right
    52 #define VI_K_LEFT       131 // cursor key Left
    53 #define VI_K_HOME       132 // Cursor Key Home
    54 #define VI_K_END        133 // Cursor Key End
    55 #define VI_K_INSERT     134 // Cursor Key Insert
    56 #define VI_K_PAGEUP     135 // Cursor Key Page Up
    57 #define VI_K_PAGEDOWN       136 // Cursor Key Page Down
    58 #define VI_K_FUN1       137 // Function Key F1
    59 #define VI_K_FUN2       138 // Function Key F2
    60 #define VI_K_FUN3       139 // Function Key F3
    61 #define VI_K_FUN4       140 // Function Key F4
    62 #define VI_K_FUN5       141 // Function Key F5
    63 #define VI_K_FUN6       142 // Function Key F6
    64 #define VI_K_FUN7       143 // Function Key F7
    65 #define VI_K_FUN8       144 // Function Key F8
    66 #define VI_K_FUN9       145 // Function Key F9
    67 #define VI_K_FUN10      146 // Function Key F10
    68 #define VI_K_FUN11      147 // Function Key F11
    69 #define VI_K_FUN12      148 // Function Key F12
     41#define VI_K_UP         (char)128   // cursor key Up
     42#define VI_K_DOWN       (char)129   // cursor key Down
     43#define VI_K_RIGHT      (char)130   // Cursor Key Right
     44#define VI_K_LEFT       (char)131   // cursor key Left
     45#define VI_K_HOME       (char)132   // Cursor Key Home
     46#define VI_K_END        (char)133   // Cursor Key End
     47#define VI_K_INSERT     (char)134   // Cursor Key Insert
     48#define VI_K_PAGEUP     (char)135   // Cursor Key Page Up
     49#define VI_K_PAGEDOWN       (char)136   // Cursor Key Page Down
     50#define VI_K_FUN1       (char)137   // Function Key F1
     51#define VI_K_FUN2       (char)138   // Function Key F2
     52#define VI_K_FUN3       (char)139   // Function Key F3
     53#define VI_K_FUN4       (char)140   // Function Key F4
     54#define VI_K_FUN5       (char)141   // Function Key F5
     55#define VI_K_FUN6       (char)142   // Function Key F6
     56#define VI_K_FUN7       (char)143   // Function Key F7
     57#define VI_K_FUN8       (char)144   // Function Key F8
     58#define VI_K_FUN9       (char)145   // Function Key F9
     59#define VI_K_FUN10      (char)146   // Function Key F10
     60#define VI_K_FUN11      (char)147   // Function Key F11
     61#define VI_K_FUN12      (char)148   // Function Key F12
    7062
    7163/* vt102 typical ESC sequence */
    7264/* terminal standout start/normal ESC sequence */
    73 static const char SOs[] = "\033[7m";
    74 static const char SOn[] = "\033[0m";
     65static const char SOs[] ALIGN1 = "\033[7m";
     66static const char SOn[] ALIGN1 = "\033[0m";
    7567/* terminal bell sequence */
    76 static const char bell[] = "\007";
     68static const char bell[] ALIGN1 = "\007";
    7769/* Clear-end-of-line and Clear-end-of-screen ESC sequence */
    78 static const char Ceol[] = "\033[0K";
    79 static const char Ceos [] = "\033[0J";
     70static const char Ceol[] ALIGN1 = "\033[0K";
     71static const char Ceos[] ALIGN1 = "\033[0J";
    8072/* Cursor motion arbitrary destination ESC sequence */
    81 static const char CMrc[] = "\033[%d;%dH";
     73static const char CMrc[] ALIGN1 = "\033[%d;%dH";
    8274/* Cursor motion up and down ESC sequence */
    83 static const char CMup[] = "\033[A";
    84 static const char CMdown[] = "\n";
     75static const char CMup[] ALIGN1 = "\033[A";
     76static const char CMdown[] ALIGN1 = "\n";
    8577
    8678
     
    9789    S_OVER_WS = 3,      // used in skip_thing() for moving "dot"
    9890    S_END_PUNCT = 4,    // used in skip_thing() for moving "dot"
    99     S_END_ALNUM = 5     // used in skip_thing() for moving "dot"
     91    S_END_ALNUM = 5,    // used in skip_thing() for moving "dot"
    10092};
    10193
    102 typedef unsigned char Byte;
    103 
    104 static int vi_setops;
     94/* vi.c expects chars to be unsigned. */
     95/* busybox build system provides that, but it's better */
     96/* to audit and fix the source */
     97
     98static smallint vi_setops;
    10599#define VI_AUTOINDENT 1
    106100#define VI_SHOWMATCH  2
     
    114108
    115109
    116 static int editing;     // >0 while we are editing a file
    117 static int cmd_mode;        // 0=command  1=insert 2=replace
    118 static int file_modified;   // buffer contents changed
    119 static int last_file_modified = -1;
    120 static int fn_start;        // index of first cmd line file name
    121 static int save_argc;       // how many file names on cmd line
    122 static int cmdcnt;      // repetition count
    123 static fd_set rfds;     // use select() for small sleeps
    124 static struct timeval tv;   // use select() for small sleeps
    125 static int rows, columns;   // the terminal screen is this size
    126 static int crow, ccol, offset;  // cursor is on Crow x Ccol with Horz Ofset
    127 static Byte *status_buffer; // mesages to the user
     110static smallint editing;        // >0 while we are editing a file
     111                                // [code audit says "can be 0 or 1 only"]
     112static smallint cmd_mode;       // 0=command  1=insert 2=replace
     113static smallint file_modified;  // buffer contents changed
     114static smallint last_file_modified = -1;
     115static int fn_start;            // index of first cmd line file name
     116static int save_argc;           // how many file names on cmd line
     117static int cmdcnt;              // repetition count
     118static int rows, columns;       // the terminal screen is this size
     119static int crow, ccol, offset;  // cursor is on Crow x Ccol with Horz Ofset
     120static char *status_buffer;     // mesages to the user
    128121#define STATUS_BUFFER_LEN  200
    129122static int have_status_msg;     // is default edit status needed?
     123                                // [don't make smallint!]
    130124static int last_status_cksum;   // hash of current status line
    131 static Byte *cfn;       // previous, current, and next file name
    132 static Byte *text, *end, *textend;  // pointers to the user data in memory
    133 static Byte *screen;        // pointer to the virtual screen buffer
    134 static int screensize;      //            and its size
    135 static Byte *screenbegin;   // index into text[], of top line on the screen
    136 static Byte *dot;       // where all the action takes place
     125static char *current_filename;               // current file name
     126//static char *text, *end;        // pointers to the user data in memory
     127static char *screen;            // pointer to the virtual screen buffer
     128static int screensize;          //            and its size
     129static char *screenbegin;       // index into text[], of top line on the screen
     130//static char *dot;               // where all the action takes place
    137131static int tabstop;
    138 static struct termios term_orig, term_vi;   // remember what the cooked mode was
    139 static Byte erase_char;         // the users erase character
    140 static Byte last_input_char;    // last char read from user
    141 static Byte last_forward_char;  // last char searched for with 'f'
    142 
    143 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     132static char erase_char;         // the users erase character
     133static char last_input_char;    // last char read from user
     134static char last_forward_char;  // last char searched for with 'f'
     135
     136#if ENABLE_FEATURE_VI_READONLY
     137//static smallint vi_readonly, readonly;
     138static smallint readonly_mode = 0;
     139#define SET_READONLY_FILE(flags)        ((flags) |= 0x01)
     140#define SET_READONLY_MODE(flags)        ((flags) |= 0x02)
     141#define UNSET_READONLY_FILE(flags)      ((flags) &= 0xfe)
     142#else
     143#define readonly_mode 0
     144#define SET_READONLY_FILE(flags)
     145#define SET_READONLY_MODE(flags)
     146#define UNSET_READONLY_FILE(flags)
     147#endif
     148
     149#if ENABLE_FEATURE_VI_DOT_CMD
     150static smallint adding2q;       // are we currently adding user input to q
     151static char *last_modifying_cmd;    // last modifying cmd for "."
     152static char *ioq, *ioq_start;           // pointer to string for get_one_char to "read"
     153#endif
     154#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    144155static int last_row;        // where the cursor was last moved to
    145 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
    146 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
    147 static jmp_buf restart;     // catch_sig()
    148 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
    149 #if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME)
     156#endif
     157#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
    150158static int my_pid;
    151159#endif
    152 #ifdef CONFIG_FEATURE_VI_DOT_CMD
    153 static int adding2q;        // are we currently adding user input to q
    154 static Byte *last_modifying_cmd;    // last modifying cmd for "."
    155 static Byte *ioq, *ioq_start;   // pointer to string for get_one_char to "read"
    156 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    157 #if defined(CONFIG_FEATURE_VI_DOT_CMD) || defined(CONFIG_FEATURE_VI_YANKMARK)
    158 static Byte *modifying_cmds;    // cmds that modify text[]
    159 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD || CONFIG_FEATURE_VI_YANKMARK */
    160 #ifdef CONFIG_FEATURE_VI_READONLY
    161 static int vi_readonly, readonly;
    162 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    163 #ifdef CONFIG_FEATURE_VI_YANKMARK
    164 static Byte *reg[28];       // named register a-z, "D", and "U" 0-25,26,27
    165 static int YDreg, Ureg;     // default delete register and orig line for "U"
    166 static Byte *mark[28];      // user marks points somewhere in text[]-  a-z and previous context ''
    167 static Byte *context_start, *context_end;
    168 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    169 #ifdef CONFIG_FEATURE_VI_SEARCH
    170 static Byte *last_search_pattern;   // last pattern from a '/' or '?' search
    171 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
    172 
    173 
    174 static void edit_file(Byte *);  // edit one file
    175 static void do_cmd(Byte);   // execute a command
    176 static void sync_cursor(Byte *, int *, int *);  // synchronize the screen cursor to dot
    177 static Byte *begin_line(Byte *);    // return pointer to cur line B-o-l
    178 static Byte *end_line(Byte *);  // return pointer to cur line E-o-l
    179 static Byte *prev_line(Byte *); // return pointer to prev line B-o-l
    180 static Byte *next_line(Byte *); // return pointer to next line B-o-l
    181 static Byte *end_screen(void);  // get pointer to last char on screen
    182 static int count_lines(Byte *, Byte *); // count line from start to stop
    183 static Byte *find_line(int);    // find begining of line #li
    184 static Byte *move_to_col(Byte *, int);  // move "p" to column l
    185 static int isblnk(Byte);    // is the char a blank or tab
     160#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
     161static char *modifying_cmds;            // cmds that modify text[]
     162#endif
     163#if ENABLE_FEATURE_VI_SEARCH
     164static char *last_search_pattern;   // last pattern from a '/' or '?' search
     165#endif
     166
     167/* Moving biggest data to malloced space... */
     168struct globals {
     169    /* many references - keep near the top of globals */
     170    char *text, *end;       // pointers to the user data in memory
     171    int text_size;      // size of the allocated buffer
     172    char *dot;              // where all the action takes place
     173#if ENABLE_FEATURE_VI_YANKMARK
     174    char *reg[28];          // named register a-z, "D", and "U" 0-25,26,27
     175    int YDreg, Ureg;        // default delete register and orig line for "U"
     176    char *mark[28];         // user marks points somewhere in text[]-  a-z and previous context ''
     177    char *context_start, *context_end;
     178#endif
     179    /* a few references only */
     180#if ENABLE_FEATURE_VI_USE_SIGNALS
     181    jmp_buf restart;        // catch_sig()
     182#endif
     183    struct termios term_orig, term_vi;  // remember what the cooked mode was
     184#if ENABLE_FEATURE_VI_COLON
     185    char *initial_cmds[3];  // currently 2 entries, NULL terminated
     186#endif
     187};
     188#define G (*ptr_to_globals)
     189#define text           (G.text          )
     190#define text_size      (G.text_size     )
     191#define end            (G.end           )
     192#define dot            (G.dot           )
     193#define reg            (G.reg           )
     194#define YDreg          (G.YDreg         )
     195#define Ureg           (G.Ureg          )
     196#define mark           (G.mark          )
     197#define context_start  (G.context_start )
     198#define context_end    (G.context_end   )
     199#define restart        (G.restart       )
     200#define term_orig      (G.term_orig     )
     201#define term_vi        (G.term_vi       )
     202#define initial_cmds   (G.initial_cmds  )
     203
     204static int init_text_buffer(char *); // init from file or create new
     205static void edit_file(char *);  // edit one file
     206static void do_cmd(char);   // execute a command
     207static int next_tabstop(int);
     208static void sync_cursor(char *, int *, int *);  // synchronize the screen cursor to dot
     209static char *begin_line(char *);    // return pointer to cur line B-o-l
     210static char *end_line(char *);  // return pointer to cur line E-o-l
     211static char *prev_line(char *); // return pointer to prev line B-o-l
     212static char *next_line(char *); // return pointer to next line B-o-l
     213static char *end_screen(void);  // get pointer to last char on screen
     214static int count_lines(char *, char *); // count line from start to stop
     215static char *find_line(int);    // find begining of line #li
     216static char *move_to_col(char *, int);  // move "p" to column l
    186217static void dot_left(void); // move dot left- dont leave line
    187218static void dot_right(void);    // move dot right- dont leave line
     
    193224static void dot_skip_over_ws(void); // move dot pat WS
    194225static void dot_delete(void);   // delete the char at 'dot'
    195 static Byte *bound_dot(Byte *); // make sure  text[0] <= P < "end"
    196 static Byte *new_screen(int, int);  // malloc virtual screen memory
    197 static Byte *new_text(int); // malloc memory for text[] buffer
    198 static Byte *char_insert(Byte *, Byte); // insert the char c at 'p'
    199 static Byte *stupid_insert(Byte *, Byte);   // stupidly insert the char c at 'p'
    200 static Byte find_range(Byte **, Byte **, Byte); // return pointers for an object
    201 static int st_test(Byte *, int, int, Byte *);   // helper for skip_thing()
    202 static Byte *skip_thing(Byte *, int, int, int); // skip some object
    203 static Byte *find_pair(Byte *, Byte);   // find matching pair ()  []  {}
    204 static Byte *text_hole_delete(Byte *, Byte *);  // at "p", delete a 'size' byte hole
    205 static Byte *text_hole_make(Byte *, int);   // at "p", make a 'size' byte hole
    206 static Byte *yank_delete(Byte *, Byte *, int, int); // yank text[] into register then delete
     226static char *bound_dot(char *); // make sure  text[0] <= P < "end"
     227static char *new_screen(int, int);  // malloc virtual screen memory
     228static char *char_insert(char *, char); // insert the char c at 'p'
     229static char *stupid_insert(char *, char);   // stupidly insert the char c at 'p'
     230static char find_range(char **, char **, char); // return pointers for an object
     231static int st_test(char *, int, int, char *);   // helper for skip_thing()
     232static char *skip_thing(char *, int, int, int); // skip some object
     233static char *find_pair(char *, char);   // find matching pair ()  []  {}
     234static char *text_hole_delete(char *, char *);  // at "p", delete a 'size' byte hole
     235static char *text_hole_make(char *, int);   // at "p", make a 'size' byte hole
     236static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete
    207237static void show_help(void);    // display some help info
    208238static void rawmode(void);  // set "raw" mode on tty
    209239static void cookmode(void); // return to "cooked" mode on tty
    210240static int mysleep(int);    // sleep for 'h' 1/100 seconds
    211 static Byte readit(void);   // read (maybe cursor) key from stdin
    212 static Byte get_one_char(void); // read 1 char from stdin
    213 static int file_size(const Byte *);   // what is the byte size of "fn"
    214 static int file_insert(Byte *, Byte *, int);
    215 static int file_write(Byte *, Byte *, Byte *);
     241static char readit(void);   // read (maybe cursor) key from stdin
     242static char get_one_char(void); // read 1 char from stdin
     243static int file_size(const char *);   // what is the byte size of "fn"
     244#if ENABLE_FEATURE_VI_READONLY
     245static int file_insert(const char *, char *, int);
     246#else
     247static int file_insert(const char *, char *);
     248#endif
     249static int file_write(char *, char *, char *);
    216250static void place_cursor(int, int, int);
    217251static void screen_erase(void);
     
    224258static void psb(const char *, ...);     // Print Status Buf
    225259static void psbs(const char *, ...);    // Print Status Buf in standout mode
    226 static void ni(Byte *);     // display messages
     260static void ni(const char *);       // display messages
    227261static int format_edit_status(void);    // format file status on status line
    228262static void redraw(int);    // force a full screen refresh
    229 static void format_line(Byte*, Byte*, int);
     263static void format_line(char*, char*, int);
    230264static void refresh(int);   // update the terminal from screen[]
    231265
     
    234268static void Hit_Return(void);
    235269
    236 #ifdef CONFIG_FEATURE_VI_SEARCH
    237 static Byte *char_search(Byte *, Byte *, int, int); // search for pattern starting at p
    238 static int mycmp(Byte *, Byte *, int);  // string cmp based in "ignorecase"
    239 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
    240 #ifdef CONFIG_FEATURE_VI_COLON
    241 static Byte *get_one_address(Byte *, int *);    // get colon addr, if present
    242 static Byte *get_address(Byte *, int *, int *); // get two colon addrs, if present
    243 static void colon(Byte *);  // execute the "colon" mode cmds
    244 #endif                          /* CONFIG_FEATURE_VI_COLON */
    245 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     270#if ENABLE_FEATURE_VI_SEARCH
     271static char *char_search(char *, const char *, int, int);   // search for pattern starting at p
     272static int mycmp(const char *, const char *, int);  // string cmp based in "ignorecase"
     273#endif
     274#if ENABLE_FEATURE_VI_COLON
     275static char *get_one_address(char *, int *);    // get colon addr, if present
     276static char *get_address(char *, int *, int *); // get two colon addrs, if present
     277static void colon(char *);  // execute the "colon" mode cmds
     278#endif
     279#if ENABLE_FEATURE_VI_USE_SIGNALS
    246280static void winch_sig(int); // catch window size changes
    247281static void suspend_sig(int);   // catch ctrl-Z
    248282static void catch_sig(int);     // catch ctrl-C and alarm time-outs
    249 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
    250 #ifdef CONFIG_FEATURE_VI_DOT_CMD
    251 static void start_new_cmd_q(Byte);  // new queue for command
     283#endif
     284#if ENABLE_FEATURE_VI_DOT_CMD
     285static void start_new_cmd_q(char);  // new queue for command
    252286static void end_cmd_q(void);    // stop saving input chars
    253 #else                           /* CONFIG_FEATURE_VI_DOT_CMD */
    254 #define end_cmd_q()
    255 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    256 #ifdef CONFIG_FEATURE_VI_SETOPTS
    257 static void showmatching(Byte *);   // show the matching pair ()  []  {}
    258 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
    259 #if defined(CONFIG_FEATURE_VI_YANKMARK) || (defined(CONFIG_FEATURE_VI_COLON) && defined(CONFIG_FEATURE_VI_SEARCH)) || defined(CONFIG_FEATURE_VI_CRASHME)
    260 static Byte *string_insert(Byte *, Byte *); // insert the string at 'p'
    261 #endif                          /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_SEARCH || CONFIG_FEATURE_VI_CRASHME */
    262 #ifdef CONFIG_FEATURE_VI_YANKMARK
    263 static Byte *text_yank(Byte *, Byte *, int);    // save copy of "p" into a register
    264 static Byte what_reg(void);     // what is letter of current YDreg
    265 static void check_context(Byte);    // remember context for '' command
    266 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    267 #ifdef CONFIG_FEATURE_VI_CRASHME
     287#else
     288#define end_cmd_q() ((void)0)
     289#endif
     290#if ENABLE_FEATURE_VI_SETOPTS
     291static void showmatching(char *);   // show the matching pair ()  []  {}
     292#endif
     293#if ENABLE_FEATURE_VI_YANKMARK || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) || ENABLE_FEATURE_VI_CRASHME
     294static char *string_insert(char *, char *); // insert the string at 'p'
     295#endif
     296#if ENABLE_FEATURE_VI_YANKMARK
     297static char *text_yank(char *, char *, int);    // save copy of "p" into a register
     298static char what_reg(void);     // what is letter of current YDreg
     299static void check_context(char);    // remember context for '' command
     300#endif
     301#if ENABLE_FEATURE_VI_CRASHME
    268302static void crash_dummy();
    269303static void crash_test();
    270304static int crashme = 0;
    271 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
     305#endif
    272306
    273307
     
    277311}
    278312
     313int vi_main(int argc, char **argv);
    279314int vi_main(int argc, char **argv)
    280315{
     
    282317    RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN);
    283318
    284 #ifdef CONFIG_FEATURE_VI_YANKMARK
    285     int i;
    286 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    287 #if defined(CONFIG_FEATURE_VI_USE_SIGNALS) || defined(CONFIG_FEATURE_VI_CRASHME)
     319#if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME
    288320    my_pid = getpid();
    289321#endif
    290 #ifdef CONFIG_FEATURE_VI_CRASHME
    291     (void) srand((long) my_pid);
    292 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
    293 
    294     status_buffer = (Byte *)STATUS_BUFFER;
     322
     323    PTR_TO_GLOBALS = xzalloc(sizeof(G));
     324
     325#if ENABLE_FEATURE_VI_CRASHME
     326    srand((long) my_pid);
     327#endif
     328
     329    status_buffer = STATUS_BUFFER;
    295330    last_status_cksum = 0;
    296 
    297 #ifdef CONFIG_FEATURE_VI_READONLY
    298     vi_readonly = readonly = FALSE;
    299     if (strncmp(argv[0], "view", 4) == 0) {
    300         readonly = TRUE;
    301         vi_readonly = TRUE;
    302     }
    303 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     331    text = NULL;
     332
     333#ifdef NO_SUCH_APPLET_YET
     334    /* If we aren't "vi", we are "view" */
     335    if (ENABLE_FEATURE_VI_READONLY && applet_name[2]) {
     336        SET_READONLY_MODE(readonly_mode);
     337    }
     338#endif
     339
    304340    vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE | VI_ERR_METHOD;
    305 #ifdef CONFIG_FEATURE_VI_YANKMARK
    306     for (i = 0; i < 28; i++) {
    307         reg[i] = 0;
    308     }                   // init the yank regs
    309 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    310 #if defined(CONFIG_FEATURE_VI_DOT_CMD) || defined(CONFIG_FEATURE_VI_YANKMARK)
    311     modifying_cmds = (Byte *) "aAcCdDiIJoOpPrRsxX<>~";  // cmds modifying text[]
    312 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    313 
    314     //  1-  process $HOME/.exrc file
     341#if ENABLE_FEATURE_VI_YANKMARK
     342    memset(reg, 0, sizeof(reg)); // init the yank regs
     343#endif
     344#if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK
     345    modifying_cmds = (char *) "aAcCdDiIJoOpPrRsxX<>~";  // cmds modifying text[]
     346#endif
     347
     348    //  1-  process $HOME/.exrc file (not inplemented yet)
    315349    //  2-  process EXINIT variable from environment
    316350    //  3-  process command line args
    317     while ((c = getopt(argc, argv, "hCR")) != -1) {
     351#if ENABLE_FEATURE_VI_COLON
     352    {
     353        char *p = getenv("EXINIT");
     354        if (p && *p)
     355            initial_cmds[0] = xstrdup(p);
     356    }
     357#endif
     358    while ((c = getopt(argc, argv, "hCR" USE_FEATURE_VI_COLON("c:"))) != -1) {
    318359        switch (c) {
    319 #ifdef CONFIG_FEATURE_VI_CRASHME
     360#if ENABLE_FEATURE_VI_CRASHME
    320361        case 'C':
    321362            crashme = 1;
    322363            break;
    323 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
    324 #ifdef CONFIG_FEATURE_VI_READONLY
     364#endif
     365#if ENABLE_FEATURE_VI_READONLY
    325366        case 'R':       // Read-only flag
    326             readonly = TRUE;
    327             vi_readonly = TRUE;
     367            SET_READONLY_MODE(readonly_mode);
    328368            break;
    329 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     369#endif
    330370            //case 'r': // recover flag-  ignore- we don't use tmp file
    331371            //case 'x': // encryption flag- ignore
    332372            //case 'c': // execute command first
     373#if ENABLE_FEATURE_VI_COLON
     374        case 'c':       // cmd line vi command
     375            if (*optarg)
     376                initial_cmds[initial_cmds[0] != 0] = xstrdup(optarg);
     377            break;
    333378            //case 'h': // help -- just use default
     379#endif
    334380        default:
    335381            show_help();
     
    345391    //----- This is the main file handling loop --------------
    346392    if (optind >= argc) {
    347         editing = 1;    // 0= exit,  1= one file,  2= multiple files
    348393        edit_file(0);
    349394    } else {
    350395        for (; optind < argc; optind++) {
    351             editing = 1;    // 0=exit, 1=one file, 2+ =many files
    352             free(cfn);
    353             cfn = (Byte *) bb_xstrdup(argv[optind]);
    354             edit_file(cfn);
     396            edit_file(argv[optind]);
    355397        }
    356398    }
    357399    //-----------------------------------------------------------
    358400
    359     return (0);
    360 }
    361 
    362 static void edit_file(Byte * fn)
    363 {
    364     Byte c;
    365     int cnt, size, ch;
    366 
    367 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     401    return 0;
     402}
     403
     404/* read text from file or create an empty buf */
     405/* will also update current_filename */
     406static int init_text_buffer(char *fn)
     407{
     408    int rc;
     409    int size = file_size(fn);   // file size. -1 means does not exist.
     410
     411    /* allocate/reallocate text buffer */
     412    free(text);
     413    text_size = size * 2;
     414    if (text_size < 10240)
     415        text_size = 10240;  // have a minimum size for new files
     416    screenbegin = dot = end = text = xzalloc(text_size);
     417
     418    if (fn != current_filename) {
     419        free(current_filename);
     420        current_filename = xstrdup(fn);
     421    }
     422    if (size < 0) {
     423        // file dont exist. Start empty buf with dummy line
     424        char_insert(text, '\n');
     425        rc = 0;
     426    } else {
     427        rc = file_insert(fn, text
     428            USE_FEATURE_VI_READONLY(, 1));
     429    }
     430    file_modified = 0;
     431    last_file_modified = -1;
     432#if ENABLE_FEATURE_VI_YANKMARK
     433    /* init the marks. */
     434    memset(mark, 0, sizeof(mark));
     435#endif
     436    return rc;
     437}
     438
     439static void edit_file(char * fn)
     440{
     441    char c;
     442    int size;
     443
     444#if ENABLE_FEATURE_VI_USE_SIGNALS
    368445    int sig;
    369 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
    370 #ifdef CONFIG_FEATURE_VI_YANKMARK
    371     static Byte *cur_line;
    372 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    373 
     446#endif
     447#if ENABLE_FEATURE_VI_YANKMARK
     448    static char *cur_line;
     449#endif
     450
     451    editing = 1;    // 0= exit,  1= one file, 2= multiple files
    374452    rawmode();
    375453    rows = 24;
    376454    columns = 80;
    377     ch= -1;
     455    size = 0;
    378456    if (ENABLE_FEATURE_VI_WIN_RESIZE)
    379457        get_terminal_width_height(0, &columns, &rows);
    380458    new_screen(rows, columns);  // get memory for virtual screen
    381 
    382     cnt = file_size(fn);    // file size
    383     size = 2 * cnt;     // 200% of file size
    384     new_text(size);     // get a text[] buffer
    385     screenbegin = dot = end = text;
    386     if (fn != 0) {
    387         ch= file_insert(fn, text, cnt);
    388     }
    389     if (ch < 1) {
    390         (void) char_insert(text, '\n'); // start empty buf with dummy line
    391     }
    392     file_modified = 0;
    393     last_file_modified = -1;
    394 #ifdef CONFIG_FEATURE_VI_YANKMARK
     459    init_text_buffer(fn);
     460
     461#if ENABLE_FEATURE_VI_YANKMARK
    395462    YDreg = 26;         // default Yank/Delete reg
    396463    Ureg = 27;          // hold orig line for "U" cmd
    397     for (cnt = 0; cnt < 28; cnt++) {
    398         mark[cnt] = 0;
    399     }                   // init the marks
    400464    mark[26] = mark[27] = text; // init "previous context"
    401 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     465#endif
    402466
    403467    last_forward_char = last_input_char = '\0';
     
    405469    ccol = 0;
    406470
    407 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     471#if ENABLE_FEATURE_VI_USE_SIGNALS
    408472    catch_sig(0);
    409473    signal(SIGWINCH, winch_sig);
     
    413477        screenbegin = dot = text;
    414478    }
    415 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
    416 
    417     editing = 1;
     479#endif
     480
    418481    cmd_mode = 0;       // 0=command  1=insert  2='R'eplace
    419482    cmdcnt = 0;
     
    421484    offset = 0;         // no horizontal offset
    422485    c = '\0';
    423 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     486#if ENABLE_FEATURE_VI_DOT_CMD
    424487    free(last_modifying_cmd);
    425488    free(ioq_start);
    426     ioq = ioq_start = last_modifying_cmd = 0;
     489    ioq = ioq_start = last_modifying_cmd = NULL;
    427490    adding2q = 0;
    428 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
     491#endif
    429492    redraw(FALSE);          // dont force every col re-draw
    430     show_status_line();
    431 
     493
     494#if ENABLE_FEATURE_VI_COLON
     495    {
     496        char *p, *q;
     497        int n = 0;
     498
     499        while ((p = initial_cmds[n])) {
     500            do {
     501                q = p;
     502                p = strchr(q,'\n');
     503                if (p)
     504                    while (*p == '\n')
     505                        *p++ = '\0';
     506                if (*q)
     507                    colon(q);
     508            } while (p);
     509            free(initial_cmds[n]);
     510            initial_cmds[n] = NULL;
     511            n++;
     512        }
     513    }
     514#endif
    432515    //------This is the main Vi cmd handling loop -----------------------
    433516    while (editing > 0) {
    434 #ifdef CONFIG_FEATURE_VI_CRASHME
     517#if ENABLE_FEATURE_VI_CRASHME
    435518        if (crashme > 0) {
    436519            if ((end - text) > 1) {
     
    438521            } else {
    439522                crashme = 0;
    440                 dot =
    441                     string_insert(text, (Byte *) "\n\n#####  Ran out of text to work on.  #####\n\n");  // insert the string
     523                dot = string_insert(text, "\n\n#####  Ran out of text to work on.  #####\n\n"); // insert the string
    442524                refresh(FALSE);
    443525            }
    444526        }
    445 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
     527#endif
    446528        last_input_char = c = get_one_char();   // get a cmd from user
    447 #ifdef CONFIG_FEATURE_VI_YANKMARK
     529#if ENABLE_FEATURE_VI_YANKMARK
    448530        // save a copy of the current line- for the 'U" command
    449531        if (begin_line(dot) != cur_line) {
     
    451533            text_yank(begin_line(dot), end_line(dot), Ureg);
    452534        }
    453 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    454 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     535#endif
     536#if ENABLE_FEATURE_VI_DOT_CMD
    455537        // These are commands that change text[].
    456538        // Remember the input for the "." command
    457539        if (!adding2q && ioq_start == 0
    458             && strchr((char *) modifying_cmds, c) != NULL) {
     540         && strchr(modifying_cmds, c)
     541        ) {
    459542            start_new_cmd_q(c);
    460543        }
    461 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
     544#endif
    462545        do_cmd(c);      // execute the user command
    463546        //
     
    470553            show_status_line();
    471554        }
    472 #ifdef CONFIG_FEATURE_VI_CRASHME
     555#if ENABLE_FEATURE_VI_CRASHME
    473556        if (crashme > 0)
    474557            crash_test();   // test editor variables
    475 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
     558#endif
    476559    }
    477560    //-------------------------------------------------------------------
     
    483566
    484567//----- The Colon commands -------------------------------------
    485 #ifdef CONFIG_FEATURE_VI_COLON
    486 static Byte *get_one_address(Byte * p, int *addr)   // get colon addr, if present
     568#if ENABLE_FEATURE_VI_COLON
     569static char *get_one_address(char * p, int *addr)   // get colon addr, if present
    487570{
    488571    int st;
    489     Byte *q;
    490 
    491 #ifdef CONFIG_FEATURE_VI_YANKMARK
    492     Byte c;
    493 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    494 #ifdef CONFIG_FEATURE_VI_SEARCH
    495     Byte *pat, buf[BUFSIZ];
    496 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
     572    char *q;
     573
     574#if ENABLE_FEATURE_VI_YANKMARK
     575    char c;
     576#endif
     577#if ENABLE_FEATURE_VI_SEARCH
     578    char *pat, buf[MAX_LINELEN];
     579#endif
    497580
    498581    *addr = -1;         // assume no addr
     
    501584        q = begin_line(dot);
    502585        *addr = count_lines(text, q);
    503 #ifdef CONFIG_FEATURE_VI_YANKMARK
     586#if ENABLE_FEATURE_VI_YANKMARK
    504587    } else if (*p == '\'') {    // is this a mark addr
    505588        p++;
     
    509592            // we have a mark
    510593            c = c - 'a';
    511             q = mark[(int) c];
     594            q = mark[(unsigned char) c];
    512595            if (q != NULL) {    // is mark valid
    513596                *addr = count_lines(text, q);   // count lines
    514597            }
    515598        }
    516 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    517 #ifdef CONFIG_FEATURE_VI_SEARCH
     599#endif
     600#if ENABLE_FEATURE_VI_SEARCH
    518601    } else if (*p == '/') { // a search pattern
    519602        q = buf;
     
    524607            *q = '\0';
    525608        }
    526         pat = (Byte *) bb_xstrdup((char *) buf);    // save copy of pattern
     609        pat = xstrdup(buf); // save copy of pattern
    527610        if (*p == '/')
    528611            p++;
     
    532615        }
    533616        free(pat);
    534 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
     617#endif
    535618    } else if (*p == '$') { // the last line in file
    536619        p++;
     
    538621        *addr = count_lines(text, q);
    539622    } else if (isdigit(*p)) {   // specific line number
    540         sscanf((char *) p, "%d%n", addr, &st);
     623        sscanf(p, "%d%n", addr, &st);
    541624        p += st;
    542625    } else {            // I don't reconise this
     
    544627        *addr = -1;
    545628    }
    546     return (p);
    547 }
    548 
    549 static Byte *get_address(Byte *p, int *b, int *e)   // get two colon addrs, if present
     629    return p;
     630}
     631
     632static char *get_address(char *p, int *b, int *e)   // get two colon addrs, if present
    550633{
    551634    //----- get the address' i.e., 1,3   'a,'b  -----
    552635    // get FIRST addr, if present
    553     while (isblnk(*p))
     636    while (isblank(*p))
    554637        p++;                // skip over leading spaces
    555638    if (*p == '%') {            // alias for 1,$
     
    560643    }
    561644    p = get_one_address(p, b);
    562     while (isblnk(*p))
     645    while (isblank(*p))
    563646        p++;
    564647    if (*p == ',') {            // is there a address separator
    565648        p++;
    566         while (isblnk(*p))
     649        while (isblank(*p))
    567650            p++;
    568651        // get SECOND addr, if present
    569652        p = get_one_address(p, e);
    570653    }
    571 ga0:
    572     while (isblnk(*p))
     654 ga0:
     655    while (isblank(*p))
    573656        p++;                // skip over trailing spaces
    574     return (p);
    575 }
    576 
    577 #ifdef CONFIG_FEATURE_VI_SETOPTS
    578 static void setops(const Byte *args, const char *opname, int flg_no,
     657    return p;
     658}
     659
     660#if ENABLE_FEATURE_VI_SET && ENABLE_FEATURE_VI_SETOPTS
     661static void setops(const char *args, const char *opname, int flg_no,
    579662            const char *short_opname, int opt)
    580663{
    581     const char *a = (char *) args + flg_no;
     664    const char *a = args + flg_no;
    582665    int l = strlen(opname) - 1; /* opname have + ' ' */
    583666
    584     if (strncasecmp(a, opname, l) == 0 ||
    585             strncasecmp(a, short_opname, 2) == 0) {
    586         if(flg_no)
     667    if (strncasecmp(a, opname, l) == 0
     668     || strncasecmp(a, short_opname, 2) == 0
     669    ) {
     670        if (flg_no)
    587671            vi_setops &= ~opt;
    588          else
     672        else
    589673            vi_setops |= opt;
    590674    }
     
    592676#endif
    593677
    594 static void colon(Byte * buf)
    595 {
    596     Byte c, *orig_buf, *buf1, *q, *r;
    597     Byte *fn, cmd[BUFSIZ], args[BUFSIZ];
    598     int i, l, li, ch, st, b, e;
     678static void colon(char * buf)
     679{
     680    char c, *orig_buf, *buf1, *q, *r;
     681    char *fn, cmd[MAX_LINELEN], args[MAX_LINELEN];
     682    int i, l, li, ch, b, e;
    599683    int useforce = FALSE, forced = FALSE;
    600     struct stat st_buf;
    601684
    602685    // :3154    // if (-e line 3154) goto it  else stay put
     
    615698    //
    616699
    617     if (strlen((char *) buf) <= 0)
     700    if (!buf[0])
    618701        goto vc1;
    619702    if (*buf == ':')
    620703        buf++;          // move past the ':'
    621704
    622     li = st = ch = i = 0;
     705    li = ch = i = 0;
    623706    b = e = -1;
    624707    q = text;           // assume 1,$ for the range
    625708    r = end - 1;
    626709    li = count_lines(text, end - 1);
    627     fn = cfn;           // default to current file
    628     memset(cmd, '\0', BUFSIZ);  // clear cmd[]
    629     memset(args, '\0', BUFSIZ); // clear args[]
     710    fn = current_filename;          // default to current file
     711    memset(cmd, '\0', MAX_LINELEN); // clear cmd[]
     712    memset(args, '\0', MAX_LINELEN);    // clear args[]
    630713
    631714    // look for optional address(es)  :.  :1  :1,9   :'q,'a   :%
     
    643726    }
    644727    // get any ARGuments
    645     while (isblnk(*buf))
     728    while (isblank(*buf))
    646729        buf++;
    647     strcpy((char *) args, (char *) buf);
    648     buf1 = (Byte*)last_char_is((char *)cmd, '!');
     730    strcpy(args, buf);
     731    buf1 = last_char_is(cmd, '!');
    649732    if (buf1) {
    650733        useforce = TRUE;
     
    668751    }
    669752    // ------------ now look for the command ------------
    670     i = strlen((char *) cmd);
     753    i = strlen(cmd);
    671754    if (i == 0) {       // :123CR goto line #123
    672755        if (b >= 0) {
     
    674757            dot_skip_over_ws();
    675758        }
    676     } else if (strncmp((char *) cmd, "!", 1) == 0) {    // run a cmd
     759    }
     760#if ENABLE_FEATURE_ALLOW_EXEC
     761    else if (strncmp(cmd, "!", 1) == 0) {   // run a cmd
     762        int retcode;
    677763        // :!ls   run the <cmd>
    678         (void) alarm(0);        // wait for input- no alarms
     764        alarm(0);       // wait for input- no alarms
    679765        place_cursor(rows - 1, 0, FALSE);   // go to Status line
    680766        clear_to_eol();         // clear the line
    681767        cookmode();
    682         system((char*)(orig_buf+1));        // run the cmd
     768        retcode = system(orig_buf + 1); // run the cmd
     769        if (retcode)
     770            printf("\nshell returned %i\n\n", retcode);
    683771        rawmode();
    684772        Hit_Return();           // let user see results
    685         (void) alarm(3);        // done waiting for input
    686     } else if (strncmp((char *) cmd, "=", i) == 0) {    // where is the address
     773        alarm(3);       // done waiting for input
     774    }
     775#endif
     776    else if (strncmp(cmd, "=", i) == 0) {   // where is the address
    687777        if (b < 0) {    // no addr given- use defaults
    688778            b = e = count_lines(text, dot);
    689779        }
    690780        psb("%d", b);
    691     } else if (strncasecmp((char *) cmd, "delete", i) == 0) {   // delete lines
     781    } else if (strncasecmp(cmd, "delete", i) == 0) {    // delete lines
    692782        if (b < 0) {    // no addr given- use defaults
    693783            q = begin_line(dot);    // assume .,. for the range
     
    696786        dot = yank_delete(q, r, 1, YANKDEL);    // save, then delete lines
    697787        dot_skip_over_ws();
    698     } else if (strncasecmp((char *) cmd, "edit", i) == 0) { // Edit a file
    699         int sr;
    700         sr= 0;
     788    } else if (strncasecmp(cmd, "edit", i) == 0) {  // Edit a file
    701789        // don't edit, if the current file has been modified
    702790        if (file_modified && ! useforce) {
     
    704792            goto vc1;
    705793        }
    706         if (strlen((char*)args) > 0) {
     794        if (args[0]) {
    707795            // the user supplied a file name
    708             fn= args;
    709         } else if (cfn != 0 && strlen((char*)cfn) > 0) {
     796            fn = args;
     797        } else if (current_filename && current_filename[0]) {
    710798            // no user supplied name- use the current filename
    711             fn= cfn;
    712             goto vc5;
     799            // fn = current_filename;  was set by default
    713800        } else {
    714801            // no user file name, no current name- punt
     
    717804        }
    718805
    719         // see if file exists- if not, its just a new file request
    720         if ((sr=stat((char*)fn, &st_buf)) < 0) {
    721             // This is just a request for a new file creation.
    722             // The file_insert below will fail but we get
    723             // an empty buffer with a file name.  Then the "write"
    724             // command can do the create.
    725         } else {
    726             if ((st_buf.st_mode & (S_IFREG)) == 0) {
    727                 // This is not a regular file
    728                 psbs("\"%s\" is not a regular file", fn);
    729                 goto vc1;
    730             }
    731             if ((st_buf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
    732                 // dont have any read permissions
    733                 psbs("\"%s\" is not readable", fn);
    734                 goto vc1;
    735             }
    736         }
    737 
    738         // There is a read-able regular file
    739         // make this the current file
    740         q = (Byte *) bb_xstrdup((char *) fn);   // save the cfn
    741         free(cfn);      // free the old name
    742         cfn = q;            // remember new cfn
    743 
    744       vc5:
    745         // delete all the contents of text[]
    746         new_text(2 * file_size(fn));
    747         screenbegin = dot = end = text;
    748 
    749         // insert new file
    750         ch = file_insert(fn, text, file_size(fn));
    751 
    752         if (ch < 1) {
    753             // start empty buf with dummy line
    754             (void) char_insert(text, '\n');
    755             ch= 1;
    756         }
    757         file_modified = 0;
    758         last_file_modified = -1;
    759 #ifdef CONFIG_FEATURE_VI_YANKMARK
     806        if (init_text_buffer(fn) < 0)
     807            goto vc1;
     808
     809#if ENABLE_FEATURE_VI_YANKMARK
    760810        if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) {
    761811            free(reg[Ureg]);    //   free orig line reg- for 'U'
     
    766816            reg[YDreg]= 0;
    767817        }
    768         for (li = 0; li < 28; li++) {
    769             mark[li] = 0;
    770         }               // init the marks
    771 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     818#endif
    772819        // how many lines in text[]?
    773820        li = count_lines(text, end - 1);
    774821        psb("\"%s\"%s"
    775 #ifdef CONFIG_FEATURE_VI_READONLY
    776             "%s"
    777 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    778             " %dL, %dC", cfn,
    779             (sr < 0 ? " [New file]" : ""),
    780 #ifdef CONFIG_FEATURE_VI_READONLY
    781             ((vi_readonly || readonly) ? " [Read only]" : ""),
    782 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     822            USE_FEATURE_VI_READONLY("%s")
     823            " %dL, %dC", current_filename,
     824            (file_size(fn) < 0 ? " [New file]" : ""),
     825            USE_FEATURE_VI_READONLY(
     826                ((readonly_mode) ? " [Readonly]" : ""),
     827            )
    783828            li, ch);
    784     } else if (strncasecmp((char *) cmd, "file", i) == 0) { // what File is this
     829    } else if (strncasecmp(cmd, "file", i) == 0) {  // what File is this
    785830        if (b != -1 || e != -1) {
    786             ni((Byte *) "No address allowed on this command");
     831            ni("No address allowed on this command");
    787832            goto vc1;
    788833        }
    789         if (strlen((char *) args) > 0) {
     834        if (args[0]) {
    790835            // user wants a new filename
    791             free(cfn);
    792             cfn = (Byte *) bb_xstrdup((char *) args);
     836            free(current_filename);
     837            current_filename = xstrdup(args);
    793838        } else {
    794839            // user wants file status info
    795840            last_status_cksum = 0;  // force status update
    796841        }
    797     } else if (strncasecmp((char *) cmd, "features", i) == 0) { // what features are available
     842    } else if (strncasecmp(cmd, "features", i) == 0) {  // what features are available
    798843        // print out values of all features
    799844        place_cursor(rows - 1, 0, FALSE);   // go to Status line, bottom of screen
     
    803848        rawmode();
    804849        Hit_Return();
    805     } else if (strncasecmp((char *) cmd, "list", i) == 0) { // literal print line
     850    } else if (strncasecmp(cmd, "list", i) == 0) {  // literal print line
    806851        if (b < 0) {    // no addr given- use defaults
    807852            q = begin_line(dot);    // assume .,. for the range
     
    815860
    816861            c = *q;
    817             c_is_no_print = c > 127 && !Isprint(c);
     862            c_is_no_print = (c & 0x80) && !Isprint(c);
    818863            if (c_is_no_print) {
    819864                c = '.';
     
    824869            } else if (c < ' ' || c == 127) {
    825870                putchar('^');
    826                 if(c == 127)
     871                if (c == 127)
    827872                    c = '?';
    828                  else
    829                 c += '@';
     873                else
     874                    c += '@';
    830875            }
    831876            putchar(c);
     
    833878                standout_end();
    834879        }
    835 #ifdef CONFIG_FEATURE_VI_SET
    836       vc2:
    837 #endif                          /* CONFIG_FEATURE_VI_SET */
     880#if ENABLE_FEATURE_VI_SET
     881 vc2:
     882#endif
    838883        Hit_Return();
    839     } else if ((strncasecmp((char *) cmd, "quit", i) == 0) ||   // Quit
    840                (strncasecmp((char *) cmd, "next", i) == 0)) {   // edit next file
     884    } else if (strncasecmp(cmd, "quit", i) == 0 // Quit
     885            || strncasecmp(cmd, "next", i) == 0 // edit next file
     886    ) {
    841887        if (useforce) {
    842888            // force end of argv list
     
    863909        }
    864910        editing = 0;
    865     } else if (strncasecmp((char *) cmd, "read", i) == 0) { // read file into text[]
     911    } else if (strncasecmp(cmd, "read", i) == 0) {  // read file into text[]
    866912        fn = args;
    867         if (strlen((char *) fn) <= 0) {
     913        if (!fn[0]) {
    868914            psbs("No filename given");
    869915            goto vc1;
     
    875921        if (b != 0)
    876922            q = next_line(q);
    877 #ifdef CONFIG_FEATURE_VI_READONLY
    878         l= readonly;            // remember current files' status
    879 #endif
    880         ch = file_insert(fn, q, file_size(fn));
    881 #ifdef CONFIG_FEATURE_VI_READONLY
    882         readonly= l;
    883 #endif
     923        ch = file_insert(fn, q  USE_FEATURE_VI_READONLY(, 0));
    884924        if (ch < 0)
    885925            goto vc1;   // nothing was inserted
     
    887927        li = count_lines(q, q + ch - 1);
    888928        psb("\"%s\""
    889 #ifdef CONFIG_FEATURE_VI_READONLY
    890             "%s"
    891 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     929            USE_FEATURE_VI_READONLY("%s")
    892930            " %dL, %dC", fn,
    893 #ifdef CONFIG_FEATURE_VI_READONLY
    894             ((vi_readonly || readonly) ? " [Read only]" : ""),
    895 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     931            USE_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),)
    896932            li, ch);
    897933        if (ch > 0) {
     
    901937            file_modified++;
    902938        }
    903     } else if (strncasecmp((char *) cmd, "rewind", i) == 0) {   // rewind cmd line args
     939    } else if (strncasecmp(cmd, "rewind", i) == 0) {    // rewind cmd line args
    904940        if (file_modified && ! useforce) {
    905941            psbs("No write since last change (:rewind! overrides)");
     
    909945            editing = 0;
    910946        }
    911 #ifdef CONFIG_FEATURE_VI_SET
    912     } else if (strncasecmp((char *) cmd, "set", i) == 0) {  // set or clear features
     947#if ENABLE_FEATURE_VI_SET
     948    } else if (strncasecmp(cmd, "set", i) == 0) {   // set or clear features
     949#if ENABLE_FEATURE_VI_SETOPTS
     950        char *argp;
     951#endif
    913952        i = 0;          // offset into args
    914         if (strlen((char *) args) == 0) {
     953        // only blank is regarded as args delmiter. What about tab '\t' ?
     954        if (!args[0] || strcasecmp(args, "all") == 0) {
    915955            // print out values of all options
    916956            place_cursor(rows - 1, 0, FALSE);   // go to Status line, bottom of screen
    917957            clear_to_eol(); // clear the line
    918958            printf("----------------------------------------\r\n");
    919 #ifdef CONFIG_FEATURE_VI_SETOPTS
     959#if ENABLE_FEATURE_VI_SETOPTS
    920960            if (!autoindent)
    921961                printf("no");
     
    931971            printf("showmatch ");
    932972            printf("tabstop=%d ", tabstop);
    933 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
     973#endif
    934974            printf("\r\n");
    935975            goto vc2;
    936976        }
    937         if (strncasecmp((char *) args, "no", 2) == 0)
    938             i = 2;      // ":set noautoindent"
    939 #ifdef CONFIG_FEATURE_VI_SETOPTS
    940         setops(args, "autoindent ", i, "ai", VI_AUTOINDENT);
    941         setops(args, "flash ", i, "fl", VI_ERR_METHOD);
    942         setops(args, "ignorecase ", i, "ic", VI_IGNORECASE);
    943         setops(args, "showmatch ", i, "ic", VI_SHOWMATCH);
    944         if (strncasecmp((char *) args + i, "tabstop=%d ", 7) == 0) {
    945             sscanf(strchr((char *) args + i, '='), "=%d", &ch);
    946             if (ch > 0 && ch < columns - 1)
    947                 tabstop = ch;
    948         }
    949 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
    950 #endif                          /* CONFIG_FEATURE_VI_SET */
    951 #ifdef CONFIG_FEATURE_VI_SEARCH
    952     } else if (strncasecmp((char *) cmd, "s", 1) == 0) {    // substitute a pattern with a replacement pattern
    953         Byte *ls, *F, *R;
     977#if ENABLE_FEATURE_VI_SETOPTS
     978        argp = args;
     979        while (*argp) {
     980            if (strncasecmp(argp, "no", 2) == 0)
     981                i = 2;      // ":set noautoindent"
     982            setops(argp, "autoindent ", i, "ai", VI_AUTOINDENT);
     983            setops(argp, "flash ", i, "fl", VI_ERR_METHOD);
     984            setops(argp, "ignorecase ", i, "ic", VI_IGNORECASE);
     985            setops(argp, "showmatch ", i, "ic", VI_SHOWMATCH);
     986            /* tabstopXXXX */
     987            if (strncasecmp(argp + i, "tabstop=%d ", 7) == 0) {
     988                sscanf(strchr(argp + i, '='), "tabstop=%d" + 7, &ch);
     989                if (ch > 0 && ch < columns - 1)
     990                    tabstop = ch;
     991            }
     992            while (*argp && *argp != ' ')
     993                argp++; // skip to arg delimiter (i.e. blank)
     994            while (*argp && *argp == ' ')
     995                argp++; // skip all delimiting blanks
     996        }
     997#endif /* FEATURE_VI_SETOPTS */
     998#endif /* FEATURE_VI_SET */
     999#if ENABLE_FEATURE_VI_SEARCH
     1000    } else if (strncasecmp(cmd, "s", 1) == 0) { // substitute a pattern with a replacement pattern
     1001        char *ls, *F, *R;
    9541002        int gflag;
    9551003
     
    9601008        c = orig_buf[1];    // what is the delimiter
    9611009        F = orig_buf + 2;   // start of "find"
    962         R = (Byte *) strchr((char *) F, c); // middle delimiter
     1010        R = strchr(F, c);   // middle delimiter
    9631011        if (!R) goto colon_s_fail;
    9641012        *R++ = '\0';    // terminate "find"
    965         buf1 = (Byte *) strchr((char *) R, c);
     1013        buf1 = strchr(R, c);
    9661014        if (!buf1) goto colon_s_fail;
    9671015        *buf1++ = '\0'; // terminate "replace"
     
    9791027        for (i = b; i <= e; i++) {  // so, :20,23 s \0 find \0 replace \0
    9801028            ls = q;     // orig line start
    981           vc4:
     1029 vc4:
    9821030            buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find"
    983             if (buf1 != NULL) {
    984                 // we found the "find" pattern- delete it
    985                 (void) text_hole_delete(buf1, buf1 + strlen((char *) F) - 1);
     1031            if (buf1) {
     1032                // we found the "find" pattern - delete it
     1033                text_hole_delete(buf1, buf1 + strlen(F) - 1);
    9861034                // inset the "replace" patern
    987                 (void) string_insert(buf1, R);  // insert the string
     1035                string_insert(buf1, R); // insert the string
    9881036                // check for "global"  :s/foo/bar/g
    9891037                if (gflag == 1) {
    990                     if ((buf1 + strlen((char *) R)) < end_line(ls)) {
    991                         q = buf1 + strlen((char *) R);
     1038                    if ((buf1 + strlen(R)) < end_line(ls)) {
     1039                        q = buf1 + strlen(R);
    9921040                        goto vc4;   // don't let q move past cur line
    9931041                    }
     
    9961044            q = next_line(ls);
    9971045        }
    998 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
    999     } else if (strncasecmp((char *) cmd, "version", i) == 0) {  // show software version
    1000         psb("%s", vi_Version);
    1001     } else if (strncasecmp((char *) cmd, "write", i) == 0       // write text to file
    1002             || strncasecmp((char *) cmd, "wq", i) == 0
    1003             || strncasecmp((char *) cmd, "wn", i) == 0
    1004             || strncasecmp((char *) cmd, "x", i) == 0) {
     1046#endif /* FEATURE_VI_SEARCH */
     1047    } else if (strncasecmp(cmd, "version", i) == 0) {  // show software version
     1048        psb("%s", BB_VER " " BB_BT);
     1049    } else if (strncasecmp(cmd, "write", i) == 0  // write text to file
     1050            || strncasecmp(cmd, "wq", i) == 0
     1051            || strncasecmp(cmd, "wn", i) == 0
     1052            || strncasecmp(cmd, "x", i) == 0
     1053    ) {
    10051054        // is there a file name to write to?
    1006         if (strlen((char *) args) > 0) {
     1055        if (args[0]) {
    10071056            fn = args;
    10081057        }
    1009 #ifdef CONFIG_FEATURE_VI_READONLY
    1010         if ((vi_readonly || readonly) && ! useforce) {
     1058#if ENABLE_FEATURE_VI_READONLY
     1059        if (readonly_mode && !useforce) {
    10111060            psbs("\"%s\" File is read only", fn);
    10121061            goto vc3;
    10131062        }
    1014 #endif                          /* CONFIG_FEATURE_VI_READONLY */
     1063#endif
    10151064        // how many lines in text[]?
    10161065        li = count_lines(q, r);
     
    10321081        if (l < 0) {
    10331082            if (l == -1)
    1034                 psbs("Write error: %s", strerror(errno));
     1083                psbs("\"%s\" %s", fn, strerror(errno));
    10351084        } else {
    10361085            psb("\"%s\" %dL, %dC", fn, li, l);
     
    10451094            }
    10461095        }
    1047 #ifdef CONFIG_FEATURE_VI_READONLY
    1048       vc3:;
    1049 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    1050 #ifdef CONFIG_FEATURE_VI_YANKMARK
    1051     } else if (strncasecmp((char *) cmd, "yank", i) == 0) { // yank lines
     1096#if ENABLE_FEATURE_VI_READONLY
     1097 vc3:;
     1098#endif
     1099#if ENABLE_FEATURE_VI_YANKMARK
     1100    } else if (strncasecmp(cmd, "yank", i) == 0) {  // yank lines
    10521101        if (b < 0) {    // no addr given- use defaults
    10531102            q = begin_line(dot);    // assume .,. for the range
     
    10571106        li = count_lines(q, r);
    10581107        psb("Yank %d lines (%d chars) into [%c]",
    1059             li, strlen((char *) reg[YDreg]), what_reg());
    1060 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     1108                li, strlen(reg[YDreg]), what_reg());
     1109#endif
    10611110    } else {
    10621111        // cmd unknown
    1063         ni((Byte *) cmd);
    1064     }
    1065   vc1:
     1112        ni(cmd);
     1113    }
     1114 vc1:
    10661115    dot = bound_dot(dot);   // make sure "dot" is valid
    10671116    return;
    1068 #ifdef CONFIG_FEATURE_VI_SEARCH
    1069 colon_s_fail:
     1117#if ENABLE_FEATURE_VI_SEARCH
     1118 colon_s_fail:
    10701119    psb(":s expression missing delimiters");
    10711120#endif
    10721121}
    10731122
    1074 #endif                          /* CONFIG_FEATURE_VI_COLON */
     1123#endif /* FEATURE_VI_COLON */
    10751124
    10761125static void Hit_Return(void)
     
    10861135}
    10871136
     1137static int next_tabstop(int col)
     1138{
     1139    return col + ((tabstop - 1) - (col % tabstop));
     1140}
     1141
    10881142//----- Synchronize the cursor to Dot --------------------------
    1089 static void sync_cursor(Byte * d, int *row, int *col)
    1090 {
    1091     Byte *beg_cur;              // begin and end of "d" line
    1092     Byte *beg_scr, *end_scr;    // begin and end of screen
    1093     Byte *tp;
     1143static void sync_cursor(char * d, int *row, int *col)
     1144{
     1145    char *beg_cur;  // begin and end of "d" line
     1146    char *end_scr;  // begin and end of screen
     1147    char *tp;
    10941148    int cnt, ro, co;
    10951149
    10961150    beg_cur = begin_line(d);    // first char of cur line
    10971151
    1098     beg_scr = end_scr = screenbegin;    // first char of screen
    10991152    end_scr = end_screen(); // last char of screen
    11001153
     
    11031156        // how many lines do we have to move
    11041157        cnt = count_lines(beg_cur, screenbegin);
    1105       sc1:
     1158 sc1:
    11061159        screenbegin = beg_cur;
    11071160        if (cnt > (rows - 1) / 2) {
     
    11391192            break;
    11401193        if (*tp == '\t') {
    1141             //         7       - (co %    8  )
    1142             co += ((tabstop - 1) - (co % tabstop));
     1194            if (d == tp && cmd_mode) { /* handle tabs like real vi */
     1195                break;
     1196            } else {
     1197                co = next_tabstop(co);
     1198            }
    11431199        } else if (*tp < ' ' || *tp == 127) {
    11441200            co++;       // display as ^X, use 2 columns
     
    11771233
    11781234//----- Text Movement Routines ---------------------------------
    1179 static Byte *begin_line(Byte * p) // return pointer to first char cur line
     1235static char *begin_line(char * p) // return pointer to first char cur line
    11801236{
    11811237    while (p > text && p[-1] != '\n')
    11821238        p--;            // go to cur line B-o-l
    1183     return (p);
    1184 }
    1185 
    1186 static Byte *end_line(Byte * p) // return pointer to NL of cur line line
     1239    return p;
     1240}
     1241
     1242static char *end_line(char * p) // return pointer to NL of cur line line
    11871243{
    11881244    while (p < end - 1 && *p != '\n')
    11891245        p++;            // go to cur line E-o-l
    1190     return (p);
    1191 }
    1192 
    1193 static inline Byte *dollar_line(Byte * p) // return pointer to just before NL line
     1246    return p;
     1247}
     1248
     1249static inline char *dollar_line(char * p) // return pointer to just before NL line
    11941250{
    11951251    while (p < end - 1 && *p != '\n')
     
    11981254    if (*p == '\n' && (p - begin_line(p)) > 0)
    11991255        p--;
    1200     return (p);
    1201 }
    1202 
    1203 static Byte *prev_line(Byte * p) // return pointer first char prev line
     1256    return p;
     1257}
     1258
     1259static char *prev_line(char * p) // return pointer first char prev line
    12041260{
    12051261    p = begin_line(p);  // goto begining of cur line
     
    12071263        p--;            // step to prev line
    12081264    p = begin_line(p);  // goto begining of prev line
    1209     return (p);
    1210 }
    1211 
    1212 static Byte *next_line(Byte * p) // return pointer first char next line
     1265    return p;
     1266}
     1267
     1268static char *next_line(char * p) // return pointer first char next line
    12131269{
    12141270    p = end_line(p);
    12151271    if (*p == '\n' && p < end - 1)
    12161272        p++;            // step to next line
    1217     return (p);
     1273    return p;
    12181274}
    12191275
    12201276//----- Text Information Routines ------------------------------
    1221 static Byte *end_screen(void)
    1222 {
    1223     Byte *q;
     1277static char *end_screen(void)
     1278{
     1279    char *q;
    12241280    int cnt;
    12251281
     
    12291285        q = next_line(q);
    12301286    q = end_line(q);
    1231     return (q);
    1232 }
    1233 
    1234 static int count_lines(Byte * start, Byte * stop) // count line from start to stop
    1235 {
    1236     Byte *q;
     1287    return q;
     1288}
     1289
     1290static int count_lines(char * start, char * stop) // count line from start to stop
     1291{
     1292    char *q;
    12371293    int cnt;
    12381294
     
    12481304            cnt++;
    12491305    }
    1250     return (cnt);
    1251 }
    1252 
    1253 static Byte *find_line(int li)  // find begining of line #li
    1254 {
    1255     Byte *q;
     1306    return cnt;
     1307}
     1308
     1309static char *find_line(int li)  // find begining of line #li
     1310{
     1311    char *q;
    12561312
    12571313    for (q = text; li > 1; li--) {
    12581314        q = next_line(q);
    12591315    }
    1260     return (q);
     1316    return q;
    12611317}
    12621318
     
    12841340}
    12851341
    1286 static Byte *move_to_col(Byte * p, int l)
     1342static char *move_to_col(char * p, int l)
    12871343{
    12881344    int co;
     
    12941350            break;
    12951351        if (*p == '\t') {
    1296             //         7       - (co %    8  )
    1297             co += ((tabstop - 1) - (co % tabstop));
     1352            co = next_tabstop(co);
    12981353        } else if (*p < ' ' || *p == 127) {
    12991354            co++;       // display as ^X, use 2 columns
    13001355        }
    13011356    } while (++co <= l && p++ < end);
    1302     return (p);
     1357    return p;
    13031358}
    13041359
     
    13151370static void dot_scroll(int cnt, int dir)
    13161371{
    1317     Byte *q;
     1372    char *q;
    13181373
    13191374    for (; cnt > 0; cnt--) {
     
    13461401static void dot_delete(void)    // delete the char at 'dot'
    13471402{
    1348     (void) text_hole_delete(dot, dot);
    1349 }
    1350 
    1351 static Byte *bound_dot(Byte * p) // make sure  text[0] <= P < "end"
     1403    text_hole_delete(dot, dot);
     1404}
     1405
     1406static char *bound_dot(char * p) // make sure  text[0] <= P < "end"
    13521407{
    13531408    if (p >= end && end > text) {
     
    13591414        indicate_error('2');
    13601415    }
    1361     return (p);
     1416    return p;
    13621417}
    13631418
     
    13751430 */
    13761431
    1377 static Byte *new_screen(int ro, int co)
     1432static char *new_screen(int ro, int co)
    13781433{
    13791434    int li;
     
    13811436    free(screen);
    13821437    screensize = ro * co + 8;
    1383     screen = (Byte *) xmalloc(screensize);
     1438    screen = xmalloc(screensize);
    13841439    // initialize the new screen. assume this will be a empty file.
    13851440    screen_erase();
     
    13881443        screen[(li * co) + 0] = '~';
    13891444    }
    1390     return (screen);
    1391 }
    1392 
    1393 static Byte *new_text(int size)
    1394 {
    1395     if (size < 10240)
    1396         size = 10240;   // have a minimum size for new files
    1397     free(text);
    1398     text = (Byte *) xmalloc(size + 8);
    1399     memset(text, '\0', size);   // clear new text[]
    1400     //text += 4;        // leave some room for "oops"
    1401     textend = text + size - 1;
    1402     //textend -= 4;     // leave some root for "oops"
    1403     return (text);
    1404 }
    1405 
    1406 #ifdef CONFIG_FEATURE_VI_SEARCH
    1407 static int mycmp(Byte * s1, Byte * s2, int len)
     1445    return screen;
     1446}
     1447
     1448#if ENABLE_FEATURE_VI_SEARCH
     1449static int mycmp(const char * s1, const char * s2, int len)
    14081450{
    14091451    int i;
    14101452
    1411     i = strncmp((char *) s1, (char *) s2, len);
    1412 #ifdef CONFIG_FEATURE_VI_SETOPTS
    1413     if (ignorecase) {
    1414         i = strncasecmp((char *) s1, (char *) s2, len);
    1415     }
    1416 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
    1417     return (i);
    1418 }
    1419 
    1420 static Byte *char_search(Byte * p, Byte * pat, int dir, int range)  // search for pattern starting at p
     1453    i = strncmp(s1, s2, len);
     1454    if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) {
     1455        i = strncasecmp(s1, s2, len);
     1456    }
     1457    return i;
     1458}
     1459
     1460// search for pattern starting at p
     1461static char *char_search(char * p, const char * pat, int dir, int range)
    14211462{
    14221463#ifndef REGEX_SEARCH
    1423     Byte *start, *stop;
     1464    char *start, *stop;
    14241465    int len;
    14251466
    1426     len = strlen((char *) pat);
     1467    len = strlen(pat);
    14271468    if (dir == FORWARD) {
    14281469        stop = end - 1; // assume range is p - end-1
     
    14311472        for (start = p; start < stop; start++) {
    14321473            if (mycmp(start, pat, len) == 0) {
    1433                 return (start);
     1474                return start;
    14341475            }
    14351476        }
     
    14401481        for (start = p - len; start >= stop; start--) {
    14411482            if (mycmp(start, pat, len) == 0) {
    1442                 return (start);
     1483                return start;
    14431484            }
    14441485        }
    14451486    }
    14461487    // pattern not found
    1447     return (NULL);
    1448 #else                           /*REGEX_SEARCH */
     1488    return NULL;
     1489#else /* REGEX_SEARCH */
    14491490    char *q;
    14501491    struct re_pattern_buffer preg;
     
    14731514    range = q - p;
    14741515
    1475     q = (char *) re_compile_pattern(pat, strlen((char *) pat), &preg);
     1516    q = re_compile_pattern(pat, strlen(pat), &preg);
    14761517    if (q != 0) {
    14771518        // The pattern was not compiled
     
    15001541        i = 0;          // return NULL if pattern not found
    15011542    }
    1502   cs1:
     1543 cs1:
    15031544    if (dir == FORWARD) {
    15041545        p = p + i;
     
    15061547        p = p - i;
    15071548    }
    1508     return (p);
    1509 #endif                          /*REGEX_SEARCH */
    1510 }
    1511 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
    1512 
    1513 static Byte *char_insert(Byte * p, Byte c) // insert the char c at 'p'
     1549    return p;
     1550#endif /* REGEX_SEARCH */
     1551}
     1552#endif /* FEATURE_VI_SEARCH */
     1553
     1554static char *char_insert(char * p, char c) // insert the char c at 'p'
    15141555{
    15151556    if (c == 22) {      // Is this an ctrl-V?
     
    15261567        end_cmd_q();    // stop adding to q
    15271568        last_status_cksum = 0;  // force status update
    1528         if ((p[-1] != '\n') && (dot>text)) {
     1569        if ((p[-1] != '\n') && (dot > text)) {
    15291570            p--;
    15301571        }
     
    15371578    } else {
    15381579        // insert a char into text[]
    1539         Byte *sp;       // "save p"
     1580        char *sp;       // "save p"
    15401581
    15411582        if (c == 13)
     
    15431584        sp = p;         // remember addr of insert
    15441585        p = stupid_insert(p, c);    // insert the char
    1545 #ifdef CONFIG_FEATURE_VI_SETOPTS
     1586#if ENABLE_FEATURE_VI_SETOPTS
    15461587        if (showmatch && strchr(")]}", *sp) != NULL) {
    15471588            showmatching(sp);
    15481589        }
    15491590        if (autoindent && c == '\n') {  // auto indent the new line
    1550             Byte *q;
     1591            char *q;
    15511592
    15521593            q = prev_line(p);   // use prev line as templet
    1553             for (; isblnk(*q); q++) {
     1594            for (; isblank(*q); q++) {
    15541595                p = stupid_insert(p, *q);   // insert the char
    15551596            }
    15561597        }
    1557 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
    1558     }
    1559     return (p);
    1560 }
    1561 
    1562 static Byte *stupid_insert(Byte * p, Byte c) // stupidly insert the char c at 'p'
     1598#endif
     1599    }
     1600    return p;
     1601}
     1602
     1603static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p'
    15631604{
    15641605    p = text_hole_make(p, 1);
     
    15681609        p++;
    15691610    }
    1570     return (p);
    1571 }
    1572 
    1573 static Byte find_range(Byte ** start, Byte ** stop, Byte c)
    1574 {
    1575     Byte *save_dot, *p, *q;
     1611    return p;
     1612}
     1613
     1614static char find_range(char ** start, char ** stop, char c)
     1615{
     1616    char *save_dot, *p, *q;
    15761617    int cnt;
    15771618
     
    16251666    }
    16261667    dot = save_dot;
    1627     return (c);
    1628 }
    1629 
    1630 static int st_test(Byte * p, int type, int dir, Byte * tested)
    1631 {
    1632     Byte c, c0, ci;
     1668    return c;
     1669}
     1670
     1671static int st_test(char * p, int type, int dir, char * tested)
     1672{
     1673    char c, c0, ci;
    16331674    int test, inc;
    16341675
     
    16591700    }
    16601701    *tested = c;
    1661     return (test);
    1662 }
    1663 
    1664 static Byte *skip_thing(Byte * p, int linecnt, int dir, int type)
    1665 {
    1666     Byte c;
     1702    return test;
     1703}
     1704
     1705static char *skip_thing(char * p, int linecnt, int dir, int type)
     1706{
     1707    char c;
    16671708
    16681709    while (st_test(p, type, dir, &c)) {
     
    16761717        p += dir;       // move to next char
    16771718    }
    1678     return (p);
     1719    return p;
    16791720}
    16801721
    16811722// find matching char of pair  ()  []  {}
    1682 static Byte *find_pair(Byte * p, Byte c)
    1683 {
    1684     Byte match, *q;
     1723static char *find_pair(char * p, char c)
     1724{
     1725    char match, *q;
    16851726    int dir, level;
    16861727
     
    17221763    if (level != 0)
    17231764        q = NULL;       // indicate no match
    1724     return (q);
    1725 }
    1726 
    1727 #ifdef CONFIG_FEATURE_VI_SETOPTS
     1765    return q;
     1766}
     1767
     1768#if ENABLE_FEATURE_VI_SETOPTS
    17281769// show the matching char of a pair,  ()  []  {}
    1729 static void showmatching(Byte * p)
    1730 {
    1731     Byte *q, *save_dot;
     1770static void showmatching(char * p)
     1771{
     1772    char *q, *save_dot;
    17321773
    17331774    // we found half of a pair
     
    17401781        dot = q;        // go to new loc
    17411782        refresh(FALSE); // let the user see it
    1742         (void) mysleep(40); // give user some time
     1783        mysleep(40);    // give user some time
    17431784        dot = save_dot; // go back to old loc
    17441785        refresh(FALSE);
    17451786    }
    17461787}
    1747 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
     1788#endif /* FEATURE_VI_SETOPTS */
    17481789
    17491790//  open a hole in text[]
    1750 static Byte *text_hole_make(Byte * p, int size) // at "p", make a 'size' byte hole
    1751 {
    1752     Byte *src, *dest;
     1791static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte hole
     1792{
     1793    char *src, *dest;
    17531794    int cnt;
    17541795
     
    17581799    dest = p + size;
    17591800    cnt = end - src;    // the rest of buffer
    1760     if (memmove(dest, src, cnt) != dest) {
     1801    if ( ((end + size) >= (text + text_size)) // TODO: realloc here
     1802            || memmove(dest, src, cnt) != dest) {
    17611803        psbs("can't create room for new characters");
     1804        p = NULL;
     1805        goto thm0;
    17621806    }
    17631807    memset(p, ' ', size);   // clear new hole
    1764     end = end + size;   // adjust the new END
     1808    end += size;        // adjust the new END
    17651809    file_modified++;    // has the file been modified
    1766   thm0:
    1767     return (p);
     1810 thm0:
     1811    return p;
    17681812}
    17691813
    17701814//  close a hole in text[]
    1771 static Byte *text_hole_delete(Byte * p, Byte * q) // delete "p" thru "q", inclusive
    1772 {
    1773     Byte *src, *dest;
     1815static char *text_hole_delete(char * p, char * q) // delete "p" thru "q", inclusive
     1816{
     1817    char *src, *dest;
    17741818    int cnt, hole_size;
    17751819
     
    17931837        psbs("can't delete the character");
    17941838    }
    1795   thd_atend:
     1839 thd_atend:
    17961840    end = end - hole_size;  // adjust the new END
    17971841    if (dest >= end)
     
    18001844        dest = end = text;  // keep pointers valid
    18011845    file_modified++;    // has the file been modified
    1802   thd0:
    1803     return (dest);
     1846 thd0:
     1847    return dest;
    18041848}
    18051849
     
    18071851// if dist <= 0, do not include, or go past, a NewLine
    18081852//
    1809 static Byte *yank_delete(Byte * start, Byte * stop, int dist, int yf)
    1810 {
    1811     Byte *p;
     1853static char *yank_delete(char * start, char * stop, int dist, int yf)
     1854{
     1855    char *p;
    18121856
    18131857    // make sure start <= stop
     
    18191863    }
    18201864    if (dist <= 0) {
    1821         // we can not cross NL boundaries
     1865        // we cannot cross NL boundaries
    18221866        p = start;
    18231867        if (*p == '\n')
    1824             return (p);
     1868            return p;
    18251869        // dont go past a NewLine
    18261870        for (; p + 1 <= stop; p++) {
     
    18321876    }
    18331877    p = start;
    1834 #ifdef CONFIG_FEATURE_VI_YANKMARK
     1878#if ENABLE_FEATURE_VI_YANKMARK
    18351879    text_yank(start, stop, YDreg);
    1836 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     1880#endif
    18371881    if (yf == YANKDEL) {
    18381882        p = text_hole_delete(start, stop);
    18391883    }                   // delete lines
    1840     return (p);
     1884    return p;
    18411885}
    18421886
     
    18441888{
    18451889    puts("These features are available:"
    1846 #ifdef CONFIG_FEATURE_VI_SEARCH
     1890#if ENABLE_FEATURE_VI_SEARCH
    18471891    "\n\tPattern searches with / and ?"
    1848 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
    1849 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     1892#endif
     1893#if ENABLE_FEATURE_VI_DOT_CMD
    18501894    "\n\tLast command repeat with \'.\'"
    1851 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    1852 #ifdef CONFIG_FEATURE_VI_YANKMARK
     1895#endif
     1896#if ENABLE_FEATURE_VI_YANKMARK
    18531897    "\n\tLine marking with  'x"
    18541898    "\n\tNamed buffers with  \"x"
    1855 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    1856 #ifdef CONFIG_FEATURE_VI_READONLY
     1899#endif
     1900#if ENABLE_FEATURE_VI_READONLY
    18571901    "\n\tReadonly if vi is called as \"view\""
    18581902    "\n\tReadonly with -R command line arg"
    1859 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    1860 #ifdef CONFIG_FEATURE_VI_SET
     1903#endif
     1904#if ENABLE_FEATURE_VI_SET
    18611905    "\n\tSome colon mode commands with \':\'"
    1862 #endif                          /* CONFIG_FEATURE_VI_SET */
    1863 #ifdef CONFIG_FEATURE_VI_SETOPTS
     1906#endif
     1907#if ENABLE_FEATURE_VI_SETOPTS
    18641908    "\n\tSettable options with \":set\""
    1865 #endif                          /* CONFIG_FEATURE_VI_SETOPTS */
    1866 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     1909#endif
     1910#if ENABLE_FEATURE_VI_USE_SIGNALS
    18671911    "\n\tSignal catching- ^C"
    18681912    "\n\tJob suspend and resume with ^Z"
    1869 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
    1870 #ifdef CONFIG_FEATURE_VI_WIN_RESIZE
     1913#endif
     1914#if ENABLE_FEATURE_VI_WIN_RESIZE
    18711915    "\n\tAdapt to window re-sizes"
    1872 #endif                          /* CONFIG_FEATURE_VI_WIN_RESIZE */
     1916#endif
    18731917    );
    18741918}
    18751919
    1876 static inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable
    1877 {
    1878     Byte c, b[2];
     1920static inline void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable
     1921{
     1922    unsigned char c;
     1923    char b[2];
    18791924
    18801925    b[1] = '\0';
    1881     strcpy((char *) buf, "");   // init buf
    1882     if (strlen((char *) s) <= 0)
    1883         s = (Byte *) "(NULL)";
    1884     for (; *s > '\0'; s++) {
     1926    buf[0] = '\0';
     1927    if (!s[0])
     1928        s = "(NULL)";
     1929    for (; *s; s++) {
    18851930        int c_is_no_print;
    18861931
    18871932        c = *s;
    1888         c_is_no_print = c > 127 && !Isprint(c);
     1933        c_is_no_print = (c & 0x80) && !Isprint(c);
    18891934        if (c_is_no_print) {
    1890             strcat((char *) buf, SOn);
     1935            strcat(buf, SOn);
    18911936            c = '.';
    18921937        }
    18931938        if (c < ' ' || c == 127) {
    1894             strcat((char *) buf, "^");
    1895             if(c == 127)
     1939            strcat(buf, "^");
     1940            if (c == 127)
    18961941                c = '?';
    1897              else
    1898             c += '@';
     1942            else
     1943                c += '@';
    18991944        }
    19001945        b[0] = c;
    1901         strcat((char *) buf, (char *) b);
     1946        strcat(buf, b);
    19021947        if (c_is_no_print)
    1903             strcat((char *) buf, SOs);
    1904         if (*s == '\n') {
    1905             strcat((char *) buf, "$");
    1906         }
    1907     }
    1908 }
    1909 
    1910 #ifdef CONFIG_FEATURE_VI_DOT_CMD
    1911 static void start_new_cmd_q(Byte c)
     1948            strcat(buf, SOs);
     1949        if (*s == '\n')
     1950            strcat(buf, "$");
     1951    }
     1952}
     1953
     1954#if ENABLE_FEATURE_VI_DOT_CMD
     1955static void start_new_cmd_q(char c)
    19121956{
    19131957    // release old cmd
    19141958    free(last_modifying_cmd);
    19151959    // get buffer for new cmd
    1916     last_modifying_cmd = (Byte *) xmalloc(BUFSIZ);
    1917     memset(last_modifying_cmd, '\0', BUFSIZ);   // clear new cmd queue
     1960    last_modifying_cmd = xzalloc(MAX_LINELEN);
    19181961    // if there is a current cmd count put it in the buffer first
    19191962    if (cmdcnt > 0)
    1920         sprintf((char *) last_modifying_cmd, "%d%c", cmdcnt, c);
     1963        sprintf(last_modifying_cmd, "%d%c", cmdcnt, c);
    19211964    else // just save char c onto queue
    19221965        last_modifying_cmd[0] = c;
     
    19261969static void end_cmd_q(void)
    19271970{
    1928 #ifdef CONFIG_FEATURE_VI_YANKMARK
     1971#if ENABLE_FEATURE_VI_YANKMARK
    19291972    YDreg = 26;         // go back to default Yank/Delete reg
    1930 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     1973#endif
    19311974    adding2q = 0;
    1932     return;
    1933 }
    1934 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    1935 
    1936 #if defined(CONFIG_FEATURE_VI_YANKMARK) || (defined(CONFIG_FEATURE_VI_COLON) && defined(CONFIG_FEATURE_VI_SEARCH)) || defined(CONFIG_FEATURE_VI_CRASHME)
    1937 static Byte *string_insert(Byte * p, Byte * s) // insert the string at 'p'
     1975}
     1976#endif /* FEATURE_VI_DOT_CMD */
     1977
     1978#if ENABLE_FEATURE_VI_YANKMARK \
     1979 || (ENABLE_FEATURE_VI_COLON && ENABLE_FEATURE_VI_SEARCH) \
     1980 || ENABLE_FEATURE_VI_CRASHME
     1981static char *string_insert(char * p, char * s) // insert the string at 'p'
    19381982{
    19391983    int cnt, i;
    19401984
    1941     i = strlen((char *) s);
    1942     p = text_hole_make(p, i);
    1943     strncpy((char *) p, (char *) s, i);
    1944     for (cnt = 0; *s != '\0'; s++) {
    1945         if (*s == '\n')
    1946             cnt++;
    1947     }
    1948 #ifdef CONFIG_FEATURE_VI_YANKMARK
    1949     psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
    1950 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    1951     return (p);
    1952 }
    1953 #endif                          /* CONFIG_FEATURE_VI_YANKMARK || CONFIG_FEATURE_VI_COLON || CONFIG_FEATURE_VI_CRASHME */
    1954 
    1955 #ifdef CONFIG_FEATURE_VI_YANKMARK
    1956 static Byte *text_yank(Byte * p, Byte * q, int dest)    // copy text into a register
    1957 {
    1958     Byte *t;
     1985    i = strlen(s);
     1986    if (text_hole_make(p, i)) {
     1987        strncpy(p, s, i);
     1988        for (cnt = 0; *s != '\0'; s++) {
     1989            if (*s == '\n')
     1990                cnt++;
     1991        }
     1992#if ENABLE_FEATURE_VI_YANKMARK
     1993        psb("Put %d lines (%d chars) from [%c]", cnt, i, what_reg());
     1994#endif
     1995    }
     1996    return p;
     1997}
     1998#endif
     1999
     2000#if ENABLE_FEATURE_VI_YANKMARK
     2001static char *text_yank(char * p, char * q, int dest)    // copy text into a register
     2002{
     2003    char *t;
    19592004    int cnt;
    19602005
     
    19672012    t = reg[dest];
    19682013    free(t);        //  if already a yank register, free it
    1969     t = (Byte *) xmalloc(cnt + 1);  // get a new register
     2014    t = xmalloc(cnt + 1);   // get a new register
    19702015    memset(t, '\0', cnt + 1);   // clear new text[]
    1971     strncpy((char *) t, (char *) p, cnt);   // copy text[] into bufer
     2016    strncpy(t, p, cnt); // copy text[] into bufer
    19722017    reg[dest] = t;
    1973     return (p);
    1974 }
    1975 
    1976 static Byte what_reg(void)
    1977 {
    1978     Byte c;
    1979     int i;
    1980 
    1981     i = 0;
     2018    return p;
     2019}
     2020
     2021static char what_reg(void)
     2022{
     2023    char c;
     2024
    19822025    c = 'D';            // default to D-reg
    19832026    if (0 <= YDreg && YDreg <= 25)
    1984         c = 'a' + (Byte) YDreg;
     2027        c = 'a' + (char) YDreg;
    19852028    if (YDreg == 26)
    19862029        c = 'D';
    19872030    if (YDreg == 27)
    19882031        c = 'U';
    1989     return (c);
    1990 }
    1991 
    1992 static void check_context(Byte cmd)
     2032    return c;
     2033}
     2034
     2035static void check_context(char cmd)
    19932036{
    19942037    // A context is defined to be "modifying text"
     
    19962039
    19972040    if (dot < context_start || dot > context_end) {
    1998         if (strchr((char *) modifying_cmds, cmd) != NULL) {
     2041        if (strchr(modifying_cmds, cmd) != NULL) {
    19992042            // we are trying to modify text[]- make this the current context
    20002043            mark[27] = mark[26];    // move cur to prev
     
    20052048        }
    20062049    }
    2007     return;
    2008 }
    2009 
    2010 static inline Byte *swap_context(Byte * p) // goto new context for '' command make this the current context
    2011 {
    2012     Byte *tmp;
     2050}
     2051
     2052static inline char *swap_context(char * p) // goto new context for '' command make this the current context
     2053{
     2054    char *tmp;
    20132055
    20142056    // the current context is in mark[26]
     
    20232065        context_end = next_line(next_line(next_line(p)));
    20242066    }
    2025     return (p);
    2026 }
    2027 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
    2028 
    2029 static int isblnk(Byte c) // is the char a blank or tab
    2030 {
    2031     return (c == ' ' || c == '\t');
    2032 }
     2067    return p;
     2068}
     2069#endif /* FEATURE_VI_YANKMARK */
    20332070
    20342071//----- Set terminal attributes --------------------------------
     
    20532090
    20542091//----- Come here when we get a window resize signal ---------
    2055 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     2092#if ENABLE_FEATURE_VI_USE_SIGNALS
    20562093static void winch_sig(int sig ATTRIBUTE_UNUSED)
    20572094{
    20582095    signal(SIGWINCH, winch_sig);
    20592096    if (ENABLE_FEATURE_VI_WIN_RESIZE)
    2060        get_terminal_width_height(0, &columns, &rows);
     2097        get_terminal_width_height(0, &columns, &rows);
    20612098    new_screen(rows, columns);  // get memory for virtual screen
    20622099    redraw(TRUE);       // re-draw the screen
     
    20912128{
    20922129    signal(SIGINT, catch_sig);
    2093     if(sig)
     2130    if (sig)
    20942131        longjmp(restart, sig);
    20952132}
    2096 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
     2133#endif /* FEATURE_VI_USE_SIGNALS */
    20972134
    20982135static int mysleep(int hund)    // sleep for 'h' 1/100 seconds
    20992136{
     2137    fd_set rfds;
     2138    struct timeval tv;
     2139
    21002140    // Don't hang- Wait 5/100 seconds-  1 Sec= 1000000
    21012141    fflush(stdout);
     
    21052145    tv.tv_usec = hund * 10000;
    21062146    select(1, &rfds, NULL, NULL, &tv);
    2107     return (FD_ISSET(0, &rfds));
     2147    return FD_ISSET(0, &rfds);
    21082148}
    21092149
     
    21132153
    21142154//----- IO Routines --------------------------------------------
    2115 static Byte readit(void)    // read (maybe cursor) key from stdin
    2116 {
    2117     Byte c;
     2155static char readit(void)    // read (maybe cursor) key from stdin
     2156{
     2157    char c;
    21182158    int n;
    21192159    struct esc_cmds {
    21202160        const char *seq;
    2121         Byte val;
     2161        char val;
    21222162    };
    21232163
    21242164    static const struct esc_cmds esccmds[] = {
    2125         {"OA", (Byte) VI_K_UP},       // cursor key Up
    2126         {"OB", (Byte) VI_K_DOWN},     // cursor key Down
    2127         {"OC", (Byte) VI_K_RIGHT},    // Cursor Key Right
    2128         {"OD", (Byte) VI_K_LEFT},     // cursor key Left
    2129         {"OH", (Byte) VI_K_HOME},     // Cursor Key Home
    2130         {"OF", (Byte) VI_K_END},      // Cursor Key End
    2131         {"[A", (Byte) VI_K_UP},       // cursor key Up
    2132         {"[B", (Byte) VI_K_DOWN},     // cursor key Down
    2133         {"[C", (Byte) VI_K_RIGHT},    // Cursor Key Right
    2134         {"[D", (Byte) VI_K_LEFT},     // cursor key Left
    2135         {"[H", (Byte) VI_K_HOME},     // Cursor Key Home
    2136         {"[F", (Byte) VI_K_END},      // Cursor Key End
    2137         {"[1~", (Byte) VI_K_HOME},     // Cursor Key Home
    2138         {"[2~", (Byte) VI_K_INSERT},  // Cursor Key Insert
    2139         {"[4~", (Byte) VI_K_END},      // Cursor Key End
    2140         {"[5~", (Byte) VI_K_PAGEUP},  // Cursor Key Page Up
    2141         {"[6~", (Byte) VI_K_PAGEDOWN},        // Cursor Key Page Down
    2142         {"OP", (Byte) VI_K_FUN1},     // Function Key F1
    2143         {"OQ", (Byte) VI_K_FUN2},     // Function Key F2
    2144         {"OR", (Byte) VI_K_FUN3},     // Function Key F3
    2145         {"OS", (Byte) VI_K_FUN4},     // Function Key F4
    2146         {"[15~", (Byte) VI_K_FUN5},   // Function Key F5
    2147         {"[17~", (Byte) VI_K_FUN6},   // Function Key F6
    2148         {"[18~", (Byte) VI_K_FUN7},   // Function Key F7
    2149         {"[19~", (Byte) VI_K_FUN8},   // Function Key F8
    2150         {"[20~", (Byte) VI_K_FUN9},   // Function Key F9
    2151         {"[21~", (Byte) VI_K_FUN10},  // Function Key F10
    2152         {"[23~", (Byte) VI_K_FUN11},  // Function Key F11
    2153         {"[24~", (Byte) VI_K_FUN12},  // Function Key F12
    2154         {"[11~", (Byte) VI_K_FUN1},   // Function Key F1
    2155         {"[12~", (Byte) VI_K_FUN2},   // Function Key F2
    2156         {"[13~", (Byte) VI_K_FUN3},   // Function Key F3
    2157         {"[14~", (Byte) VI_K_FUN4},   // Function Key F4
     2165        {"OA", VI_K_UP},       // cursor key Up
     2166        {"OB", VI_K_DOWN},     // cursor key Down
     2167        {"OC", VI_K_RIGHT},    // Cursor Key Right
     2168        {"OD", VI_K_LEFT},     // cursor key Left
     2169        {"OH", VI_K_HOME},     // Cursor Key Home
     2170        {"OF", VI_K_END},      // Cursor Key End
     2171        {"[A", VI_K_UP},       // cursor key Up
     2172        {"[B", VI_K_DOWN},     // cursor key Down
     2173        {"[C", VI_K_RIGHT},    // Cursor Key Right
     2174        {"[D", VI_K_LEFT},     // cursor key Left
     2175        {"[H", VI_K_HOME},     // Cursor Key Home
     2176        {"[F", VI_K_END},      // Cursor Key End
     2177        {"[1~", VI_K_HOME},    // Cursor Key Home
     2178        {"[2~", VI_K_INSERT},  // Cursor Key Insert
     2179        {"[4~", VI_K_END},     // Cursor Key End
     2180        {"[5~", VI_K_PAGEUP},  // Cursor Key Page Up
     2181        {"[6~", VI_K_PAGEDOWN},// Cursor Key Page Down
     2182        {"OP", VI_K_FUN1},     // Function Key F1
     2183        {"OQ", VI_K_FUN2},     // Function Key F2
     2184        {"OR", VI_K_FUN3},     // Function Key F3
     2185        {"OS", VI_K_FUN4},     // Function Key F4
     2186        {"[15~", VI_K_FUN5},   // Function Key F5
     2187        {"[17~", VI_K_FUN6},   // Function Key F6
     2188        {"[18~", VI_K_FUN7},   // Function Key F7
     2189        {"[19~", VI_K_FUN8},   // Function Key F8
     2190        {"[20~", VI_K_FUN9},   // Function Key F9
     2191        {"[21~", VI_K_FUN10},  // Function Key F10
     2192        {"[23~", VI_K_FUN11},  // Function Key F11
     2193        {"[24~", VI_K_FUN12},  // Function Key F12
     2194        {"[11~", VI_K_FUN1},   // Function Key F1
     2195        {"[12~", VI_K_FUN2},   // Function Key F2
     2196        {"[13~", VI_K_FUN3},   // Function Key F3
     2197        {"[14~", VI_K_FUN4},   // Function Key F4
    21582198    };
    2159 
    2160 #define ESCCMDS_COUNT (sizeof(esccmds)/sizeof(struct esc_cmds))
    2161 
    2162     (void) alarm(0);    // turn alarm OFF while we wait for input
     2199    enum { ESCCMDS_COUNT = ARRAY_SIZE(esccmds) };
     2200
     2201    alarm(0);   // turn alarm OFF while we wait for input
    21632202    fflush(stdout);
    21642203    n = readed_for_parse;
    21652204    // get input from User- are there already input chars in Q?
    21662205    if (n <= 0) {
    2167       ri0:
     2206 ri0:
    21682207        // the Q is empty, wait for a typed char
    2169         n = read(0, readbuffer, BUFSIZ - 1);
     2208        n = read(0, readbuffer, MAX_LINELEN - 1);
    21702209        if (n < 0) {
    21712210            if (errno == EINTR)
    21722211                goto ri0;   // interrupted sys call
    2173             if (errno == EBADF)
    2174                 editing = 0;
    2175             if (errno == EFAULT)
    2176                 editing = 0;
    2177             if (errno == EINVAL)
    2178                 editing = 0;
    2179             if (errno == EIO)
     2212            if (errno == EBADF || errno == EFAULT || errno == EINVAL
     2213                    || errno == EIO)
    21802214                editing = 0;
    21812215            errno = 0;
    21822216        }
    2183         if(n <= 0)
     2217        if (n <= 0)
    21842218            return 0;       // error
    21852219        if (readbuffer[0] == 27) {
    2186     // This is an ESC char. Is this Esc sequence?
    2187     // Could be bare Esc key. See if there are any
    2188     // more chars to read after the ESC. This would
    2189     // be a Function or Cursor Key sequence.
    2190     FD_ZERO(&rfds);
    2191     FD_SET(0, &rfds);
    2192     tv.tv_sec = 0;
    2193     tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000
    2194 
    2195     // keep reading while there are input chars and room in buffer
    2196             while (select(1, &rfds, NULL, NULL, &tv) > 0 && n <= (BUFSIZ - 5)) {
    2197         // read the rest of the ESC string
    2198                 int r = read(0, (void *) (readbuffer + n), BUFSIZ - n);
     2220            fd_set rfds;
     2221            struct timeval tv;
     2222
     2223            // This is an ESC char. Is this Esc sequence?
     2224            // Could be bare Esc key. See if there are any
     2225            // more chars to read after the ESC. This would
     2226            // be a Function or Cursor Key sequence.
     2227            FD_ZERO(&rfds);
     2228            FD_SET(0, &rfds);
     2229            tv.tv_sec = 0;
     2230            tv.tv_usec = 50000; // Wait 5/100 seconds- 1 Sec=1000000
     2231
     2232            // keep reading while there are input chars and room in buffer
     2233            while (select(1, &rfds, NULL, NULL, &tv) > 0 && n <= (MAX_LINELEN - 5)) {
     2234                // read the rest of the ESC string
     2235                int r = read(0, (void *) (readbuffer + n), MAX_LINELEN - n);
    21992236                if (r > 0) {
    22002237                    n += r;
     
    22052242    }
    22062243    c = readbuffer[0];
    2207     if(c == 27 && n > 1) {
    2208     // Maybe cursor or function key?
     2244    if (c == 27 && n > 1) {
     2245        // Maybe cursor or function key?
    22092246        const struct esc_cmds *eindex;
    22102247
     
    22122249            int cnt = strlen(eindex->seq);
    22132250
    2214             if(n <= cnt)
     2251            if (n <= cnt)
    22152252                continue;
    2216             if(strncmp(eindex->seq, (char *) readbuffer + 1, cnt))
     2253            if (strncmp(eindex->seq, readbuffer + 1, cnt))
    22172254                continue;
    22182255            // is a Cursor key- put derived value back into Q
     
    22222259            break;
    22232260        }
    2224         if(eindex == &esccmds[ESCCMDS_COUNT]) {
     2261        if (eindex == &esccmds[ESCCMDS_COUNT]) {
    22252262            /* defined ESC sequence not found, set only one ESC */
    22262263            n = 1;
     
    22312268    // remove key sequence from Q
    22322269    readed_for_parse -= n;
    2233     memmove(readbuffer, readbuffer + n, BUFSIZ - n);
    2234     (void) alarm(3);    // we are done waiting for input, turn alarm ON
    2235     return (c);
     2270    memmove(readbuffer, readbuffer + n, MAX_LINELEN - n);
     2271    alarm(3);   // we are done waiting for input, turn alarm ON
     2272    return c;
    22362273}
    22372274
    22382275//----- IO Routines --------------------------------------------
    2239 static Byte get_one_char(void)
    2240 {
    2241     static Byte c;
    2242 
    2243 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     2276static char get_one_char(void)
     2277{
     2278    static char c;
     2279
     2280#if ENABLE_FEATURE_VI_DOT_CMD
    22442281    // ! adding2q  && ioq == 0  read()
    22452282    // ! adding2q  && ioq != 0  *ioq
     
    22652302        c = readit();   // get the users input
    22662303        if (last_modifying_cmd != 0) {
    2267             int len = strlen((char *) last_modifying_cmd);
    2268             if (len + 1 >= BUFSIZ) {
     2304            int len = strlen(last_modifying_cmd);
     2305            if (len >= MAX_LINELEN - 1) {
    22692306                psbs("last_modifying_cmd overrun");
    22702307            } else {
     
    22742311        }
    22752312    }
    2276 #else                           /* CONFIG_FEATURE_VI_DOT_CMD */
     2313#else
    22772314    c = readit();       // get the users input
    2278 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    2279     return (c);         // return the char, where ever it came from
    2280 }
    2281 
    2282 static Byte *get_input_line(Byte * prompt) // get input line- use "status line"
    2283 {
    2284     Byte buf[BUFSIZ];
    2285     Byte c;
     2315#endif /* FEATURE_VI_DOT_CMD */
     2316    return c;           // return the char, where ever it came from
     2317}
     2318
     2319static char *get_input_line(const char * prompt) // get input line- use "status line"
     2320{
     2321    static char *obufp;
     2322
     2323    char buf[MAX_LINELEN];
     2324    char c;
    22862325    int i;
    2287     static Byte *obufp = NULL;
    2288 
    2289     strcpy((char *) buf, (char *) prompt);
     2326
     2327    strcpy(buf, prompt);
    22902328    last_status_cksum = 0;  // force status update
    22912329    place_cursor(rows - 1, 0, FALSE);   // go to Status line, bottom of screen
    22922330    clear_to_eol();     // clear the line
    2293     write1((char *) prompt);      // write out the :, /, or ? prompt
    2294 
    2295     for (i = strlen((char *) buf); i < BUFSIZ;) {
     2331    write1(prompt);      // write out the :, /, or ? prompt
     2332
     2333    i = strlen(buf);
     2334    while (i < MAX_LINELEN) {
    22962335        c = get_one_char(); // read user input
    22972336        if (c == '\n' || c == '\r' || c == 27)
     
    23152354    refresh(FALSE);
    23162355    free(obufp);
    2317     obufp = (Byte *) bb_xstrdup((char *) buf);
    2318     return (obufp);
    2319 }
    2320 
    2321 static int file_size(const Byte * fn) // what is the byte size of "fn"
     2356    obufp = xstrdup(buf);
     2357    return obufp;
     2358}
     2359
     2360static int file_size(const char *fn) // what is the byte size of "fn"
    23222361{
    23232362    struct stat st_buf;
    2324     int cnt, sr;
    2325 
    2326     if (fn == 0 || strlen((char *)fn) <= 0)
    2327         return (-1);
     2363    int cnt;
     2364
    23282365    cnt = -1;
    2329     sr = stat((char *) fn, &st_buf);    // see if file exists
    2330     if (sr >= 0) {
     2366    if (fn && fn[0] && stat(fn, &st_buf) == 0)  // see if file exists
    23312367        cnt = (int) st_buf.st_size;
    2332     }
    2333     return (cnt);
    2334 }
    2335 
    2336 static int file_insert(Byte * fn, Byte * p, int size)
    2337 {
    2338     int fd, cnt;
    2339 
    2340     cnt = -1;
    2341 #ifdef CONFIG_FEATURE_VI_READONLY
    2342     readonly = FALSE;
    2343 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    2344     if (fn == 0 || strlen((char*) fn) <= 0) {
    2345         psbs("No filename given");
     2368    return cnt;
     2369}
     2370
     2371static int file_insert(const char * fn, char *p
     2372        USE_FEATURE_VI_READONLY(, int update_ro_status))
     2373{
     2374    int cnt = -1;
     2375    int fd, size;
     2376    struct stat statbuf;
     2377
     2378    /* Validate file */
     2379    if (stat(fn, &statbuf) < 0) {
     2380        psbs("\"%s\" %s", fn, strerror(errno));
    23462381        goto fi0;
    23472382    }
    2348     if (size == 0) {
    2349         // OK- this is just a no-op
    2350         cnt = 0;
     2383    if ((statbuf.st_mode & S_IFREG) == 0) {
     2384        // This is not a regular file
     2385        psbs("\"%s\" Not a regular file", fn);
    23512386        goto fi0;
    23522387    }
    2353     if (size < 0) {
    2354         psbs("Trying to insert a negative number (%d) of characters", size);
     2388    /* // this check is done by open()
     2389    if ((statbuf.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)) == 0) {
     2390        // dont have any read permissions
     2391        psbs("\"%s\" Not readable", fn);
    23552392        goto fi0;
    23562393    }
     2394    */
    23572395    if (p < text || p > end) {
    23582396        psbs("Trying to insert file outside of memory");
     
    23602398    }
    23612399
    2362     // see if we can open the file
    2363 #ifdef CONFIG_FEATURE_VI_READONLY
    2364     if (vi_readonly) goto fi1;      // do not try write-mode
    2365 #endif
    2366     fd = open((char *) fn, O_RDWR);         // assume read & write
     2400    // read file to buffer
     2401    fd = open(fn, O_RDONLY);
    23672402    if (fd < 0) {
    2368         // could not open for writing- maybe file is read only
    2369 #ifdef CONFIG_FEATURE_VI_READONLY
    2370   fi1:
    2371 #endif
    2372         fd = open((char *) fn, O_RDONLY);   // try read-only
    2373         if (fd < 0) {
    2374             psbs("\"%s\" %s", fn, "could not open file");
    2375             goto fi0;
    2376         }
    2377 #ifdef CONFIG_FEATURE_VI_READONLY
    2378         // got the file- read-only
    2379         readonly = TRUE;
    2380 #endif                          /* CONFIG_FEATURE_VI_READONLY */
    2381     }
     2403        psbs("\"%s\" %s", fn, strerror(errno));
     2404        goto fi0;
     2405    }
     2406    size = statbuf.st_size;
    23822407    p = text_hole_make(p, size);
     2408    if (p == NULL)
     2409        goto fi0;
    23832410    cnt = read(fd, p, size);
    2384     close(fd);
    23852411    if (cnt < 0) {
    2386         cnt = -1;
     2412        psbs("\"%s\" %s", fn, strerror(errno));
    23872413        p = text_hole_delete(p, p + size - 1);  // un-do buffer insert
    2388         psbs("could not read file \"%s\"", fn);
    23892414    } else if (cnt < size) {
    23902415        // There was a partial read, shrink unused space text[]
    23912416        p = text_hole_delete(p + cnt, p + (size - cnt) - 1);    // un-do buffer insert
    2392         psbs("could not read all of file \"%s\"", fn);
     2417        psbs("cannot read all of file \"%s\"", fn);
    23932418    }
    23942419    if (cnt >= size)
    23952420        file_modified++;
    2396   fi0:
    2397     return (cnt);
    2398 }
    2399 
    2400 static int file_write(Byte * fn, Byte * first, Byte * last)
     2421    close(fd);
     2422 fi0:
     2423#if ENABLE_FEATURE_VI_READONLY
     2424    if (update_ro_status
     2425     && ((access(fn, W_OK) < 0) ||
     2426        /* root will always have access()
     2427         * so we check fileperms too */
     2428        !(statbuf.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH))
     2429        )
     2430    ) {
     2431        SET_READONLY_FILE(readonly_mode);
     2432    }
     2433#endif
     2434    return cnt;
     2435}
     2436
     2437
     2438static int file_write(char * fn, char * first, char * last)
    24012439{
    24022440    int fd, cnt, charcnt;
     
    24042442    if (fn == 0) {
    24052443        psbs("No current filename");
    2406         return (-2);
     2444        return -2;
    24072445    }
    24082446    charcnt = 0;
    24092447    // FIXIT- use the correct umask()
    2410     fd = open((char *) fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
     2448    fd = open(fn, (O_WRONLY | O_CREAT | O_TRUNC), 0664);
    24112449    if (fd < 0)
    2412         return (-1);
     2450        return -1;
    24132451    cnt = last - first + 1;
    24142452    charcnt = write(fd, first, cnt);
    24152453    if (charcnt == cnt) {
    24162454        // good write
    2417         //file_modified= FALSE; // the file has not been modified
     2455        //file_modified = FALSE; // the file has not been modified
    24182456    } else {
    24192457        charcnt = 0;
    24202458    }
    24212459    close(fd);
    2422     return (charcnt);
     2460    return charcnt;
    24232461}
    24242462
     
    24382476static void place_cursor(int row, int col, int opti)
    24392477{
    2440     char cm1[BUFSIZ];
     2478    char cm1[MAX_LINELEN];
    24412479    char *cm;
    2442 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
    2443     char cm2[BUFSIZ];
    2444     Byte *screenp;
    2445     // char cm3[BUFSIZ];
    2446     int Rrow= last_row;
    2447 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
    2448 
    2449     memset(cm1, '\0', BUFSIZ - 1);  // clear the buffer
     2480#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
     2481    char cm2[MAX_LINELEN];
     2482    char *screenp;
     2483    // char cm3[MAX_LINELEN];
     2484    int Rrow = last_row;
     2485#endif
     2486
     2487    memset(cm1, '\0', MAX_LINELEN);  // clear the buffer
    24502488
    24512489    if (row < 0) row = 0;
     
    24552493
    24562494    //----- 1.  Try the standard terminal ESC sequence
    2457     sprintf((char *) cm1, CMrc, row + 1, col + 1);
    2458     cm= cm1;
    2459     if (! opti) goto pc0;
    2460 
    2461 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     2495    sprintf(cm1, CMrc, row + 1, col + 1);
     2496    cm = cm1;
     2497    if (!opti)
     2498        goto pc0;
     2499
     2500#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    24622501    //----- find the minimum # of chars to move cursor -------------
    24632502    //----- 2.  Try moving with discreet chars (Newline, [back]space, ...)
    2464     memset(cm2, '\0', BUFSIZ - 1);  // clear the buffer
     2503    memset(cm2, '\0', MAX_LINELEN);  // clear the buffer
    24652504
    24662505    // move to the correct row
     
    24802519    // just send out orignal source char to get to correct place
    24812520    screenp = &screen[row * columns];   // start of screen line
    2482     strncat(cm2, (char* )screenp, col);
     2521    strncat(cm2, screenp, col);
    24832522
    24842523    //----- 3.  Try some other way of moving cursor
     
    24862525
    24872526    // pick the shortest cursor motion to send out
    2488     cm= cm1;
     2527    cm = cm1;
    24892528    if (strlen(cm2) < strlen(cm)) {
    2490         cm= cm2;
     2529        cm = cm2;
    24912530    }  /* else if (strlen(cm3) < strlen(cm)) {
    24922531        cm= cm3;
    24932532    } */
    2494 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
    2495   pc0:
     2533#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
     2534 pc0:
    24962535    write1(cm);                 // move the cursor
    24972536}
     
    25262565    standout_start();   // send "start reverse video" sequence
    25272566    redraw(TRUE);
    2528     (void) mysleep(h);
     2567    mysleep(h);
    25292568    standout_end();     // send "end reverse video" sequence
    25302569    redraw(TRUE);
     
    25332572static void Indicate_Error(void)
    25342573{
    2535 #ifdef CONFIG_FEATURE_VI_CRASHME
     2574#if ENABLE_FEATURE_VI_CRASHME
    25362575    if (crashme > 0)
    25372576        return;         // generate a random command
    2538 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
     2577#endif
    25392578    if (!err_method) {
    25402579        write1(bell);   // send out a bell character
     
    25512590}
    25522591
    2553 static int bufsum(unsigned char *buf, int count)
     2592static int bufsum(char *buf, int count)
    25542593{
    25552594    int sum = 0;
    2556     unsigned char *e = buf + count;
     2595    char *e = buf + count;
     2596
    25572597    while (buf < e)
    2558         sum += *buf++;
     2598        sum += (unsigned char) *buf++;
    25592599    return sum;
    25602600}
     
    25742614        last_status_cksum= cksum;       // remember if we have seen this line
    25752615        place_cursor(rows - 1, 0, FALSE);   // put cursor on status line
    2576         write1((char*)status_buffer);
     2616        write1(status_buffer);
    25772617        clear_to_eol();
    25782618        if (have_status_msg) {
    2579             if (((int)strlen((char*)status_buffer) - (have_status_msg - 1)) >
     2619            if (((int)strlen(status_buffer) - (have_status_msg - 1)) >
    25802620                    (columns - 1) ) {
    25812621                have_status_msg = 0;
     
    25962636
    25972637    va_start(args, format);
    2598     strcpy((char *) status_buffer, SOs);    // Terminal standout mode on
    2599     vsprintf((char *) status_buffer + strlen((char *) status_buffer), format, args);
    2600     strcat((char *) status_buffer, SOn);    // Terminal standout mode off
     2638    strcpy(status_buffer, SOs); // Terminal standout mode on
     2639    vsprintf(status_buffer + strlen(status_buffer), format, args);
     2640    strcat(status_buffer, SOn); // Terminal standout mode off
    26012641    va_end(args);
    26022642
    26032643    have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2;
    2604 
    2605     return;
    26062644}
    26072645
     
    26122650
    26132651    va_start(args, format);
    2614     vsprintf((char *) status_buffer, format, args);
     2652    vsprintf(status_buffer, format, args);
    26152653    va_end(args);
    26162654
    26172655    have_status_msg = 1;
    2618 
    2619     return;
    2620 }
    2621 
    2622 static void ni(Byte * s) // display messages
    2623 {
    2624     Byte buf[BUFSIZ];
     2656}
     2657
     2658static void ni(const char * s) // display messages
     2659{
     2660    char buf[MAX_LINELEN];
    26252661
    26262662    print_literal(buf, s);
     
    26302666static int format_edit_status(void) // show file status on status line
    26312667{
     2668    static int tot;
     2669    static const char cmd_mode_indicator[] ALIGN1 = "-IR-";
    26322670    int cur, percent, ret, trunc_at;
    2633     static int tot;
    26342671
    26352672    // file_modified is now a counter rather than a flag.  this
     
    26632700        columns : STATUS_BUFFER_LEN-1;
    26642701
    2665     ret = snprintf((char *) status_buffer, trunc_at+1,
    2666 #ifdef CONFIG_FEATURE_VI_READONLY
     2702    ret = snprintf(status_buffer, trunc_at+1,
     2703#if ENABLE_FEATURE_VI_READONLY
    26672704        "%c %s%s%s %d/%d %d%%",
    26682705#else
    26692706        "%c %s%s %d/%d %d%%",
    26702707#endif
    2671         (cmd_mode ? (cmd_mode == 2 ? 'R':'I'):'-'),
    2672         (cfn != 0 ? (char *) cfn : "No file"),
    2673 #ifdef CONFIG_FEATURE_VI_READONLY
    2674         ((vi_readonly || readonly) ? " [Read-only]" : ""),
    2675 #endif
    2676         (file_modified ? " [modified]" : ""),
     2708        cmd_mode_indicator[cmd_mode & 3],
     2709        (current_filename != NULL ? current_filename : "No file"),
     2710#if ENABLE_FEATURE_VI_READONLY
     2711        (readonly_mode ? " [Readonly]" : ""),
     2712#endif
     2713        (file_modified ? " [Modified]" : ""),
    26772714        cur, tot, percent);
    26782715
     
    26952732
    26962733//----- Format a text[] line into a buffer ---------------------
    2697 static void format_line(Byte *dest, Byte *src, int li)
     2734static void format_line(char *dest, char *src, int li)
    26982735{
    26992736    int co;
    2700     Byte c;
    2701 
    2702     for (co= 0; co < MAX_SCR_COLS; co++) {
    2703         c= ' ';     // assume blank
     2737    char c;
     2738
     2739    for (co = 0; co < MAX_SCR_COLS; co++) {
     2740        c = ' ';        // assume blank
    27042741        if (li > 0 && co == 0) {
    27052742            c = '~';        // not first line, assume Tilde
     
    27112748        if (c == '\n')
    27122749            break;
    2713         if (c > 127 && !Isprint(c)) {
     2750        if ((c & 0x80) && !Isprint(c)) {
    27142751            c = '.';
    27152752        }
    2716         if (c < ' ' || c == 127) {
     2753        if ((unsigned char)(c) < ' ' || c == 0x7f) {
    27172754            if (c == '\t') {
    27182755                c = ' ';
     
    27232760            } else {
    27242761                dest[co++] = '^';
    2725                 if(c == 127)
     2762                if (c == 0x7f)
    27262763                    c = '?';
    2727                  else
     2764                else
    27282765                    c += '@';       // make it visible
    27292766            }
     
    27452782{
    27462783    static int old_offset;
     2784
    27472785    int li, changed;
    2748     Byte buf[MAX_SCR_COLS];
    2749     Byte *tp, *sp;      // pointer into text[] and screen[]
    2750 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
    2751     int last_li= -2;                // last line that changed- for optimizing cursor movement
    2752 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
     2786    char buf[MAX_SCR_COLS];
     2787    char *tp, *sp;      // pointer into text[] and screen[]
     2788#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
     2789    int last_li = -2; // last line that changed- for optimizing cursor movement
     2790#endif
    27532791
    27542792    if (ENABLE_FEATURE_VI_WIN_RESIZE)
     
    27662804
    27672805        // skip to the end of the current text[] line
    2768         while (tp < end && *tp++ != '\n') /*no-op*/ ;
     2806        while (tp < end && *tp++ != '\n') /*no-op*/;
    27692807
    27702808        // see if there are any changes between vitual screen and buf
     
    27792817        // compare newly formatted buffer with virtual screen
    27802818        // look forward for first difference between buf and screen
    2781         for ( ; cs <= ce; cs++) {
     2819        for (; cs <= ce; cs++) {
    27822820            if (buf[cs + offset] != sp[cs]) {
    27832821                changed = TRUE; // mark for redraw
     
    27972835        // if horz offset has changed, force a redraw
    27982836        if (offset != old_offset) {
    2799   re0:
     2837 re0:
    28002838            changed = TRUE;
    28012839        }
     
    28162854                place_cursor(li, cs, FALSE);
    28172855            } else {
    2818 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     2856#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    28192857                // if this just the next line
    28202858                //  try to optimize cursor movement
     
    28222860                place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE);
    28232861                last_li= li;
    2824 #else                           /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
     2862#else
    28252863                place_cursor(li, cs, FALSE);    // use standard ESC sequence
    2826 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
     2864#endif /* FEATURE_VI_OPTIMIZE_CURSOR */
    28272865            }
    28282866
    28292867            // write line out to terminal
    28302868            {
    2831                 int nic = ce-cs+1;
    2832                 char *out = (char*)sp+cs;
    2833 
    2834                 while(nic-- > 0) {
     2869                int nic = ce - cs + 1;
     2870                char *out = sp + cs;
     2871
     2872                while (nic-- > 0) {
    28352873                    putchar(*out);
    28362874                    out++;
    28372875                }
    28382876            }
    2839 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     2877#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    28402878            last_row = li;
    2841 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
    2842         }
    2843     }
    2844 
    2845 #ifdef CONFIG_FEATURE_VI_OPTIMIZE_CURSOR
     2879#endif
     2880        }
     2881    }
     2882
     2883#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR
    28462884    place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE);
    28472885    last_row = crow;
    28482886#else
    28492887    place_cursor(crow, ccol, FALSE);
    2850 #endif                          /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */
     2888#endif
    28512889
    28522890    if (offset != old_offset)
     
    28762914
    28772915//----- Execute a Vi Command -----------------------------------
    2878 static void do_cmd(Byte c)
    2879 {
    2880     Byte c1, *p, *q, *msg, buf[9], *save_dot;
     2916static void do_cmd(char c)
     2917{
     2918    const char *msg;
     2919    char c1, *p, *q, buf[9], *save_dot;
    28812920    int cnt, i, j, dir, yf;
    28822921
    28832922    c1 = c;             // quiet the compiler
    28842923    cnt = yf = dir = 0; // quiet the compiler
    2885     p = q = save_dot = msg = buf;   // quiet the compiler
     2924    msg = p = q = save_dot = buf;   // quiet the compiler
    28862925    memset(buf, '\0', 9);   // clear buf
    28872926
     
    29032942    if (cmd_mode == 2) {
    29042943        //  flip-flop Insert/Replace mode
    2905         if (c == VI_K_INSERT) goto dc_i;
     2944        if (c == VI_K_INSERT)
     2945            goto dc_i;
    29062946        // we are 'R'eplacing the current *dot with new char
    29072947        if (*dot == '\n') {
     
    29272967    }
    29282968
    2929 key_cmd_mode:
     2969 key_cmd_mode:
    29302970    switch (c) {
    29312971        //case 0x01:    // soh
     
    29372977        //case 0x11:    // dc1
    29382978        //case 0x13:    // dc3
    2939 #ifdef CONFIG_FEATURE_VI_CRASHME
     2979#if ENABLE_FEATURE_VI_CRASHME
    29402980    case 0x14:          // dc4  ctrl-T
    29412981        crashme = (crashme == 0) ? 1 : 0;
    29422982        break;
    2943 #endif                          /* CONFIG_FEATURE_VI_CRASHME */
     2983#endif
    29442984        //case 0x16:    // syn
    29452985        //case 0x17:    // etb
     
    29803020            buf[2] = '\0';
    29813021        }
    2982         ni((Byte *) buf);
     3022        ni(buf);
    29833023        end_cmd_q();    // stop adding to q
    29843024    case 0x00:          // nul- ignore
     
    29883028        dot_scroll(rows - 2, -1);
    29893029        break;
    2990 #ifdef CONFIG_FEATURE_VI_USE_SIGNALS
     3030#if ENABLE_FEATURE_VI_USE_SIGNALS
    29913031    case 0x03:          // ctrl-C   interrupt
    29923032        longjmp(restart, 1);
     
    29953035        suspend_sig(SIGTSTP);
    29963036        break;
    2997 #endif                          /* CONFIG_FEATURE_VI_USE_SIGNALS */
     3037#endif
    29983038    case 4:         // ctrl-D  scroll down half screen
    29993039        dot_scroll((rows - 2) / 2, 1);
     
    30123052    case VI_K_LEFT: // cursor key Left
    30133053    case 8:     // ctrl-H- move left    (This may be ERASE char)
    3014     case 127:   // DEL- move left   (This may be ERASE char)
     3054    case 0x7f:  // DEL- move left   (This may be ERASE char)
    30153055        if (cmdcnt-- > 1) {
    30163056            do_cmd(c);
     
    30313071        place_cursor(0, 0, FALSE);  // put cursor in correct place
    30323072        clear_to_eos(); // tel terminal to erase display
    3033         (void) mysleep(10);
     3073        mysleep(10);
    30343074        screen_erase(); // erase the internal screen buffer
    30353075        last_status_cksum = 0;  // force status update
     
    30653105        dot_right();
    30663106        break;
    3067 #ifdef CONFIG_FEATURE_VI_YANKMARK
     3107#if ENABLE_FEATURE_VI_YANKMARK
    30683108    case '"':           // "- name a register to use for Delete/Yank
    30693109        c1 = get_one_char();
     
    30813121            c1 = c1 - 'a';
    30823122            // get the b-o-l
    3083             q = mark[(int) c1];
     3123            q = mark[(unsigned char) c1];
    30843124            if (text <= q && q < end) {
    30853125                dot = q;
     
    31183158        }
    31193159        // are we putting whole lines or strings
    3120         if (strchr((char *) p, '\n') != NULL) {
     3160        if (strchr(p, '\n') != NULL) {
    31213161            if (c == 'P') {
    31223162                dot_begin();    // putting lines- Put above
     
    31473187        }
    31483188        break;
    3149 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     3189#endif /* FEATURE_VI_YANKMARK */
    31503190    case '$':           // $- goto end of line
    31513191    case VI_K_END:      // Cursor Key End
     
    31813221            do_cmd(';');
    31823222        }               // repeat cnt
    3183         if (last_forward_char == 0) break;
     3223        if (last_forward_char == 0)
     3224            break;
    31843225        q = dot + 1;
    31853226        while (q < end - 1 && *q != '\n' && *q != last_forward_char) {
     
    31963237        dot_skip_over_ws();
    31973238        break;
    3198 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     3239#if ENABLE_FEATURE_VI_DOT_CMD
    31993240    case '.':           // .- repeat the last modifying command
    32003241        // Stuff the last_modifying_cmd back into stdin
    32013242        // and let it be re-executed.
    32023243        if (last_modifying_cmd != 0) {
    3203             ioq = ioq_start = (Byte *) bb_xstrdup((char *) last_modifying_cmd);
    3204         }
    3205         break;
    3206 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
    3207 #ifdef CONFIG_FEATURE_VI_SEARCH
     3244            ioq = ioq_start = xstrdup(last_modifying_cmd);
     3245        }
     3246        break;
     3247#endif
     3248#if ENABLE_FEATURE_VI_SEARCH
    32083249    case '?':           // /- search for a pattern
    32093250    case '/':           // /- search for a pattern
     
    32113252        buf[1] = '\0';
    32123253        q = get_input_line(buf);    // get input line- use "status line"
    3213         if (strlen((char *) q) == 1)
    3214             goto dc3;   // if no pat re-use old pat
    3215         if (strlen((char *) q) > 1) {   // new pat- save it and find
     3254        if (q[0] && !q[1])
     3255            goto dc3; // if no pat re-use old pat
     3256        if (q[0]) {       // strlen(q) > 1: new pat- save it and find
    32163257            // there is a new pat
    32173258            free(last_search_pattern);
    3218             last_search_pattern = (Byte *) bb_xstrdup((char *) q);
     3259            last_search_pattern = xstrdup(q);
    32193260            goto dc3;   // now find the pattern
    32203261        }
     
    32393280            do_cmd(c);
    32403281        }               // repeat cnt
    3241       dc3:
     3282 dc3:
    32423283        if (last_search_pattern == 0) {
    3243             msg = (Byte *) "No previous regular expression";
     3284            msg = "No previous regular expression";
    32443285            goto dc2;
    32453286        }
     
    32523293            p = dot - 1;
    32533294        }
    3254       dc4:
     3295 dc4:
    32553296        q = char_search(p, last_search_pattern + 1, dir, FULL);
    32563297        if (q != NULL) {
    32573298            dot = q;    // good search, update "dot"
    3258             msg = (Byte *) "";
     3299            msg = "";
    32593300            goto dc2;
    32603301        }
     
    32673308        if (q != NULL) {    // found something
    32683309            dot = q;    // found new pattern- goto it
    3269             msg = (Byte *) "search hit BOTTOM, continuing at TOP";
     3310            msg = "search hit BOTTOM, continuing at TOP";
    32703311            if (dir == BACK) {
    3271                 msg = (Byte *) "search hit TOP, continuing at BOTTOM";
     3312                msg = "search hit TOP, continuing at BOTTOM";
    32723313            }
    32733314        } else {
    3274             msg = (Byte *) "Pattern not found";
    3275         }
    3276       dc2:
    3277         if (*msg) psbs("%s", msg);
     3315            msg = "Pattern not found";
     3316        }
     3317 dc2:
     3318        if (*msg)
     3319            psbs("%s", msg);
    32783320        break;
    32793321    case '{':           // {- move backward paragraph
    3280         q = char_search(dot, (Byte *) "\n\n", BACK, FULL);
     3322        q = char_search(dot, "\n\n", BACK, FULL);
    32813323        if (q != NULL) {    // found blank line
    32823324            dot = next_line(q); // move to next blank line
     
    32843326        break;
    32853327    case '}':           // }- move forward paragraph
    3286         q = char_search(dot, (Byte *) "\n\n", FORWARD, FULL);
     3328        q = char_search(dot, "\n\n", FORWARD, FULL);
    32873329        if (q != NULL) {    // found blank line
    32883330            dot = next_line(q); // move to next blank line
    32893331        }
    32903332        break;
    3291 #endif                          /* CONFIG_FEATURE_VI_SEARCH */
     3333#endif /* FEATURE_VI_SEARCH */
    32923334    case '0':           // 0- goto begining of line
    32933335    case '1':           // 1-
     
    33073349        break;
    33083350    case ':':           // :- the colon mode commands
    3309         p = get_input_line((Byte *) ":");   // get input line- use "status line"
    3310 #ifdef CONFIG_FEATURE_VI_COLON
     3351        p = get_input_line(":");    // get input line- use "status line"
     3352#if ENABLE_FEATURE_VI_COLON
    33113353        colon(p);       // execute the command
    3312 #else                           /* CONFIG_FEATURE_VI_COLON */
     3354#else
    33133355        if (*p == ':')
    33143356            p++;                // move past the ':'
    3315         cnt = strlen((char *) p);
     3357        cnt = strlen(p);
    33163358        if (cnt <= 0)
    33173359            break;
    3318         if (strncasecmp((char *) p, "quit", cnt) == 0 ||
    3319             strncasecmp((char *) p, "q!", cnt) == 0) {  // delete lines
     3360        if (strncasecmp(p, "quit", cnt) == 0
     3361         || strncasecmp(p, "q!", cnt) == 0   // delete lines
     3362        ) {
    33203363            if (file_modified && p[1] != '!') {
    33213364                psbs("No write since last change (:quit! overrides)");
     
    33233366                editing = 0;
    33243367            }
    3325         } else if (strncasecmp((char *) p, "write", cnt) == 0
    3326                 || strncasecmp((char *) p, "wq", cnt) == 0
    3327                 || strncasecmp((char *) p, "wn", cnt) == 0
    3328                 || strncasecmp((char *) p, "x", cnt) == 0) {
    3329             cnt = file_write(cfn, text, end - 1);
     3368        } else if (strncasecmp(p, "write", cnt) == 0
     3369                || strncasecmp(p, "wq", cnt) == 0
     3370                || strncasecmp(p, "wn", cnt) == 0
     3371                || strncasecmp(p, "x", cnt) == 0
     3372        ) {
     3373            cnt = file_write(current_filename, text, end - 1);
    33303374            if (cnt < 0) {
    33313375                if (cnt == -1)
     
    33343378                file_modified = 0;
    33353379                last_file_modified = -1;
    3336                 psb("\"%s\" %dL, %dC", cfn, count_lines(text, end - 1), cnt);
    3337                 if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' ||
    3338                     p[0] == 'X' || p[1] == 'Q' || p[1] == 'N') {
     3380                psb("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt);
     3381                if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n'
     3382                 || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N'
     3383                ) {
    33393384                    editing = 0;
    33403385                }
    33413386            }
    3342         } else if (strncasecmp((char *) p, "file", cnt) == 0 ) {
     3387        } else if (strncasecmp(p, "file", cnt) == 0) {
    33433388            last_status_cksum = 0;  // force status update
    3344         } else if (sscanf((char *) p, "%d", &j) > 0) {
     3389        } else if (sscanf(p, "%d", &j) > 0) {
    33453390            dot = find_line(j);     // go to line # j
    33463391            dot_skip_over_ws();
    33473392        } else {        // unrecognised cmd
    3348             ni((Byte *) p);
    3349         }
    3350 #endif                          /* CONFIG_FEATURE_VI_COLON */
     3393            ni(p);
     3394        }
     3395#endif /* !FEATURE_VI_COLON */
    33513396        break;
    33523397    case '<':           // <- Left  shift something
     
    33553400        c1 = get_one_char();    // get the type of thing to delete
    33563401        find_range(&p, &q, c1);
    3357         (void) yank_delete(p, q, 1, YANKONLY);  // save copy before change
     3402        yank_delete(p, q, 1, YANKONLY); // save copy before change
    33583403        p = begin_line(p);
    33593404        q = end_line(q);
     
    33643409                if (*p == '\t') {
    33653410                    // shrink buffer 1 char
    3366                     (void) text_hole_delete(p, p);
     3411                    text_hole_delete(p, p);
    33673412                } else if (*p == ' ') {
    33683413                    // we should be calculating columns, not just SPACE
    33693414                    for (j = 0; *p == ' ' && j < tabstop; j++) {
    3370                         (void) text_hole_delete(p, p);
     3415                        text_hole_delete(p, p);
    33713416                    }
    33723417                }
    33733418            } else if (c == '>') {
    33743419                // shift right -- add tab or 8 spaces
    3375                 (void) char_insert(p, '\t');
     3420                char_insert(p, '\t');
    33763421            }
    33773422        }
     
    34123457        if (c == 'C')
    34133458            goto dc_i;  // start inserting
    3414 #ifdef CONFIG_FEATURE_VI_DOT_CMD
     3459#if ENABLE_FEATURE_VI_DOT_CMD
    34153460        if (c == 'D')
    34163461            end_cmd_q();    // stop adding to q
    3417 #endif                          /* CONFIG_FEATURE_VI_DOT_CMD */
     3462#endif
    34183463        break;
    34193464    case 'G':       // G- goto to a line number (default= E-O-F)
     
    34403485    case 'i':           // i- insert before current char
    34413486    case VI_K_INSERT:   // Cursor Key Insert
    3442       dc_i:
     3487 dc_i:
    34433488        cmd_mode = 1;   // start insrting
    34443489        break;
     
    34513496            *dot++ = ' ';   // replace NL with space
    34523497            file_modified++;
    3453             while (isblnk(*dot)) {  // delete leading WS
     3498            while (isblank(*dot)) { // delete leading WS
    34543499                dot_delete();
    34553500            }
     
    34893534        break;
    34903535    case 'R':           // R- continuous Replace char
    3491       dc5:
     3536 dc5:
    34923537        cmd_mode = 2;
    34933538        break;
     
    35183563        }
    35193564        if (file_modified) {
    3520 #ifdef CONFIG_FEATURE_VI_READONLY
    3521             if (vi_readonly || readonly) {
    3522                 psbs("\"%s\" File is read only", cfn);
    3523                 break;
    3524             }
    3525 #endif      /* CONFIG_FEATURE_VI_READONLY */
    3526             cnt = file_write(cfn, text, end - 1);
     3565            if (ENABLE_FEATURE_VI_READONLY && readonly_mode) {
     3566                psbs("\"%s\" File is read only", current_filename);
     3567                break;
     3568            }
     3569            cnt = file_write(current_filename, text, end - 1);
    35273570            if (cnt < 0) {
    35283571                if (cnt == -1)
     
    35613604    case 'c':           // c- change something
    35623605    case 'd':           // d- delete something
    3563 #ifdef CONFIG_FEATURE_VI_YANKMARK
     3606#if ENABLE_FEATURE_VI_YANKMARK
    35643607    case 'y':           // y- yank   something
    35653608    case 'Y':           // Y- Yank a line
    3566 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     3609#endif
    35673610        yf = YANKDEL;   // assume either "c" or "d"
    3568 #ifdef CONFIG_FEATURE_VI_YANKMARK
     3611#if ENABLE_FEATURE_VI_YANKMARK
    35693612        if (c == 'y' || c == 'Y')
    35703613            yf = YANKONLY;
    3571 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     3614#endif
    35723615        c1 = 'y';
    35733616        if (c != 'Y')
     
    35793622            if (c == 'c') {
    35803623                // don't include trailing WS as part of word
    3581                 while (isblnk(*q)) {
     3624                while (isblank(*q)) {
    35823625                    if (q <= text || q[-1] == '\n')
    35833626                        break;
     
    36103653            // if CHANGING, not deleting, start inserting after the delete
    36113654            if (c == 'c') {
    3612                 strcpy((char *) buf, "Change");
     3655                strcpy(buf, "Change");
    36133656                goto dc_i;  // start inserting
    36143657            }
    36153658            if (c == 'd') {
    3616                 strcpy((char *) buf, "Delete");
    3617             }
    3618 #ifdef CONFIG_FEATURE_VI_YANKMARK
     3659                strcpy(buf, "Delete");
     3660            }
     3661#if ENABLE_FEATURE_VI_YANKMARK
    36193662            if (c == 'y' || c == 'Y') {
    3620                 strcpy((char *) buf, "Yank");
     3663                strcpy(buf, "Yank");
    36213664            }
    36223665            p = reg[YDreg];
    3623             q = p + strlen((char *) p);
     3666            q = p + strlen(p);
    36243667            for (cnt = 0; p <= q; p++) {
    36253668                if (*p == '\n')
     
    36273670            }
    36283671            psb("%s %d lines (%d chars) using [%c]",
    3629                 buf, cnt, strlen((char *) reg[YDreg]), what_reg());
    3630 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     3672                buf, cnt, strlen(reg[YDreg]), what_reg());
     3673#endif
    36313674            end_cmd_q();    // stop adding to q
    36323675        }
     
    37173760    }
    37183761
    3719   dc1:
     3762 dc1:
    37203763    // if text[] just became empty, add back an empty line
    37213764    if (end == text) {
    3722         (void) char_insert(text, '\n'); // start empty buf with dummy line
     3765        char_insert(text, '\n');    // start empty buf with dummy line
    37233766        dot = text;
    37243767    }
     
    37273770        dot = bound_dot(dot);   // make sure "dot" is valid
    37283771    }
    3729 #ifdef CONFIG_FEATURE_VI_YANKMARK
     3772#if ENABLE_FEATURE_VI_YANKMARK
    37303773    check_context(c);   // update the current context
    3731 #endif                          /* CONFIG_FEATURE_VI_YANKMARK */
     3774#endif
    37323775
    37333776    if (!isdigit(c))
     
    37393782}
    37403783
    3741 #ifdef CONFIG_FEATURE_VI_CRASHME
     3784#if ENABLE_FEATURE_VI_CRASHME
    37423785static int totalcmds = 0;
    37433786static int Mp = 85;             // Movement command Probability
     
    37483791static int Pp = 99;             // Put command Probability
    37493792static int M = 0, N = 0, I = 0, D = 0, Y = 0, P = 0, U = 0;
    3750 char chars[20] = "\t012345 abcdABCD-=.$";
    3751 char *words[20] = { "this", "is", "a", "test",
     3793const char chars[20] = "\t012345 abcdABCD-=.$";
     3794const char *const words[20] = {
     3795    "this", "is", "a", "test",
    37523796    "broadcast", "the", "emergency", "of",
    37533797    "system", "quick", "brown", "fox",
     
    37553799    "back", "January", "Febuary", "March"
    37563800};
    3757 char *lines[20] = {
     3801const char *const lines[20] = {
    37583802    "You should have received a copy of the GNU General Public License\n",
    37593803    "char c, cm, *cmd, *cmd1;\n",
     
    38133857    if (readed_for_parse > 0)
    38143858        goto cd1;
    3815   cd0:
     3859 cd0:
    38163860    startrbi = rbi = 0;
    38173861    sleeptime = 0;          // how long to pause between commands
    3818     memset(readbuffer, '\0', BUFSIZ);   // clear the read buffer
     3862    memset(readbuffer, '\0', MAX_LINELEN);   // clear the read buffer
    38193863    // generate a command by percentages
    38203864    percent = (int) lrand48() % 100;        // get a number from 0-99
     
    38753919                readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))];
    38763920            } else if (thing == 1) {        // insert words
    3877                 strcat((char *) readbuffer, words[(int) lrand48() % 20]);
    3878                 strcat((char *) readbuffer, " ");
     3921                strcat(readbuffer, words[(int) lrand48() % 20]);
     3922                strcat(readbuffer, " ");
    38793923                sleeptime = 0;  // how fast to type
    38803924            } else if (thing == 2) {        // insert lines
    3881                 strcat((char *) readbuffer, lines[(int) lrand48() % 20]);
     3925                strcat(readbuffer, lines[(int) lrand48() % 20]);
    38823926                sleeptime = 0;  // how fast to type
    38833927            } else {        // insert multi-lines
    3884                 strcat((char *) readbuffer, multilines[(int) lrand48() % 20]);
     3928                strcat(readbuffer, multilines[(int) lrand48() % 20]);
    38853929                sleeptime = 0;  // how fast to type
    38863930            }
    38873931        }
    3888         strcat((char *) readbuffer, "\033");
     3932        strcat(readbuffer, "\033");
    38893933    }
    38903934    readed_for_parse = strlen(readbuffer);
    3891   cd1:
     3935 cd1:
    38923936    totalcmds++;
    38933937    if (sleeptime > 0)
    3894         (void) mysleep(sleeptime);      // sleep 1/100 sec
     3938        mysleep(sleeptime);      // sleep 1/100 sec
    38953939}
    38963940
     
    38993943{
    39003944    static time_t oldtim;
     3945
    39013946    time_t tim;
    3902     char d[2], msg[BUFSIZ];
     3947    char d[2], msg[MAX_LINELEN];
    39033948
    39043949    msg[0] = '\0';
    39053950    if (end < text) {
    3906         strcat((char *) msg, "end<text ");
     3951        strcat(msg, "end<text ");
    39073952    }
    39083953    if (end > textend) {
    3909         strcat((char *) msg, "end>textend ");
     3954        strcat(msg, "end>textend ");
    39103955    }
    39113956    if (dot < text) {
    3912         strcat((char *) msg, "dot<text ");
     3957        strcat(msg, "dot<text ");
    39133958    }
    39143959    if (dot > end) {
    3915         strcat((char *) msg, "dot>end ");
     3960        strcat(msg, "dot>end ");
    39163961    }
    39173962    if (screenbegin < text) {
    3918         strcat((char *) msg, "screenbegin<text ");
     3963        strcat(msg, "screenbegin<text ");
    39193964    }
    39203965    if (screenbegin > end - 1) {
    3921         strcat((char *) msg, "screenbegin>end-1 ");
    3922     }
    3923 
    3924     if (strlen(msg) > 0) {
     3966        strcat(msg, "screenbegin>end-1 ");
     3967    }
     3968
     3969    if (msg[0]) {
    39253970        alarm(0);
    39263971        printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s",
     
    39353980    tim = (time_t) time((time_t *) 0);
    39363981    if (tim >= (oldtim + 3)) {
    3937         sprintf((char *) status_buffer,
     3982        sprintf(status_buffer,
    39383983                "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d",
    39393984                totalcmds, M, N, I, D, Y, P, U, end - text + 1);
    39403985        oldtim = tim;
    39413986    }
    3942     return;
    3943 }
    3944 #endif                            /* CONFIG_FEATURE_VI_CRASHME */
     3987}
     3988#endif
Note: See TracChangeset for help on using the changeset viewer.