Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/editors
- Timestamp:
- Nov 6, 2007, 11:01:53 AM (16 years ago)
- Location:
- branches/stable/mindi-busybox/editors
- Files:
-
- 2 deleted
- 6 edited
- 3 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/stable/mindi-busybox/editors/Config.in
r821 r1770 6 6 menu "Editors" 7 7 8 config CONFIG_AWK8 config AWK 9 9 bool "awk" 10 10 default n … … 13 13 the BusyBox implementation of that programming language. 14 14 15 config CONFIG_FEATURE_AWK_MATH15 config FEATURE_AWK_MATH 16 16 bool "Enable math functions (requires libm)" 17 17 default y 18 depends on CONFIG_AWK18 depends on AWK 19 19 help 20 20 Enable math functions of the Awk programming language. 21 21 NOTE: This will require libm to be present for linking. 22 22 23 config CONFIG_ED 23 config 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 30 config 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 38 config 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 46 config 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 54 config 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 62 config ED 24 63 bool "ed" 25 64 default n … … 29 68 this, you don't need it. 30 69 31 config CONFIG_PATCH70 config PATCH 32 71 bool "patch" 33 72 default n … … 35 74 Apply a unified diff formatted patch. 36 75 37 config CONFIG_SED76 config SED 38 77 bool "sed" 39 78 default n … … 42 81 or input from a pipeline. 43 82 44 config CONFIG_VI83 config VI 45 84 bool "vi" 46 85 default n … … 51 90 you may wish to use something else. 52 91 53 config CONFIG_FEATURE_VI_COLON 92 config 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 102 config FEATURE_VI_COLON 54 103 bool "Enable \":\" colon commands (no \"ex\" mode)" 55 104 default y 56 depends on CONFIG_VI105 depends on VI 57 106 help 58 107 Enable a limited set of colon commands for vi. This does not 59 108 provide an "ex" mode. 60 109 61 config CONFIG_FEATURE_VI_YANKMARK110 config FEATURE_VI_YANKMARK 62 111 bool "Enable yank/put commands and mark cmds" 63 112 default y 64 depends on CONFIG_VI113 depends on VI 65 114 help 66 115 This will enable you to use yank and put, as well as mark in 67 116 busybox vi. 68 117 69 config CONFIG_FEATURE_VI_SEARCH118 config FEATURE_VI_SEARCH 70 119 bool "Enable search and replace cmds" 71 120 default y 72 depends on CONFIG_VI121 depends on VI 73 122 help 74 123 Select this if you wish to be able to do search and replace in 75 124 busybox vi. 76 125 77 config CONFIG_FEATURE_VI_USE_SIGNALS126 config FEATURE_VI_USE_SIGNALS 78 127 bool "Catch signals" 79 128 default y 80 depends on CONFIG_VI129 depends on VI 81 130 help 82 131 Selecting this option will make busybox vi signal aware. This will … … 84 133 Ctrl-Z and Ctrl-C and alarms. 85 134 86 config CONFIG_FEATURE_VI_DOT_CMD135 config FEATURE_VI_DOT_CMD 87 136 bool "Remember previous cmd and \".\" cmd" 88 137 default y 89 depends on CONFIG_VI138 depends on VI 90 139 help 91 140 Make busybox vi remember the last command and be able to repeat it. 92 141 93 config CONFIG_FEATURE_VI_READONLY142 config FEATURE_VI_READONLY 94 143 bool "Enable -R option and \"view\" mode" 95 144 default y 96 depends on CONFIG_VI145 depends on VI 97 146 help 98 147 Enable the read-only command line option, which allows the user to 99 148 open a file in read-only mode. 100 149 101 config CONFIG_FEATURE_VI_SETOPTS150 config FEATURE_VI_SETOPTS 102 151 bool "Enable set-able options, ai ic showmatch" 103 152 default y 104 depends on CONFIG_VI153 depends on VI 105 154 help 106 155 Enable the editor to set some (ai, ic, showmatch) options. 107 156 108 config CONFIG_FEATURE_VI_SET157 config FEATURE_VI_SET 109 158 bool "Support for :set" 110 159 default y 111 depends on CONFIG_VI160 depends on VI 112 161 help 113 162 Support for ":set". 114 163 115 config CONFIG_FEATURE_VI_WIN_RESIZE164 config FEATURE_VI_WIN_RESIZE 116 165 bool "Handle window resize" 117 166 default y 118 depends on CONFIG_VI167 depends on VI 119 168 help 120 169 Make busybox vi behave nicely with terminals that get resized. 121 170 122 config CONFIG_FEATURE_VI_OPTIMIZE_CURSOR171 config FEATURE_VI_OPTIMIZE_CURSOR 123 172 bool "Optimize cursor movement" 124 173 default y 125 depends on CONFIG_VI174 depends on VI 126 175 help 127 176 This will make the cursor movement faster, but requires more memory 128 177 and it makes the applet a tiny bit larger. 129 178 179 config 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 130 187 endmenu 131 -
branches/stable/mindi-busybox/editors/awk.c
r821 r1770 8 8 */ 9 9 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" 17 12 #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 13 extern char **environ; 14 15 /* This is a NOEXEC applet. Be very careful! */ 16 17 18 #define MAXVARFMT 240 19 #define MINNVBLOCK 64 27 20 28 21 /* variable flags */ 29 #define VF_NUMBER 30 #define VF_ARRAY 31 32 #define VF_CACHED 33 #define VF_USER 34 #define VF_SPECIAL 35 #define VF_WALK 36 #define VF_FSTR 0x1000 /* 1 =string points to fstring buffer */37 #define VF_CHILD 38 #define VF_DIRTY 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 */ 39 32 40 33 /* 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) 42 35 43 36 /* Variable */ 44 37 typedef struct var_s { 45 unsigned short type;/* flags */38 unsigned type; /* flags */ 46 39 double number; 47 40 char *string; 48 41 union { 49 int aidx; 50 struct xhash_s *array; 51 struct var_s *parent; 52 char **walker; 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) */ 53 46 } x; 54 47 } var; … … 58 51 struct node_s *first; 59 52 struct node_s *last; 60 c har *programname;53 const char *programname; 61 54 } chain; 62 55 63 56 /* Function */ 64 57 typedef struct func_s { 65 unsigned shortnargs;58 unsigned nargs; 66 59 struct chain_s body; 67 60 } func; … … 74 67 int size; 75 68 int pos; 76 unsigned short is_pipe;69 smallint is_pipe; 77 70 } rstream; 78 71 79 72 typedef struct hash_item_s { 80 73 union { 81 struct var_s v; 82 struct rstream_s rs; 83 struct func_s f; 74 struct var_s v; /* variable/array hash */ 75 struct rstream_s rs; /* redirect streams hash */ 76 struct func_s f; /* functions hash */ 84 77 } data; 85 struct hash_item_s *next; 86 char name[1]; 78 struct hash_item_s *next; /* next in chain */ 79 char name[1]; /* really it's longer */ 87 80 } hash_item; 88 81 89 82 typedef 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 */ 94 87 struct hash_item_s **items; 95 88 } xhash; … … 98 91 typedef struct node_s { 99 92 uint32_t info; 100 unsigned shortlineno;93 unsigned lineno; 101 94 union { 102 95 struct node_s *n; … … 164 157 #define TC_NUMBER (1 << 29) 165 158 166 #define TC_UOPPRE 159 #define TC_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) 167 160 168 161 /* combined token classes */ 169 #define TC_BINOP 170 #define TC_UNARYOP 171 #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION |\172 173 174 #define TC_STATEMNT 175 #define TC_OPTERM 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) 176 169 177 170 /* word tokens, cannot mean something else if not expected */ 178 #define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN |\179 171 #define TC_WORD (TC_IN | TC_STATEMNT | TC_ELSE | TC_BUILTIN \ 172 | TC_GETLINE | TC_FUNCDECL | TC_BEGIN | TC_END) 180 173 181 174 /* discard newlines after these */ 182 #define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM |\183 175 #define TC_NOTERM (TC_COMMA | TC_GRPSTART | TC_GRPTERM \ 176 | TC_BINOP | TC_OPTERM) 184 177 185 178 /* what can expression begin with */ 186 #define TC_OPSEQ 179 #define TC_OPSEQ (TC_OPERAND | TC_UOPPRE | TC_REGEXP) 187 180 /* what can group begin with */ 188 #define TC_GRPSEQ 181 #define TC_GRPSEQ (TC_OPSEQ | TC_OPTERM | TC_STATEMNT | TC_GRPSTART) 189 182 190 183 /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ 191 184 /* operator is inserted between them */ 192 #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM |\193 194 #define TC_CONCAT2 195 196 #define OF_RES1 197 #define OF_RES2 198 #define OF_STR1 199 #define OF_STR2 200 #define OF_NUM1 201 #define OF_CHECKED 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 202 195 203 196 /* combined operator flags */ … … 213 206 #define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) 214 207 215 #define OPCLSMASK 216 #define OPNMASK 208 #define OPCLSMASK 0xFF00 209 #define OPNMASK 0x007F 217 210 218 211 /* operator priority is a highest byte (even: r->l, odd: l->r grouping) … … 220 213 * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string 221 214 */ 222 #define P(x)(x << 24)223 #define PRIMASK0x7F000000224 #define PRIMASK20x7E000000215 #define P(x) (x << 24) 216 #define PRIMASK 0x7F000000 217 #define PRIMASK2 0x7E000000 225 218 226 219 /* Operation classes */ … … 230 223 231 224 enum { 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 =0x3300225 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 251 244 }; 252 245 253 246 /* simple builtins */ 254 247 enum { 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, 256 249 F_ti, F_le, F_sy, F_ff, F_cl 257 250 }; … … 259 252 /* builtins */ 260 253 enum { 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, 263 257 }; 264 258 265 259 /* tokens and their corresponding info values */ 266 260 267 #define NTC "\377"/* switch to next token class (tc<<1) */268 #define NTCC 261 #define NTC "\377" /* switch to next token class (tc<<1) */ 262 #define NTCC '\377' 269 263 270 264 #define OC_B OC_BUILTIN 271 265 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" 266 static 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" 313 309 ; 314 310 315 311 static const uint32_t tokeninfo[] = { 316 317 312 0, 318 313 0, 319 314 OC_REGEXP, 320 xS|'a', xS|'w',xS|'|',321 OC_UNARY|xV|P(9)|'p', 322 OC_UNARY|xV|P(9)|'P', 323 324 OC_COMPARE|VV|P(39)|5, 325 OC_REPLACE|NV|P(74)|'+',OC_REPLACE|NV|P(74)|'-',326 OC_REPLACE|NV|P(74)|'*', 327 OC_REPLACE|NV|P(74)|'%',OC_REPLACE|NV|P(74)|'&',328 OC_BINARY|NV|P(29)|'+', 329 OC_REPLACE|NV|P(74)|'&',OC_BINARY|NV|P(15)|'&',330 OC_BINARY|NV|P(25)|'/', 331 OC_BINARY|NV|P(15)|'&',OC_BINARY|NV|P(25)|'*',332 OC_COMPARE|VV|P(39)|4, 333 OC_COMPARE|VV|P(39)|0,OC_COMPARE|VV|P(39)|1,334 OC_COMPARE|VV|P(39)|2, 335 OC_MATCH|Sx|P(45)|'~',OC_LAND|Vx|P(55),336 OC_LOR|Vx|P(59), 337 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)|':', 338 333 OC_IN|SV|P(49), 339 334 OC_COMMA|SS|P(80), 340 335 OC_PGETLINE|SV|P(37), 341 OC_UNARY|xV|P(19)|'+', 342 336 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', 337 OC_UNARY|xV|P(19)|'!', 343 338 0, 344 339 0, … … 346 341 0, 347 342 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, 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, 352 347 ST_WHILE, 353 348 0, 354 349 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), 355 352 OC_FBLTIN|Sx|F_cl, OC_FBLTIN|Sx|F_sy, OC_FBLTIN|Sx|F_ff, OC_B|B_a2|P(0x83), 356 353 OC_FBLTIN|Nx|F_co, OC_FBLTIN|Nx|F_ex, OC_FBLTIN|Nx|F_in, OC_FBLTIN|Nx|F_lg, … … 369 366 /* asterisk marks SPECIAL vars; $ is just no-named Field0 */ 370 367 enum { 371 CONVFMT =0, OFMT, FS,OFS,372 ORS, RS, RT,FILENAME,373 SUBSEP, ARGIND, ARGC,ARGV,374 ERRNO, 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 377 374 }; 378 375 379 static c har * 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" 384 "NR\0" "NF\0*""IGNORECASE\0*"385 "ENVIRON\0" "$\0*""\0";386 387 static c har * vValues=388 "%.6g\0" "%.6g\0" " \0"" \0"389 "\n\0" "\n\0" "\0""\0"376 static 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 384 static const char vValues[] ALIGN1 = 385 "%.6g\0" "%.6g\0" " \0" " \0" 386 "\n\0" "\n\0" "\0" "\0" 390 387 "\034\0" 391 388 "\377"; 392 389 393 390 /* 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 392 static 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 */ 397 struct 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 }; 416 struct 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 428 494 429 495 /* function prototypes */ … … 438 504 /* ---- error handling ---- */ 439 505 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 #if ndef CONFIG_FEATURE_AWK_MATH450 static const char EMSG_NO_MATH[] = "Math support is not compiled in";506 static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error"; 507 static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; 508 static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; 509 static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; 510 static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; 511 static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; 512 static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 513 static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 514 static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 515 #if !ENABLE_FEATURE_AWK_MATH 516 static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 451 517 #endif 452 518 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 519 static void zero_out_var(var * vp) 520 { 521 memset(vp, 0, sizeof(*vp)); 522 } 523 524 static void syntax_error(const char *const message) ATTRIBUTE_NORETURN; 525 static void syntax_error(const char *const message) 526 { 527 bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); 528 } 461 529 462 530 /* ---- hash stuff ---- */ 463 531 464 static unsigned inthashidx(const char *name)465 { 466 register unsigned int idx=0;467 468 while (*name) 532 static unsigned hashidx(const char *name) 533 { 534 unsigned idx = 0; 535 536 while (*name) idx = *name++ + (idx << 6) - idx; 469 537 return idx; 470 538 } … … 475 543 xhash *newhash; 476 544 477 newhash = (xhash *)xzalloc(sizeof(xhash));545 newhash = xzalloc(sizeof(xhash)); 478 546 newhash->csize = FIRST_PRIME; 479 newhash->items = (hash_item **)xzalloc(newhash->csize * sizeof(hash_item *));547 newhash->items = xzalloc(newhash->csize * sizeof(hash_item *)); 480 548 481 549 return newhash; … … 499 567 static void hash_rebuild(xhash *hash) 500 568 { 501 unsigned intnewsize, i, idx;569 unsigned newsize, i, idx; 502 570 hash_item **newitems, *hi, *thi; 503 571 504 if (hash->nprime == NPRIMES)572 if (hash->nprime == ARRAY_SIZE(PRIMES)) 505 573 return; 506 574 507 575 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++) { 511 579 hi = hash->items[i]; 512 580 while (hi) { … … 528 596 { 529 597 hash_item *hi; 530 unsigned i nt idx;598 unsigned idx; 531 599 int l; 532 600 533 601 hi = hash_search(hash, name); 534 if (! 602 if (!hi) { 535 603 if (++hash->nel / hash->csize > 10) 536 604 hash_rebuild(hash); … … 548 616 } 549 617 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))) 554 622 555 623 static void hash_remove(xhash *hash, const char *name) … … 557 625 hash_item *hi, **phi; 558 626 559 phi = &(hash->items[ hashidx(name) % hash->csize]);627 phi = &(hash->items[hashidx(name) % hash->csize]); 560 628 while (*phi) { 561 629 hi = *phi; … … 575 643 static void skip_spaces(char **s) 576 644 { 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 } 581 654 p++; 582 655 } … … 586 659 static char *nextword(char **s) 587 660 { 588 registerchar *p = *s;589 590 while (*(*s)++) ;661 char *p = *s; 662 663 while (*(*s)++) /* */; 591 664 592 665 return p; … … 595 668 static char nextchar(char **s) 596 669 { 597 registerchar c, *pps;670 char c, *pps; 598 671 599 672 c = *((*s)++); … … 604 677 } 605 678 606 static in line intisalnum_(int c)679 static int ALWAYS_INLINE isalnum_(int c) 607 680 { 608 681 return (isalnum(c) || c == '_'); … … 611 684 static FILE *afopen(const char *path, const char *mode) 612 685 { 613 return (*path == '-' && *(path+1) == '\0') ? stdin : bb_xfopen(path, mode);686 return (*path == '-' && *(path+1) == '\0') ? stdin : xfopen(path, mode); 614 687 } 615 688 … … 623 696 a = a->x.parent; 624 697 625 if (! 698 if (!(a->type & VF_ARRAY)) { 626 699 a->type |= VF_ARRAY; 627 700 a->x.array = hash_init(); … … 632 705 static void clear_array(xhash *array) 633 706 { 634 unsigned i nt i;707 unsigned i; 635 708 hash_item *hi, *thi; 636 709 637 for (i =0; i<array->csize; i++) {710 for (i = 0; i < array->csize; i++) { 638 711 hi = array->items[i]; 639 712 while (hi) { … … 666 739 v->string = value; 667 740 handle_special(v); 668 669 741 return v; 670 742 } … … 673 745 static var *setvar_s(var *v, const char *value) 674 746 { 675 return setvar_p(v, (value && *value) ? bb_xstrdup(value) : NULL);747 return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); 676 748 } 677 749 … … 687 759 static void setari_u(var *a, int idx, const char *s) 688 760 { 689 register var *v;690 static char sidx[12];761 char sidx[sizeof(int)*3 + 1]; 762 var *v; 691 763 692 764 sprintf(sidx, "%d", idx); … … 705 777 } 706 778 707 static c har *getvar_s(var *v)779 static const char *getvar_s(var *v) 708 780 { 709 781 /* if v is numeric and has no cached string, convert it to string */ 710 782 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); 713 785 v->type |= VF_CACHED; 714 786 } … … 742 814 if (dest != src) { 743 815 clrvar(dest); 744 dest->type |= (src->type & ~ VF_DONTTOUCH);816 dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); 745 817 dest->number = src->number; 746 818 if (src->string) 747 dest->string = bb_xstrdup(src->string);819 dest->string = xstrdup(src->string); 748 820 } 749 821 handle_special(dest); … … 753 825 static var *incvar(var *v) 754 826 { 755 return setvar_i(v, getvar_i(v) +1.);827 return setvar_i(v, getvar_i(v) + 1.); 756 828 } 757 829 … … 768 840 if (is_numeric(v)) 769 841 return (v->number == 0) ? 0 : 1; 770 else 771 return (v->string && *(v->string)) ? 1 : 0; 842 return (v->string && *(v->string)) ? 1 : 0; 772 843 } 773 844 … … 779 850 int size; 780 851 781 while ( cb) {782 pb = cb;783 if (( cb->pos - cb->nv) + n <=cb->size) break;784 cb =cb->next;785 } 786 787 if (! 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) { 788 859 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) { 801 872 v->type = 0; 802 873 v->string = NULL; … … 811 882 var *p; 812 883 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) { 818 889 clear_array(iamarray(p)); 819 890 free(p->x.array->items); … … 826 897 } 827 898 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; 831 902 } 832 903 } … … 834 905 /* ------- awk program text parsing ------- */ 835 906 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. 837 908 * If token isn't expected, give away. Return token class 838 909 */ 839 910 static uint32_t next_token(uint32_t expected) 840 911 { 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 841 918 char *p, *pp, *s; 842 c har *tl;919 const char *tl; 843 920 uint32_t tc; 844 921 const uint32_t *ti; 845 922 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; 853 926 854 927 } else if (concat_inserted) { 855 856 928 concat_inserted = FALSE; 857 t .tclass = save_tclass;858 t .info = save_info;929 t_tclass = save_tclass; 930 t_info = save_info; 859 931 860 932 } else { 861 862 p = pos; 863 864 readnext: 933 p = g_pos; 934 readnext: 865 935 skip_spaces(&p); 866 lineno = t.lineno;936 g_lineno = t_lineno; 867 937 if (*p == '#') 868 while (*p != '\n' && *p != '\0') p++; 938 while (*p != '\n' && *p != '\0') 939 p++; 869 940 870 941 if (*p == '\n') 871 t .lineno++;942 t_lineno++; 872 943 873 944 if (*p == '\0') { … … 876 947 } else if (*p == '\"') { 877 948 /* it's a string */ 878 t .string = s = ++p;949 t_string = s = ++p; 879 950 while (*p != '\"') { 880 951 if (*p == '\0' || *p == '\n') … … 888 959 } else if ((expected & TC_REGEXP) && *p == '/') { 889 960 /* it's regexp */ 890 t .string = s = ++p;961 t_string = s = ++p; 891 962 while (*p != '/') { 892 963 if (*p == '\0' || *p == '\n') 893 964 syntax_error(EMSG_UNEXP_EOS); 894 if ((*s++ = *p++) == '\\') { 965 *s = *p++; 966 if (*s++ == '\\') { 895 967 pp = p; 896 968 *(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++; 899 973 } 900 974 } … … 905 979 } else if (*p == '.' || isdigit(*p)) { 906 980 /* it's a number */ 907 t .number= strtod(p, &p);981 t_double = strtod(p, &p); 908 982 if (*p == '.') 909 983 syntax_error(EMSG_UNEXP_TOKEN); … … 925 999 * then this is what we are looking for 926 1000 */ 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; 931 1006 p += l; 932 1007 break; … … 936 1011 } 937 1012 938 if (! 1013 if (!*tl) { 939 1014 /* it's a name (var/array/function), 940 1015 * otherwise it's something wrong 941 1016 */ 942 if (! 1017 if (!isalnum_(*p)) 943 1018 syntax_error(EMSG_UNEXP_TOKEN); 944 1019 945 t .string = --p;946 while (isalnum_(*(++p))) {1020 t_string = --p; 1021 while (isalnum_(*(++p))) { 947 1022 *(p-1) = *p; 948 1023 } … … 950 1025 tc = TC_VARIABLE; 951 1026 /* also consume whitespace between functionname and bracket */ 952 if (! (expected & TC_VARIABLE)) skip_spaces(&p); 1027 if (!(expected & TC_VARIABLE)) 1028 skip_spaces(&p); 953 1029 if (*p == '(') { 954 1030 tc = TC_FUNCTION; … … 961 1037 } 962 1038 } 963 pos = p;1039 g_pos = p; 964 1040 965 1041 /* skipping newlines in some cases */ … … 968 1044 969 1045 /* 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)) { 971 1047 concat_inserted = TRUE; 972 1048 save_tclass = tc; 973 save_info = t .info;1049 save_info = t_info; 974 1050 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; 981 1057 982 1058 /* Are we ready for this? */ 983 if (! 1059 if (!(ltclass & expected)) 984 1060 syntax_error((ltclass & (TC_NEWLINE | TC_EOF)) ? 985 1061 EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); 986 1062 987 1063 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 1070 static void rollback_token(void) 1071 { 1072 t_rollback = TRUE; 1073 } 991 1074 992 1075 static node *new_node(uint32_t info) 993 1076 { 994 registernode *n;995 996 n = (node *)xzalloc(sizeof(node));1077 node *n; 1078 1079 n = xzalloc(sizeof(node)); 997 1080 n->info = info; 998 n->lineno = lineno;1081 n->lineno = g_lineno; 999 1082 return n; 1000 1083 } 1001 1084 1002 static node *mk_re_node(c har *s, node *n, regex_t *re)1085 static node *mk_re_node(const char *s, node *n, regex_t *re) 1003 1086 { 1004 1087 n->info = OC_REGEXP; … … 1006 1089 n->r.ire = re + 1; 1007 1090 xregcomp(re, s, REG_EXTENDED); 1008 xregcomp(re +1, s, REG_EXTENDED | REG_ICASE);1091 xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); 1009 1092 1010 1093 return n; … … 1031 1114 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; 1032 1115 1033 while (! 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))) { 1035 1118 /* 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)); 1037 1120 cn->a.n = glptr; 1038 1121 xtc = TC_OPERAND | TC_UOPPRE; … … 1043 1126 * previous operators with higher priority */ 1044 1127 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)) ) 1047 1130 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); 1051 1134 cn->a.n = vn->a.n; 1052 1135 if (tc & TC_BINOP) { 1053 1136 cn->l.n = vn; 1054 1137 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; 1055 if ((t .info & OPCLSMASK) == OC_PGETLINE) {1138 if ((t_info & OPCLSMASK) == OC_PGETLINE) { 1056 1139 /* it's a pipe */ 1057 1140 next_token(TC_GETLINE); … … 1070 1153 * to last node */ 1071 1154 vn = cn; 1072 cn = vn->r.n = new_node(t .info);1155 cn = vn->r.n = new_node(t_info); 1073 1156 cn->a.n = vn; 1074 1157 xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; … … 1078 1161 * only simple tclasses should be used! */ 1079 1162 switch (tc) { 1080 1081 1163 case TC_VARIABLE: 1164 case TC_ARRAY: 1082 1165 cn->info = OC_VAR; 1083 if ((v = hash_search(ahash, t.string)) != NULL) { 1166 v = hash_search(ahash, t_string); 1167 if (v != NULL) { 1084 1168 cn->info = OC_FNARG; 1085 1169 cn->l.i = v->x.aidx; 1086 1170 } else { 1087 cn->l.v = newvar(t .string);1171 cn->l.v = newvar(t_string); 1088 1172 } 1089 1173 if (tc & TC_ARRAY) { … … 1093 1177 break; 1094 1178 1095 1096 1179 case TC_NUMBER: 1180 case TC_STRING: 1097 1181 cn->info = OC_VAR; 1098 1182 v = cn->l.v = xzalloc(sizeof(var)); 1099 1183 if (tc & TC_NUMBER) 1100 setvar_i(v, t .number);1184 setvar_i(v, t_double); 1101 1185 else 1102 setvar_s(v, t .string);1186 setvar_s(v, t_string); 1103 1187 break; 1104 1188 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)); 1108 1191 break; 1109 1192 1110 1193 case TC_FUNCTION: 1111 1194 cn->info = OC_FUNC; 1112 cn->r.f = newfunc(t .string);1195 cn->r.f = newfunc(t_string); 1113 1196 cn->l.n = condition(); 1114 1197 break; 1115 1198 1116 1199 case TC_SEQSTART: 1117 1200 cn = vn->r.n = parse_expr(TC_SEQTERM); 1118 1201 cn->a.n = vn; 1119 1202 break; 1120 1203 1121 1204 case TC_GETLINE: 1122 1205 glptr = cn; 1123 1206 xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; 1124 1207 break; 1125 1208 1126 1209 case TC_BUILTIN: 1127 1210 cn->l.n = condition(); 1128 1211 break; … … 1137 1220 static node *chain_node(uint32_t info) 1138 1221 { 1139 registernode *n;1140 1141 if (! 1222 node *n; 1223 1224 if (!seq->first) 1142 1225 seq->first = seq->last = new_node(0); 1143 1226 1144 if (seq->programname != programname) {1145 seq->programname = programname;1227 if (seq->programname != g_progname) { 1228 seq->programname = g_progname; 1146 1229 n = chain_node(OC_NEWSOURCE); 1147 n->l.s = bb_xstrdup(programname);1230 n->l.s = xstrdup(g_progname); 1148 1231 } 1149 1232 … … 1161 1244 n = chain_node(info); 1162 1245 n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); 1163 if (t .tclass & TC_GRPTERM)1246 if (t_tclass & TC_GRPTERM) 1164 1247 rollback_token(); 1165 1248 } … … 1199 1282 1200 1283 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; 1203 1286 rollback_token(); 1204 1287 chain_group(); … … 1208 1291 chain_expr(OC_EXEC | Vx); 1209 1292 } 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) { 1214 1301 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; 1227 1331 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); 1228 1336 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); 1289 1371 } 1290 1372 } … … 1298 1380 var *v; 1299 1381 1300 pos = p;1301 t .lineno = 1;1302 while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART |1303 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) { 1304 1386 1305 1387 if (tclass & TC_OPTERM) … … 1317 1399 } else if (tclass & TC_FUNCDECL) { 1318 1400 next_token(TC_FUNCTION); 1319 pos++;1320 f = newfunc(t .string);1401 g_pos++; 1402 f = newfunc(t_string); 1321 1403 f->body.first = NULL; 1322 1404 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); 1325 1407 v->x.aidx = (f->nargs)++; 1326 1408 … … 1336 1418 cn = chain_node(OC_TEST); 1337 1419 cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); 1338 if (t .tclass & TC_GRPSTART) {1420 if (t_tclass & TC_GRPSTART) { 1339 1421 rollback_token(); 1340 1422 chain_group(); … … 1354 1436 /* -------- program execution part -------- */ 1355 1437 1356 static node *mk_splitter(c har *s, tsplitter *spl)1357 { 1358 reg ister regex_t *re, *ire;1438 static node *mk_splitter(const char *s, tsplitter *spl) 1439 { 1440 regex_t *re, *ire; 1359 1441 node *n; 1360 1442 … … 1362 1444 ire = &spl->re[1]; 1363 1445 n = &spl->n; 1364 if ((n->info & &OPCLSMASK) == OC_REGEXP) {1446 if ((n->info & OPCLSMASK) == OC_REGEXP) { 1365 1447 regfree(re); 1366 regfree(ire); 1448 regfree(ire); // TODO: nuke ire, use re+1? 1367 1449 } 1368 1450 if (strlen(s) > 1) { … … 1382 1464 { 1383 1465 var *v; 1384 c har *s;1466 const char *s; 1385 1467 1386 1468 if ((op->info & OPCLSMASK) == OC_REGEXP) { 1387 1469 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; 1395 1476 } 1396 1477 … … 1398 1479 static void qrealloc(char **b, int n, int *size) 1399 1480 { 1400 if (! 1481 if (!*b || n >= *size) 1401 1482 *b = xrealloc(*b, *size = n + (n>>1) + 80); 1402 1483 } … … 1405 1486 static void fsrealloc(int size) 1406 1487 { 1407 static int maxfields = 0;1408 1488 int i; 1409 1489 … … 1411 1491 i = maxfields; 1412 1492 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++) { 1415 1495 Fields[i].type = VF_SPECIAL; 1416 1496 Fields[i].string = NULL; … … 1419 1499 1420 1500 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); 1423 1503 } 1424 1504 } … … 1426 1506 } 1427 1507 1428 static int awk_split(c har *s, node *spl, char **slist)1429 { 1430 int l, n =0;1508 static int awk_split(const char *s, node *spl, char **slist) 1509 { 1510 int l, n = 0; 1431 1511 char c[4]; 1432 1512 char *s1; 1433 regmatch_t pmatch[2]; 1513 regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... 1434 1514 1435 1515 /* 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); 1437 1518 1438 1519 c[0] = c[1] = (char)spl->info; 1439 1520 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 ) { 1447 1533 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 */ 1449 1539 } else { 1450 1540 pmatch[0].rm_eo = l; 1451 if (*(s+l)) pmatch[0].rm_eo++; 1452 } 1453 1541 if (s[l]) pmatch[0].rm_eo++; 1542 } 1454 1543 memcpy(s1, s, l); 1455 *(s1+l)= '\0';1544 s1[l] = '\0'; 1456 1545 nextword(&s1); 1457 1546 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'; 1458 1554 n++; 1459 1555 } 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 */ 1467 1559 if (icase) { 1468 1560 c[0] = toupper(c[0]); … … 1471 1563 if (*s1) n++; 1472 1564 while ((s1 = strpbrk(s1, c))) { 1473 * (s1++)= '\0';1565 *s1++ = '\0'; 1474 1566 n++; 1475 1567 } 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'; 1485 1578 } 1486 1579 return n; … … 1489 1582 static void split_f0(void) 1490 1583 { 1491 static char *fstrings = NULL; 1584 /* static char *fstrings; */ 1585 #define fstrings (G.split_f0__fstrings) 1586 1492 1587 int i, n; 1493 1588 char *s; … … 1499 1594 free(fstrings); 1500 1595 fsrealloc(0); 1501 n = awk_split(getvar_s( V[F0]), &fsplitter.n, &fstrings);1596 n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings); 1502 1597 fsrealloc(n); 1503 1598 s = fstrings; 1504 for (i =0; i<n; i++) {1599 for (i = 0; i < n; i++) { 1505 1600 Fields[i].string = nextword(&s); 1506 1601 Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY); … … 1508 1603 1509 1604 /* 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 1513 1609 } 1514 1610 … … 1517 1613 { 1518 1614 int n; 1519 char *b, *sep, *s; 1615 char *b; 1616 const char *sep, *s; 1520 1617 int sl, l, len, i, bsize; 1521 1618 1522 if (! 1619 if (!(v->type & VF_SPECIAL)) 1523 1620 return; 1524 1621 1525 if (v == V[NF]) {1622 if (v == intvar[NF]) { 1526 1623 n = (int)getvar_i(v); 1527 1624 fsrealloc(n); 1528 1625 1529 1626 /* recalculate $0 */ 1530 sep = getvar_s( V[OFS]);1627 sep = getvar_s(intvar[OFS]); 1531 1628 sl = strlen(sep); 1532 1629 b = NULL; 1533 1630 len = 0; 1534 for (i =0; i<n; i++) {1631 for (i = 0; i < n; i++) { 1535 1632 s = getvar_s(&Fields[i]); 1536 1633 l = strlen(s); … … 1543 1640 len += l; 1544 1641 } 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); 1547 1645 is_f0_split = TRUE; 1548 1646 1549 } else if (v == V[F0]) {1647 } else if (v == intvar[F0]) { 1550 1648 is_f0_split = FALSE; 1551 1649 1552 } else if (v == V[FS]) {1650 } else if (v == intvar[FS]) { 1553 1651 mk_splitter(getvar_s(v), &fsplitter); 1554 1652 1555 } else if (v == V[RS]) {1653 } else if (v == intvar[RS]) { 1556 1654 mk_splitter(getvar_s(v), &rsplitter); 1557 1655 1558 } else if (v == V[IGNORECASE]) {1656 } else if (v == intvar[IGNORECASE]) { 1559 1657 icase = istrue(v); 1560 1658 1561 } else { 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); 1564 1662 /* right here v is invalid. Just to note... */ 1565 1663 } … … 1591 1689 1592 1690 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++) { 1596 1694 hi = array->items[i]; 1597 while (hi) {1695 while (hi) { 1598 1696 strcpy(*w, hi->name); 1599 1697 nextword(w); … … 1608 1706 1609 1707 w = v->x.walker; 1610 if ( *(w+1) == *w)1708 if (w[1] == w[0]) 1611 1709 return FALSE; 1612 1710 … … 1618 1716 static int ptest(node *pattern) 1619 1717 { 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)); 1622 1720 } 1623 1721 … … 1642 1740 rp = 0; 1643 1741 1644 if (! 1742 if (!m) qrealloc(&m, 256, &size); 1645 1743 do { 1646 1744 b = m + a; … … 1650 1748 if ((rsplitter.n.info & OPCLSMASK) == OC_REGEXP) { 1651 1749 if (regexec(icase ? rsplitter.n.r.ire : rsplitter.n.l.re, 1652 1750 b, 1, pmatch, 0) == 0) { 1653 1751 so = pmatch[0].rm_so; 1654 1752 eo = pmatch[0].rm_eo; … … 1658 1756 } else if (c != '\0') { 1659 1757 s = strchr(b+pp, c); 1660 if (! 1758 if (!s) s = memchr(b+pp, '\0', p - pp); 1661 1759 if (s) { 1662 1760 so = eo = s-b; … … 1690 1788 p = 0; 1691 1789 r = 0; 1692 setvar_i( V[ERRNO], errno);1790 setvar_i(intvar[ERRNO], errno); 1693 1791 } 1694 1792 b[p] = '\0'; … … 1704 1802 b[so] = c; 1705 1803 c = b[eo]; b[eo] = '\0'; 1706 setvar_s( V[RT], b+so);1804 setvar_s(intvar[RT], b+so); 1707 1805 b[eo] = c; 1708 1806 } … … 1718 1816 static int fmt_num(char *b, int size, const char *format, double n, int int_as_int) 1719 1817 { 1720 int r =0;1818 int r = 0; 1721 1819 char c; 1722 const char *s =format;1820 const char *s = format; 1723 1821 1724 1822 if (int_as_int && n == (int)n) { 1725 1823 r = snprintf(b, size, "%d", (int)n); 1726 1824 } else { 1727 do { c = *s; } while ( *s&& *++s);1825 do { c = *s; } while (c && *++s); 1728 1826 if (strchr("diouxX", c)) { 1729 1827 r = snprintf(b, size, format, (int)n); … … 1731 1829 r = snprintf(b, size, format, n); 1732 1830 } else { 1733 runtime_error(EMSG_INV_FMT);1831 syntax_error(EMSG_INV_FMT); 1734 1832 } 1735 1833 } … … 1742 1840 { 1743 1841 char *b = NULL; 1744 char *fmt, *s, *s1, *f; 1842 char *fmt, *s, *f; 1843 const char *s1; 1745 1844 int i, j, incr, bsize; 1746 1845 char c, c1; … … 1748 1847 1749 1848 v = nvalloc(1); 1750 fmt = f = bb_xstrdup(getvar_s(evaluate(nextarg(&n), v)));1849 fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), v))); 1751 1850 1752 1851 i = 0; … … 1755 1854 while (*f && (*f != '%' || *(++f) == '%')) 1756 1855 f++; 1757 while (*f && !isalpha(*f)) 1856 while (*f && !isalpha(*f)) { 1857 if (*f == '*') 1858 syntax_error("%*x formats are not supported"); 1758 1859 f++; 1860 } 1759 1861 1760 1862 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'; 1764 1868 arg = evaluate(nextarg(&n), v); 1765 1869 1766 1870 j = i; 1767 1871 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)); 1771 1874 } else if (c == 's') { 1772 1875 s1 = getvar_s(arg); 1773 1876 qrealloc(&b, incr+i+strlen(s1), &bsize); 1774 1877 i += sprintf(b+i, s, s1); 1775 1776 1878 } else { 1777 1879 i += fmt_num(b+i, incr, s, getvar_i(arg), FALSE); … … 1781 1883 /* if there was an error while sprintf, return value is negative */ 1782 1884 if (i < j) i = j; 1783 1784 } 1785 1786 b = xrealloc(b, i+1); 1885 } 1886 1887 b = xrealloc(b, i + 1); 1787 1888 free(fmt); 1788 1889 nvfree(v); … … 1797 1898 * subexpression matching (\1-\9) 1798 1899 */ 1799 static int awk_sub(node *rn, c har *repl, int nm, var *src, var *dest, int ex)1900 static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest, int ex) 1800 1901 { 1801 1902 char *ds = NULL; 1802 char *sp, *s; 1903 const char *s; 1904 const char *sp; 1803 1905 int c, i, j, di, rl, so, eo, nbs, n, dssize; 1804 1906 regmatch_t pmatch[10]; … … 1806 1908 1807 1909 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]; 1810 1912 1811 1913 i = di = 0; 1812 1914 sp = getvar_s(src); 1813 1915 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) { 1815 1917 so = pmatch[0].rm_so; 1816 1918 eo = pmatch[0].rm_eo; … … 1852 1954 if (i == nm) break; 1853 1955 if (eo == so) { 1854 if (! (ds[di++] = *sp++)) break; 1956 ds[di] = *sp++; 1957 if (!ds[di++]) break; 1855 1958 } 1856 1959 } … … 1865 1968 static var *exec_builtin(node *op, var *res) 1866 1969 { 1970 #define tspl (G.exec_builtin__tspl) 1971 1867 1972 int (*to_xxx)(int); 1868 1973 var *tv; 1869 1974 node *an[4]; 1870 var 1871 c har *as[4];1975 var *av[4]; 1976 const char *as[4]; 1872 1977 regmatch_t pmatch[2]; 1873 1978 regex_t sreg, *re; 1874 static tsplitter tspl;1875 1979 node *spl; 1876 1980 uint32_t isr, info; … … 1885 1989 1886 1990 av[2] = av[3] = NULL; 1887 for (i =0 ; i<4 && op; i++) {1991 for (i = 0; i < 4 && op; i++) { 1888 1992 an[i] = nextarg(&op); 1889 1993 if (isr & 0x09000000) av[i] = evaluate(an[i], &tv[i]); … … 1894 1998 nargs = i; 1895 1999 if (nargs < (info >> 30)) 1896 runtime_error(EMSG_TOO_FEW_ARGS);2000 syntax_error(EMSG_TOO_FEW_ARGS); 1897 2001 1898 2002 switch (info & OPNMASK) { 1899 2003 1900 1901 #if def CONFIG_FEATURE_AWK_MATH2004 case B_a2: 2005 #if ENABLE_FEATURE_AWK_MATH 1902 2006 setvar_i(res, atan2(getvar_i(av[i]), getvar_i(av[1]))); 1903 2007 #else 1904 runtime_error(EMSG_NO_MATH);2008 syntax_error(EMSG_NO_MATH); 1905 2009 #endif 1906 2010 break; 1907 2011 1908 2012 case B_sp: 1909 2013 if (nargs > 2) { 1910 2014 spl = (an[2]->info & OPCLSMASK) == OC_REGEXP ? … … 1923 2027 break; 1924 2028 1925 2029 case B_ss: 1926 2030 l = strlen(as[0]); 1927 2031 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; 1929 2034 n = (nargs > 2) ? getvar_i(av[2]) : l-i; 1930 if (n <0) n=0;2035 if (n < 0) n = 0; 1931 2036 s = xmalloc(n+1); 1932 2037 strncpy(s, as[0]+i, n); … … 1935 2040 break; 1936 2041 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: 1938 2067 to_xxx = tolower; 1939 2068 goto lo_cont; 1940 2069 1941 2070 case B_up: 1942 2071 to_xxx = toupper; 1943 lo_cont:1944 s1 = s = bb_xstrdup(as[0]);2072 lo_cont: 2073 s1 = s = xstrdup(as[0]); 1945 2074 while (*s1) { 1946 2075 *s1 = (*to_xxx)(*s1); … … 1950 2079 break; 1951 2080 1952 2081 case B_ix: 1953 2082 n = 0; 1954 2083 ll = strlen(as[1]); 1955 2084 l = strlen(as[0]) - ll; 1956 2085 if (ll > 0 && l >= 0) { 1957 if (! 2086 if (!icase) { 1958 2087 s = strstr(as[0], as[1]); 1959 2088 if (s) n = (s - as[0]) + 1; … … 1973 2102 break; 1974 2103 1975 2104 case B_ti: 1976 2105 if (nargs > 1) 1977 2106 tt = getvar_i(av[1]); 1978 2107 else 1979 2108 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); 1984 2115 break; 1985 2116 1986 2117 case B_ma: 1987 2118 re = as_regex(an[1], &sreg); 1988 2119 n = regexec(re, as[0], 1, pmatch, 0); … … 2000 2131 break; 2001 2132 2002 2133 case B_ge: 2003 2134 awk_sub(an[0], as[1], getvar_i(av[2]), av[3], res, TRUE); 2004 2135 break; 2005 2136 2006 2137 case B_gs: 2007 2138 setvar_i(res, awk_sub(an[0], as[1], 0, av[2], av[2], FALSE)); 2008 2139 break; 2009 2140 2010 2141 case B_su: 2011 2142 setvar_i(res, awk_sub(an[0], as[1], 1, av[2], av[2], FALSE)); 2012 2143 break; … … 2015 2146 nvfree(tv); 2016 2147 return res; 2148 #undef tspl 2017 2149 } 2018 2150 … … 2025 2157 static var *evaluate(node *op, var *res) 2026 2158 { 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 2031 2165 node *op1; 2032 2166 var *v1; 2033 2167 union { 2034 2168 var *v; 2035 c har *s;2169 const char *s; 2036 2170 double d; 2037 2171 int i; 2038 2172 } L, R; 2039 2173 uint32_t opinfo; 2040 short opn;2174 int opn; 2041 2175 union { 2042 2176 char *s; … … 2048 2182 } X; 2049 2183 2050 if (! 2184 if (!op) 2051 2185 return setvar_s(res, NULL); 2052 2186 … … 2054 2188 2055 2189 while (op) { 2056 2057 2190 opinfo = op->info; 2058 opn = ( short)(opinfo & OPNMASK);2059 lineno = op->lineno;2191 opn = (opinfo & OPNMASK); 2192 g_lineno = op->lineno; 2060 2193 2061 2194 /* execute inevitable things */ … … 2069 2202 switch (XC(opinfo & OPCLSMASK)) { 2070 2203 2071 2072 2073 2074 2204 /* -- iterative node type -- */ 2205 2206 /* test pattern */ 2207 case XC( OC_TEST ): 2075 2208 if ((op1->info & OPCLSMASK) == OC_COMMA) { 2076 2209 /* it's range pattern */ … … 2089 2222 break; 2090 2223 2091 2092 2093 break; 2094 2095 2096 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 ): 2097 2230 op = istrue(L.v) ? op->a.n : op->r.n; 2098 2231 break; 2099 2232 2100 2101 2233 /* initialize for-in loop */ 2234 case XC( OC_WALKINIT ): 2102 2235 hashwalk_init(L.v, iamarray(R.v)); 2103 2236 break; 2104 2237 2105 2106 2238 /* get next array item */ 2239 case XC( OC_WALKNEXT ): 2107 2240 op = hashwalk_next(L.v) ? op->a.n : op->r.n; 2108 2241 break; 2109 2242 2110 2111 2243 case XC( OC_PRINT ): 2244 case XC( OC_PRINTF ): 2112 2245 X.F = stdout; 2113 2246 if (op->r.n) { 2114 2247 X.rsm = newfile(R.s); 2115 if (! 2248 if (!X.rsm->F) { 2116 2249 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) 2118 2252 bb_perror_msg_and_die("popen"); 2119 2253 X.rsm->is_pipe = 1; 2120 2254 } else { 2121 X.rsm->F = bb_xfopen(R.s, opn=='w' ? "w" : "a");2255 X.rsm->F = xfopen(R.s, opn=='w' ? "w" : "a"); 2122 2256 } 2123 2257 } … … 2126 2260 2127 2261 if ((opinfo & OPCLSMASK) == OC_PRINT) { 2128 if (! 2129 fputs(getvar_s( V[F0]), X.F);2262 if (!op1) { 2263 fputs(getvar_s(intvar[F0]), X.F); 2130 2264 } else { 2131 2265 while (op1) { 2132 2266 L.v = evaluate(nextarg(&op1), v1); 2133 2267 if (L.v->type & VF_NUMBER) { 2134 fmt_num( buf, MAXVARFMT, getvar_s(V[OFMT]),2135 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); 2137 2271 } else { 2138 2272 fputs(getvar_s(L.v), X.F); 2139 2273 } 2140 2274 2141 if (op1) fputs(getvar_s( V[OFS]), X.F);2275 if (op1) fputs(getvar_s(intvar[OFS]), X.F); 2142 2276 } 2143 2277 } 2144 fputs(getvar_s( V[ORS]), X.F);2278 fputs(getvar_s(intvar[ORS]), X.F); 2145 2279 2146 2280 } else { /* OC_PRINTF */ 2147 2281 L.s = awk_printf(op1); 2148 2282 fputs(L.s, X.F); 2149 free( L.s);2283 free((char*)L.s); 2150 2284 } 2151 2285 fflush(X.F); 2152 2286 break; 2153 2287 2154 2288 case XC( OC_DELETE ): 2155 2289 X.info = op1->info & OPCLSMASK; 2156 2290 if (X.info == OC_VAR) { … … 2159 2293 R.v = &fnargs[op1->l.i]; 2160 2294 } else { 2161 runtime_error(EMSG_NOT_ARRAY);2295 syntax_error(EMSG_NOT_ARRAY); 2162 2296 } 2163 2297 … … 2171 2305 break; 2172 2306 2173 2174 programname = op->l.s;2175 break; 2176 2177 2307 case XC( OC_NEWSOURCE ): 2308 g_progname = op->l.s; 2309 break; 2310 2311 case XC( OC_RETURN ): 2178 2312 copyvar(res, L.v); 2179 2313 break; 2180 2314 2181 2315 case XC( OC_NEXTFILE ): 2182 2316 nextfile = TRUE; 2183 2317 case XC( OC_NEXT ): 2184 2318 nextrec = TRUE; 2185 2319 case XC( OC_DONE ): 2186 2320 clrvar(res); 2187 2321 break; 2188 2322 2189 2323 case XC( OC_EXIT ): 2190 2324 awk_exit(L.d); 2191 2325 2192 2193 2194 2326 /* -- recursive node type -- */ 2327 2328 case XC( OC_VAR ): 2195 2329 L.v = op->l.v; 2196 if (L.v == V[NF])2330 if (L.v == intvar[NF]) 2197 2331 split_f0(); 2198 2332 goto v_cont; 2199 2333 2200 2334 case XC( OC_FNARG ): 2201 2335 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 ): 2208 2341 setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); 2209 2342 break; 2210 2343 2211 2344 case XC( OC_REGEXP ): 2212 2345 op1 = op; 2213 L.s = getvar_s( V[F0]);2346 L.s = getvar_s(intvar[F0]); 2214 2347 goto re_cont; 2215 2348 2216 2349 case XC( OC_MATCH ): 2217 2350 op1 = op->r.n; 2218 re_cont:2351 re_cont: 2219 2352 X.re = as_regex(op1, &sreg); 2220 2353 R.i = regexec(X.re, L.s, 0, NULL, 0); … … 2223 2356 break; 2224 2357 2225 2358 case XC( OC_MOVE ): 2226 2359 /* if source is a temporary string, jusk relink it to dest */ 2227 2360 if (R.v == v1+1 && R.v->string) { … … 2233 2366 break; 2234 2367 2235 2368 case XC( OC_TERNARY ): 2236 2369 if ((op->r.n->info & OPCLSMASK) != OC_COLON) 2237 runtime_error(EMSG_POSSIBLE_ERROR);2370 syntax_error(EMSG_POSSIBLE_ERROR); 2238 2371 res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); 2239 2372 break; 2240 2373 2241 2242 if (! 2243 runtime_error(EMSG_UNDEF_FUNC);2374 case XC( OC_FUNC ): 2375 if (!op->r.f->body.first) 2376 syntax_error(EMSG_UNDEF_FUNC); 2244 2377 2245 2378 X.v = R.v = nvalloc(op->r.f->nargs+1); … … 2256 2389 fnargs = X.v; 2257 2390 2258 L.s = programname;2391 L.s = g_progname; 2259 2392 res = evaluate(op->r.f->body.first, res); 2260 programname = L.s;2393 g_progname = L.s; 2261 2394 2262 2395 nvfree(fnargs); … … 2264 2397 break; 2265 2398 2266 2267 2399 case XC( OC_GETLINE ): 2400 case XC( OC_PGETLINE ): 2268 2401 if (op1) { 2269 2402 X.rsm = newfile(L.s); 2270 if (! 2403 if (!X.rsm->F) { 2271 2404 if ((opinfo & OPCLSMASK) == OC_PGETLINE) { 2272 2405 X.rsm->F = popen(L.s, "r"); 2273 2406 X.rsm->is_pipe = TRUE; 2274 2407 } else { 2275 X.rsm->F = fopen(L.s, "r"); /* not bb_xfopen! */2408 X.rsm->F = fopen(L.s, "r"); /* not xfopen! */ 2276 2409 } 2277 2410 } 2278 2411 } else { 2279 if (! 2412 if (!iF) iF = next_input_file(); 2280 2413 X.rsm = iF; 2281 2414 } 2282 2415 2283 if (! 2284 setvar_i( V[ERRNO], errno);2416 if (!X.rsm->F) { 2417 setvar_i(intvar[ERRNO], errno); 2285 2418 setvar_i(res, -1); 2286 2419 break; 2287 2420 } 2288 2421 2289 if (! 2290 R.v = V[F0];2422 if (!op->r.n) 2423 R.v = intvar[F0]; 2291 2424 2292 2425 L.i = awk_getline(X.rsm, R.v); 2293 2426 if (L.i > 0) { 2294 if (! 2295 incvar( V[FNR]);2296 incvar( V[NR]);2427 if (!op1) { 2428 incvar(intvar[FNR]); 2429 incvar(intvar[NR]); 2297 2430 } 2298 2431 } … … 2300 2433 break; 2301 2434 2302 2303 2435 /* simple builtins */ 2436 case XC( OC_FBLTIN ): 2304 2437 switch (opn) { 2305 2438 2306 2439 case F_in: 2307 2440 R.d = (int)L.d; 2308 2441 break; 2309 2442 2310 2311 R.d = 2443 case F_rn: 2444 R.d = (double)rand() / (double)RAND_MAX; 2312 2445 break; 2313 2314 #ifdef CONFIG_FEATURE_AWK_MATH 2315 case F_co: 2446 #if ENABLE_FEATURE_AWK_MATH 2447 case F_co: 2316 2448 R.d = cos(L.d); 2317 2449 break; 2318 2450 2319 2451 case F_ex: 2320 2452 R.d = exp(L.d); 2321 2453 break; 2322 2454 2323 2455 case F_lg: 2324 2456 R.d = log(L.d); 2325 2457 break; 2326 2458 2327 2459 case F_si: 2328 2460 R.d = sin(L.d); 2329 2461 break; 2330 2462 2331 2463 case F_sq: 2332 2464 R.d = sqrt(L.d); 2333 2465 break; 2334 2466 #else 2335 2336 2337 2338 2339 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); 2341 2473 break; 2342 2474 #endif 2343 2344 case F_sr: 2475 case F_sr: 2345 2476 R.d = (double)seed; 2346 seed = op1 ? (unsigned int)L.d : (unsigned int)time(NULL);2477 seed = op1 ? (unsigned)L.d : (unsigned)time(NULL); 2347 2478 srand(seed); 2348 2479 break; 2349 2480 2350 2481 case F_ti: 2351 2482 R.d = time(NULL); 2352 2483 break; 2353 2484 2354 2355 if (! 2356 L.s = getvar_s( V[F0]);2485 case F_le: 2486 if (!op1) 2487 L.s = getvar_s(intvar[F0]); 2357 2488 R.d = strlen(L.s); 2358 2489 break; 2359 2490 2360 2491 case F_sy: 2361 2492 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; 2363 2495 break; 2364 2496 2365 2366 if (! 2497 case F_ff: 2498 if (!op1) 2367 2499 fflush(stdout); 2368 2500 else { … … 2376 2508 break; 2377 2509 2378 2510 case F_cl: 2379 2511 X.rsm = (rstream *)hash_search(fdhash, L.s); 2380 2512 if (X.rsm) { … … 2384 2516 } 2385 2517 if (R.i != 0) 2386 setvar_i( V[ERRNO], errno);2518 setvar_i(intvar[ERRNO], errno); 2387 2519 R.d = (double)R.i; 2388 2520 break; … … 2391 2523 break; 2392 2524 2393 2525 case XC( OC_BUILTIN ): 2394 2526 res = exec_builtin(op, res); 2395 2527 break; 2396 2528 2397 2529 case XC( OC_SPRINTF ): 2398 2530 setvar_p(res, awk_printf(op1)); 2399 2531 break; 2400 2532 2401 2533 case XC( OC_UNARY ): 2402 2534 X.v = R.v; 2403 2535 L.d = R.d = getvar_i(R.v); 2404 2536 switch (opn) { 2405 2537 case 'P': 2406 2538 L.d = ++R.d; 2407 2539 goto r_op_change; 2408 2540 case 'p': 2409 2541 R.d++; 2410 2542 goto r_op_change; 2411 2543 case 'M': 2412 2544 L.d = --R.d; 2413 2545 goto r_op_change; 2414 2546 case 'm': 2415 2547 R.d--; 2416 2548 goto r_op_change; 2417 2418 2549 case '!': 2550 L.d = istrue(X.v) ? 0 : 1; 2419 2551 break; 2420 2552 case '-': 2421 2553 L.d = -R.d; 2422 2554 break; 2423 2555 r_op_change: 2424 2556 setvar_i(X.v, R.d); 2425 2557 } … … 2427 2559 break; 2428 2560 2429 2561 case XC( OC_FIELD ): 2430 2562 R.i = (int)getvar_i(R.v); 2431 2563 if (R.i == 0) { 2432 res = V[F0];2564 res = intvar[F0]; 2433 2565 } else { 2434 2566 split_f0(); 2435 2567 if (R.i > nfields) 2436 2568 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 ): 2445 2576 opn = strlen(L.s) + strlen(R.s) + 2; 2446 X.s = (char *)xmalloc(opn);2577 X.s = xmalloc(opn); 2447 2578 strcpy(X.s, L.s); 2448 2579 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)); 2451 2582 strcat(X.s, L.s); 2452 2583 } … … 2455 2586 break; 2456 2587 2457 2588 case XC( OC_LAND ): 2458 2589 setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); 2459 2590 break; 2460 2591 2461 2592 case XC( OC_LOR ): 2462 2593 setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); 2463 2594 break; 2464 2595 2465 2466 2596 case XC( OC_BINARY ): 2597 case XC( OC_REPLACE ): 2467 2598 R.d = getvar_i(R.v); 2468 2599 switch (opn) { 2469 2600 case '+': 2470 2601 L.d += R.d; 2471 2602 break; 2472 2603 case '-': 2473 2604 L.d -= R.d; 2474 2605 break; 2475 2606 case '*': 2476 2607 L.d *= R.d; 2477 2608 break; 2478 2479 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);2609 case '/': 2610 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2480 2611 L.d /= R.d; 2481 2612 break; 2482 2483 #if def CONFIG_FEATURE_AWK_MATH2613 case '&': 2614 #if ENABLE_FEATURE_AWK_MATH 2484 2615 L.d = pow(L.d, R.d); 2485 2616 #else 2486 runtime_error(EMSG_NO_MATH);2617 syntax_error(EMSG_NO_MATH); 2487 2618 #endif 2488 2619 break; 2489 2490 if (R.d == 0) runtime_error(EMSG_DIV_BY_ZERO);2620 case '%': 2621 if (R.d == 0) syntax_error(EMSG_DIV_BY_ZERO); 2491 2622 L.d -= (int)(L.d / R.d) * R.d; 2492 2623 break; 2493 2624 } 2494 res = setvar_i(((opinfo &OPCLSMASK) == OC_BINARY) ? res : X.v, L.d);2495 break; 2496 2497 2625 res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : X.v, L.d); 2626 break; 2627 2628 case XC( OC_COMPARE ): 2498 2629 if (is_numeric(L.v) && is_numeric(R.v)) { 2499 2630 L.d = getvar_i(L.v) - getvar_i(R.v); … … 2504 2635 } 2505 2636 switch (opn & 0xfe) { 2506 2637 case 0: 2507 2638 R.i = (L.d > 0); 2508 2639 break; 2509 2640 case 2: 2510 2641 R.i = (L.d >= 0); 2511 2642 break; 2512 2643 case 4: 2513 2644 R.i = (L.d == 0); 2514 2645 break; … … 2517 2648 break; 2518 2649 2519 2520 runtime_error(EMSG_POSSIBLE_ERROR);2650 default: 2651 syntax_error(EMSG_POSSIBLE_ERROR); 2521 2652 } 2522 2653 if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) … … 2529 2660 nvfree(v1); 2530 2661 return res; 2662 #undef fnargs 2663 #undef seed 2664 #undef sreg 2531 2665 } 2532 2666 … … 2536 2670 static int awk_exit(int r) 2537 2671 { 2538 unsigned int i; 2672 var tv; 2673 unsigned i; 2539 2674 hash_item *hi; 2540 static var tv; 2541 2542 if (! exiting) { 2675 2676 zero_out_var(&tv); 2677 2678 if (!exiting) { 2543 2679 exiting = TRUE; 2544 2680 nextrec = FALSE; … … 2547 2683 2548 2684 /* waiting for children */ 2549 for (i =0; i<fdhash->csize; i++) {2685 for (i = 0; i < fdhash->csize; i++) { 2550 2686 hi = fdhash->items[i]; 2551 while (hi) {2687 while (hi) { 2552 2688 if (hi->data.rs.F && hi->data.rs.is_pipe) 2553 2689 pclose(hi->data.rs.F); … … 2565 2701 char *exprc, *s, *s0, *s1; 2566 2702 2567 exprc = bb_xstrdup(expr);2703 exprc = xstrdup(expr); 2568 2704 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { 2569 2705 free(exprc); … … 2585 2721 static rstream *next_input_file(void) 2586 2722 { 2587 static rstream rsm; 2723 #define rsm (G.next_input_file__rsm) 2724 #define files_happen (G.next_input_file__files_happen) 2725 2588 2726 FILE *F = NULL; 2589 char *fname, *ind; 2590 static int files_happen = FALSE; 2727 const char *fname, *ind; 2591 2728 2592 2729 if (rsm.F) fclose(rsm.F); … … 2595 2732 2596 2733 do { 2597 if (getvar_i( V[ARGIND])+1 >= getvar_i(V[ARGC])) {2734 if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { 2598 2735 if (files_happen) 2599 2736 return NULL; … … 2601 2738 F = stdin; 2602 2739 } 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)); 2605 2742 if (fname && *fname && !is_assignment(fname)) 2606 2743 F = afopen(fname, "r"); … … 2609 2746 2610 2747 files_happen = TRUE; 2611 setvar_s( V[FILENAME], fname);2748 setvar_s(intvar[FILENAME], fname); 2612 2749 rsm.F = F; 2613 2750 return &rsm; 2614 } 2615 2751 #undef rsm 2752 #undef files_happen 2753 } 2754 2755 int awk_main(int argc, char **argv); 2616 2756 int awk_main(int argc, char **argv) 2617 2757 { 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; 2620 2762 var *v; 2621 staticvar tv;2763 var tv; 2622 2764 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); 2627 2776 2628 2777 /* allocate global buffer */ 2629 buf = xmalloc(MAXVARFMT+1);2778 g_buf = xmalloc(MAXVARFMT + 1); 2630 2779 2631 2780 vhash = hash_init(); … … 2635 2784 2636 2785 /* initialize variables */ 2637 for (i =0; *vNames;i++) {2638 V[i] = v = newvar(nextword(&vNames));2639 if (*v Values != '\377')2640 setvar_s(v, nextword(&v Values));2786 for (i = 0; *vnames; i++) { 2787 intvar[i] = v = newvar(nextword(&vnames)); 2788 if (*vvalues != '\377') 2789 setvar_s(v, nextword(&vvalues)); 2641 2790 else 2642 2791 setvar_i(v, 0); 2643 2792 2644 if (*v Names == '*') {2793 if (*vnames == '*') { 2645 2794 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); 2670 2847 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) 2714 2850 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); 2719 2857 2720 2858 /* 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++); 2725 2864 2726 2865 evaluate(beginseq.first, &tv); 2727 if (! mainseq.first && !endseq.first)2866 if (!mainseq.first && !endseq.first) 2728 2867 awk_exit(EXIT_SUCCESS); 2729 2868 2730 2869 /* input file could already be opened in BEGIN block */ 2731 if (! 2870 if (!iF) iF = next_input_file(); 2732 2871 2733 2872 /* passing through input files */ 2734 2873 while (iF) { 2735 2736 2874 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) { 2741 2878 nextrec = FALSE; 2742 incvar( V[NR]);2743 incvar( V[FNR]);2879 incvar(intvar[NR]); 2880 incvar(intvar[FNR]); 2744 2881 evaluate(mainseq.first, &tv); 2745 2882 … … 2748 2885 } 2749 2886 2750 if ( c< 0)2751 runtime_error(strerror(errno));2887 if (i < 0) 2888 syntax_error(strerror(errno)); 2752 2889 2753 2890 iF = next_input_file(); 2754 2755 2891 } 2756 2892 2757 2893 awk_exit(EXIT_SUCCESS); 2758 2759 return 0; 2760 } 2761 2894 /*return 0;*/ 2895 } -
branches/stable/mindi-busybox/editors/ed.c
r821 r1770 8 8 */ 9 9 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 14 enum { 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 22 20 typedef struct LINE { 23 21 struct LINE *next; … … 29 27 static LINE lines, *curLine; 30 28 static int curNum, lastNum, marks[26], dirty; 31 static char *bufBase, *bufPtr, *fileName , searchString[USERSIZE];29 static char *bufBase, *bufPtr, *fileName; 32 30 static int bufUsed, bufSize; 33 31 … … 49 47 static int findString(const LINE *lp, const char * str, int len, int offset); 50 48 49 int ed_main(int argc, char **argv); 51 50 int ed_main(int argc, char **argv) 52 51 { … … 58 57 59 58 if (fileName == NULL) { 60 bb_error_msg(" No memory");59 bb_error_msg("no memory"); 61 60 termEdit(); 62 61 return EXIT_SUCCESS; … … 89 88 int len, num1, num2, have1, have2; 90 89 91 while (TRUE) 92 { 90 while (TRUE) { 93 91 printf(": "); 94 92 fflush(stdout); … … 104 102 endbuf = &buf[len - 1]; 105 103 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 { 112 108 len = fgetc(stdin); 113 } 114 while ((len != EOF) && (len != '\n')); 109 } while ((len != EOF) && (len != '\n')); 115 110 116 111 continue; … … 130 125 have2 = FALSE; 131 126 132 if ((curNum == 0) && (lastNum > 0)) 133 { 127 if ((curNum == 0) && (lastNum > 0)) { 134 128 curNum = 1; 135 129 curLine = lines.next; … … 142 136 cp++; 143 137 144 if (*cp == ',') 145 { 138 if (*cp == ',') { 146 139 cp++; 147 140 … … 165 158 num2 = num1; 166 159 167 switch (*cp++) 168 { 160 switch (*cp++) { 169 161 case 'a': 170 162 addLines(num1 + 1); … … 181 173 182 174 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"); 186 177 break; 187 178 } … … 190 181 cp++; 191 182 192 if (*cp == '\0') 193 { 183 if (*cp == '\0') { 194 184 if (fileName) 195 185 printf("\"%s\"\n", fileName); 196 186 else 197 187 printf("No file name\n"); 198 199 188 break; 200 189 } … … 202 191 newname = strdup(cp); 203 192 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"); 207 195 break; 208 196 } … … 222 210 cp++; 223 211 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"); 227 214 break; 228 215 } … … 243 230 cp++; 244 231 245 if (have1 || *cp) 246 { 247 bb_error_msg("Bad quit command"); 232 if (have1 || *cp) { 233 bb_error_msg("bad quit command"); 248 234 break; 249 235 } … … 268 254 269 255 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"); 273 258 break; 274 259 } … … 277 262 cp++; 278 263 279 if (*cp == '\0') 280 { 281 bb_error_msg("No file name"); 264 if (*cp == '\0') { 265 bb_error_msg("no file name"); 282 266 break; 283 267 } … … 299 283 300 284 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"); 304 287 break; 305 288 } … … 316 299 cp = fileName; 317 300 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"); 321 303 break; 322 304 } … … 326 308 327 309 case 'z': 328 switch (*cp) 329 { 310 switch (*cp) { 330 311 case '-': 331 312 printLines(curNum-21, curNum, FALSE); … … 341 322 342 323 case '.': 343 if (have1) 344 { 345 bb_error_msg("No arguments allowed"); 324 if (have1) { 325 bb_error_msg("no arguments allowed"); 346 326 break; 347 327 } … … 361 341 362 342 case '\0': 363 if (have1) 364 { 343 if (have1) { 365 344 printLines(num2, num2, FALSE); 366 345 break; … … 373 352 374 353 default: 375 bb_error_msg(" Unimplemented command");354 bb_error_msg("unimplemented command"); 376 355 break; 377 356 } … … 387 366 { 388 367 char *cp, *oldStr, *newStr, buf[USERSIZE]; 389 int 368 int delim, oldLen, newLen, deltaLen, offset; 390 369 LINE *lp, *nlp; 391 370 int globalFlag, printFlag, didSub, needPrint; 392 371 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"); 397 374 return; 398 375 } … … 409 386 cp = buf; 410 387 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"); 415 390 return; 416 391 } … … 421 396 cp = strchr(cp, delim); 422 397 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"); 427 400 return; 428 401 } … … 436 409 *cp++ = '\0'; 437 410 else 438 cp = ""; 439 440 while (*cp) switch (*cp++) 441 { 411 cp = (char*)""; 412 413 while (*cp) switch (*cp++) { 442 414 case 'g': 443 415 globalFlag = TRUE; … … 449 421 450 422 default: 451 bb_error_msg("Unknown option for substitute"); 452 423 bb_error_msg("unknown option for substitute"); 453 424 return; 454 425 } 455 426 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"); 462 430 return; 463 431 } … … 480 448 nlp = NULL; 481 449 482 while (num1 <= num2) 483 { 450 while (num1 <= num2) { 484 451 offset = findString(lp, oldStr, oldLen, offset); 485 452 486 if (offset < 0) 487 { 488 if (needPrint) 489 { 453 if (offset < 0) { 454 if (needPrint) { 490 455 printLines(num1, num1, FALSE); 491 456 needPrint = FALSE; … … 507 472 * than the old string, then the substitution is easy. 508 473 */ 509 if (deltaLen <= 0) 510 { 474 if (deltaLen <= 0) { 511 475 memcpy(&lp->data[offset], newStr, newLen); 512 476 513 if (deltaLen) 514 { 477 if (deltaLen) { 515 478 memcpy(&lp->data[offset + newLen], 516 479 &lp->data[offset + oldLen], … … 525 488 continue; 526 489 527 if (needPrint) 528 { 490 if (needPrint) { 529 491 printLines(num1, num1, FALSE); 530 492 needPrint = FALSE; … … 544 506 nlp = (LINE *) malloc(sizeof(LINE) + lp->len + deltaLen); 545 507 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"); 550 510 return; 551 511 } … … 577 537 continue; 578 538 579 if (needPrint) 580 { 539 if (needPrint) { 581 540 printLines(num1, num1, FALSE); 582 541 needPrint = FALSE; … … 588 547 589 548 if (!didSub) 590 bb_error_msg(" No substitutions found for \"%s\"", oldStr);549 bb_error_msg("no substitutions found for \"%s\"", oldStr); 591 550 } 592 551 … … 604 563 left = lp->len - offset; 605 564 606 while (left >= len) 607 { 565 while (left >= len) { 608 566 ncp = memchr(cp, *str, left); 609 567 … … 637 595 static void addLines(int num) 638 596 { 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)) { 644 601 if ((buf[0] == '.') && (buf[1] == '\n') && (buf[2] == '\0')) 645 602 return; … … 650 607 return; 651 608 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 { 658 612 len = fgetc(stdin); 659 } 660 while ((len != EOF) && (len != '\n')); 661 613 } while ((len != EOF) && (len != '\n')); 662 614 return; 663 615 } … … 688 640 sign = 1; 689 641 690 while (TRUE) 691 { 642 while (TRUE) { 692 643 while (isblank(*cp)) 693 644 cp++; 694 645 695 switch (*cp) 696 { 646 switch (*cp) { 697 647 case '.': 698 648 haveNum = TRUE; … … 710 660 cp++; 711 661 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"); 716 664 return FALSE; 717 665 } … … 725 673 endStr = strchr(str, '/'); 726 674 727 if (endStr) 728 { 675 if (endStr) { 729 676 *endStr++ = '\0'; 730 677 cp += (endStr - str); … … 742 689 743 690 default: 744 if (!isdigit(*cp)) 745 { 691 if (!isdigit(*cp)) { 746 692 *retcp = cp; 747 693 *retHaveNum = haveNum; 748 694 *retNum = value; 749 750 695 return TRUE; 751 696 } … … 765 710 cp++; 766 711 767 switch (*cp) 768 { 712 switch (*cp) { 769 713 case '-': 770 714 sign = -1; … … 781 725 *retHaveNum = haveNum; 782 726 *retNum = value; 783 784 727 return TRUE; 785 728 } … … 793 736 static int initEdit(void) 794 737 { 795 int 738 int i; 796 739 797 740 bufSize = INITBUF_SIZE; 798 741 bufBase = malloc(bufSize); 799 742 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"); 804 745 return FALSE; 805 746 } … … 860 801 static int readLines(const char * file, int num) 861 802 { 862 int 803 int fd, cc; 863 804 int len, lineCount, charCount; 864 805 char *cp; 865 806 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"); 870 809 return FALSE; 871 810 } … … 873 812 fd = open(file, 0); 874 813 875 if (fd < 0) 876 { 814 if (fd < 0) { 877 815 perror(file); 878 879 816 return FALSE; 880 817 } … … 889 826 fflush(stdout); 890 827 891 do 892 { 828 do { 893 829 cp = memchr(bufPtr, '\n', bufUsed); 894 830 895 if (cp) 896 { 831 if (cp) { 897 832 len = (cp - bufPtr) + 1; 898 833 899 if (!insertLine(num, bufPtr, len)) 900 { 834 if (!insertLine(num, bufPtr, len)) { 901 835 close(fd); 902 903 836 return FALSE; 904 837 } … … 913 846 } 914 847 915 if (bufPtr != bufBase) 916 { 848 if (bufPtr != bufBase) { 917 849 memcpy(bufBase, bufPtr, bufUsed); 918 850 bufPtr = bufBase + bufUsed; 919 851 } 920 852 921 if (bufUsed >= bufSize) 922 { 853 if (bufUsed >= bufSize) { 923 854 len = (bufSize * 3) / 2; 924 855 cp = realloc(bufBase, len); 925 856 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"); 929 859 close(fd); 930 931 860 return FALSE; 932 861 } … … 941 870 bufPtr = bufBase; 942 871 943 } 944 while (cc > 0); 945 946 if (cc < 0) 947 { 872 } while (cc > 0); 873 874 if (cc < 0) { 948 875 perror(file); 949 876 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)) { 958 882 close(fd); 959 960 883 return -1; 961 884 } … … 981 904 { 982 905 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"); 989 910 return FALSE; 990 911 } … … 997 918 if (fd < 0) { 998 919 perror(file); 999 1000 920 return FALSE; 1001 921 } … … 1006 926 lp = findLine(num1); 1007 927 1008 if (lp == NULL) 1009 { 928 if (lp == NULL) { 1010 929 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) { 1019 935 perror(file); 1020 936 close(fd); 1021 1022 937 return FALSE; 1023 938 } … … 1028 943 } 1029 944 1030 if (close(fd) < 0) 1031 { 945 if (close(fd) < 0) { 1032 946 perror(file); 1033 1034 947 return FALSE; 1035 948 } 1036 949 1037 950 printf("%d lines, %d chars\n", lineCount, charCount); 1038 1039 951 return TRUE; 1040 952 } … … 1053 965 int ch, count; 1054 966 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"); 1059 969 return FALSE; 1060 970 } … … 1065 975 return FALSE; 1066 976 1067 while (num1 <= num2) 1068 { 1069 if (!expandFlag) 1070 { 977 while (num1 <= num2) { 978 if (!expandFlag) { 1071 979 write(1, lp->data, lp->len); 1072 980 setCurNum(num1++); … … 1086 994 count--; 1087 995 1088 while (count-- > 0) 1089 { 996 while (count-- > 0) { 1090 997 ch = *cp++; 1091 998 1092 if (ch & 0x80) 1093 { 999 if (ch & 0x80) { 1094 1000 fputs("M-", stdout); 1095 1001 ch &= 0x7f; 1096 1002 } 1097 1003 1098 if (ch < ' ') 1099 { 1004 if (ch < ' ') { 1100 1005 fputc('^', stdout); 1101 1006 ch += '@'; 1102 1007 } 1103 1008 1104 if (ch == 0x7f) 1105 { 1009 if (ch == 0x7f) { 1106 1010 fputc('^', stdout); 1107 1011 ch = '?'; … … 1132 1036 LINE *newLp, *lp; 1133 1037 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"); 1147 1047 return FALSE; 1148 1048 } … … 1153 1053 if (num > lastNum) 1154 1054 lp = &lines; 1155 else 1156 { 1055 else { 1157 1056 lp = findLine(num); 1158 1057 1159 if (lp == NULL) 1160 { 1058 if (lp == NULL) { 1161 1059 free((char *) newLp); 1162 1163 1060 return FALSE; 1164 1061 } … … 1172 1069 lastNum++; 1173 1070 dirty = TRUE; 1174 1175 1071 return setCurNum(num); 1176 1072 } … … 1185 1081 int count; 1186 1082 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"); 1191 1085 return FALSE; 1192 1086 } … … 1197 1091 return FALSE; 1198 1092 1199 if ((curNum >= num1) && (curNum <= num2)) 1200 { 1093 if ((curNum >= num1) && (curNum <= num2)) { 1201 1094 if (num2 < lastNum) 1202 1095 setCurNum(num2 + 1); … … 1214 1107 lastNum -= count; 1215 1108 1216 while (count-- > 0) 1217 { 1109 while (count-- > 0) { 1218 1110 nlp = lp->next; 1219 1111 plp = lp->prev; … … 1245 1137 int len; 1246 1138 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"); 1251 1141 return 0; 1252 1142 } 1253 1143 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"); 1260 1147 return 0; 1261 1148 } … … 1274 1161 return 0; 1275 1162 1276 while (num1 <= num2) 1277 { 1163 while (num1 <= num2) { 1278 1164 if (findString(lp, str, len, 0) >= 0) 1279 1165 return num1; … … 1283 1169 } 1284 1170 1285 bb_error_msg("Cannot find string \"%s\"", str); 1286 1171 bb_error_msg("cannot find string \"%s\"", str); 1287 1172 return 0; 1288 1173 } … … 1297 1182 int lnum; 1298 1183 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); 1303 1186 return NULL; 1304 1187 } 1305 1188 1306 if (curNum <= 0) 1307 { 1189 if (curNum <= 0) { 1308 1190 curNum = 1; 1309 1191 curLine = lines.next; … … 1316 1198 lnum = curNum; 1317 1199 1318 if (num < (curNum / 2)) 1319 { 1200 if (num < (curNum / 2)) { 1320 1201 lp = lines.next; 1321 1202 lnum = 1; 1322 1203 } 1323 else if (num > ((curNum + lastNum) / 2)) 1324 { 1204 else if (num > ((curNum + lastNum) / 2)) { 1325 1205 lp = lines.prev; 1326 1206 lnum = lastNum; 1327 1207 } 1328 1208 1329 while (lnum < num) 1330 { 1209 while (lnum < num) { 1331 1210 lp = lp->next; 1332 1211 lnum++; 1333 1212 } 1334 1213 1335 while (lnum > num) 1336 { 1214 while (lnum > num) { 1337 1215 lp = lp->prev; 1338 1216 lnum--; 1339 1217 } 1340 1341 1218 return lp; 1342 1219 } … … 1358 1235 curNum = num; 1359 1236 curLine = lp; 1360 1361 1237 return TRUE; 1362 1238 } -
branches/stable/mindi-busybox/editors/patch.c
r821 r1770 16 16 * Issues 17 17 * - Non-interactive 18 * - Patches must apply cleanly or the hunkwill fail.18 * - Patches must apply cleanly or patch (not just one hunk) will fail. 19 19 * - Reject file isnt saved 20 * -21 20 */ 22 21 23 22 #include <getopt.h> 24 #include <string.h> 25 #include <stdlib.h> 26 #include <unistd.h> 27 #include "busybox.h" 23 24 #include "libbb.h" 28 25 29 26 static unsigned int copy_lines(FILE *src_stream, FILE *dest_stream, const unsigned int lines_count) … … 33 30 while (src_stream && (i < lines_count)) { 34 31 char *line; 35 line = bb_get_line_from_file(src_stream);32 line = xmalloc_fgets(src_stream); 36 33 if (line == NULL) { 37 34 break; 38 35 } 39 36 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"); 41 38 } 42 39 free(line); … … 44 41 i++; 45 42 } 46 return (i);43 return i; 47 44 } 48 45 … … 59 56 60 57 /* 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; 65 64 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; 67 68 filename_start_ptr = temp + 1; 68 69 } 69 70 70 return (bb_xstrdup(filename_start_ptr));71 return xstrdup(filename_start_ptr); 71 72 } 72 73 … … 74 75 { 75 76 struct stat statbuf; 76 return(stat(filename, &statbuf)); 77 } 78 77 return stat(filename, &statbuf); 78 } 79 80 int patch_main(int argc, char **argv); 79 81 int patch_main(int argc, char **argv) 80 82 { … … 86 88 { 87 89 char *p, *i; 88 ret = bb_getopt_ulflags(argc,argv, "p:i:", &p, &i);90 ret = getopt32(argv, "p:i:", &p, &i); 89 91 if (ret & 1) 90 patch_level = bb_xgetlarg(p, 10, -1, USHRT_MAX);92 patch_level = xatol_range(p, -1, USHRT_MAX); 91 93 if (ret & 2) { 92 patch_file = bb_xfopen(i, "r");94 patch_file = xfopen(i, "r"); 93 95 } else { 94 96 patch_file = stdin; … … 97 99 } 98 100 99 patch_line = bb_get_line_from_file(patch_file);101 patch_line = xmalloc_getline(patch_file); 100 102 while (patch_line) { 101 103 FILE *src_stream; … … 116 118 while (patch_line && strncmp(patch_line, "--- ", 4) != 0) { 117 119 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?? */ 120 123 121 124 /* Extract the filename used before the patch was generated */ … … 123 126 free(patch_line); 124 127 125 patch_line = bb_get_line_from_file(patch_file); 128 patch_line = xmalloc_getline(patch_file); 129 /* FIXME: NULL check?? */ 126 130 if (strncmp(patch_line, "+++ ", 4) != 0) { 127 131 ret = 2; 128 bb_error_msg(" Invalid patch");132 bb_error_msg("invalid patch"); 129 133 continue; 130 134 } … … 141 145 *line_ptr = '/'; 142 146 } 143 dst_stream = bb_xfopen(new_filename, "w+");147 dst_stream = xfopen(new_filename, "w+"); 144 148 backup_filename = NULL; 145 149 } else { … … 148 152 strcat(backup_filename, ".orig"); 149 153 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", 151 155 backup_filename); 152 156 } 153 dst_stream = bb_xfopen(new_filename, "w");157 dst_stream = xfopen(new_filename, "w"); 154 158 } 155 159 … … 158 162 } else { 159 163 if (strcmp(original_filename, new_filename) == 0) { 160 src_stream = bb_xfopen(backup_filename, "r");164 src_stream = xfopen(backup_filename, "r"); 161 165 } else { 162 src_stream = bb_xfopen(original_filename, "r");166 src_stream = xfopen(original_filename, "r"); 163 167 } 164 168 } … … 167 171 168 172 /* Handle each hunk */ 169 patch_line = bb_get_line_from_file(patch_file);173 patch_line = xmalloc_fgets(patch_file); 170 174 while (patch_line) { 171 175 unsigned int count; … … 190 194 count = src_beg_line - src_cur_line; 191 195 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"); 193 197 } 194 198 src_cur_line += count; … … 198 202 hunk_offset_start = src_cur_line; 199 203 200 while ((patch_line = bb_get_line_from_file(patch_file)) != NULL) {204 while ((patch_line = xmalloc_fgets(patch_file)) != NULL) { 201 205 if ((*patch_line == '-') || (*patch_line == ' ')) { 202 206 char *src_line = NULL; 203 207 if (src_stream) { 204 src_line = bb_get_line_from_file(src_stream);208 src_line = xmalloc_fgets(src_stream); 205 209 if (!src_line) { 206 210 hunk_error++; … … 210 214 } 211 215 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); 213 217 hunk_error++; 214 218 free(patch_line); 219 /* Probably need to find next hunk, etc... */ 220 /* but for now we just bail out */ 221 patch_line = NULL; 215 222 break; 216 223 } … … 256 263 if ((dest_cur_line == 0) || (dest_beg_line == 0)) { 257 264 /* 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); 264 268 } 265 269 } … … 270 274 * 2 = More serious problems 271 275 */ 272 return (ret);273 } 276 return ret; 277 } -
branches/stable/mindi-busybox/editors/sed.c
r902 r1770 11 11 * MAINTAINER: Rob Landley <rob@landley.net> 12 12 * 13 * Licensed under GPL v2 or later, see file LICENSE in this tarball for details.13 * Licensed under GPL version 2, see file LICENSE in this tarball for details. 14 14 */ 15 15 … … 22 22 the command line). It calls get_address() and parse_cmd_args(). The 23 23 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). 25 25 26 26 add_input_file() adds a FILE * to the list of input files. We need to … … 59 59 */ 60 60 61 #include " busybox.h"61 #include "libbb.h" 62 62 #include "xregex.h" 63 63 64 64 /* Each sed command turns into one of these structures. */ 65 65 typedef 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:={} */ 89 90 } sed_cmd_t; 90 91 91 static const char *const semicolon_whitespace = "; \n\r\t\v"; 92 93 struct sed_globals 94 { 92 static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v"; 93 94 struct globals { 95 95 /* options */ 96 int be_quiet, in_place,regex_type;96 int be_quiet, regex_type; 97 97 FILE *nonstdout; 98 98 char *outname, *hold_space; 99 99 100 100 /* List of input files */ 101 int input_file_count, current_input_file;101 int input_file_count, current_input_file; 102 102 FILE **input_file_list; 103 103 104 104 regmatch_t regmatch[10]; 105 105 regex_t *previous_regex_ptr; 106 106 107 107 /* linked list of sed commands */ 108 108 sed_cmd_t sed_cmd_head, *sed_cmd_tail; … … 118 118 int len; /* Space allocated */ 119 119 } pipeline; 120 } bbg; 121 122 123 void sed_free_and_close_stuff(void); 120 }; 121 #define G (*(struct globals*)&bb_common_bufsiz1) 122 void 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 124 130 #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);131 static 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); 130 136 131 137 while (sed_cmd) { 132 138 sed_cmd_t *sed_cmd_next = sed_cmd->next; 133 139 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); 136 142 137 143 if (sed_cmd->beg_match) { … … 152 158 } 153 159 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 166 void sed_free_and_close_stuff(void); 159 167 #endif 160 168 … … 163 171 static void cleanup_outname(void) 164 172 { 165 if(bbg.outname) unlink(bbg.outname);173 if (G.outname) unlink(G.outname); 166 174 } 167 175 168 176 /* strdup, replacing "\n" with '\n', and "\delimiter" with 'delimiter' */ 169 177 170 static void parse_escapes(char *dest, c har *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;178 static 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; 179 187 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 196 static 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'); 192 201 return dest; 193 202 } … … 200 209 * a backslash ('\'). A negative delimiter disables square bracket checking. 201 210 */ 202 static int index_of_next_unescaped_regexp_delim(int delimiter, c har *str)211 static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) 203 212 { 204 213 int bracket = -1; … … 209 218 if (delimiter < 0) { 210 219 bracket--; 211 delimiter *= -1;220 delimiter = -delimiter; 212 221 } 213 222 … … 228 237 229 238 /* 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); 231 240 } 232 241 … … 234 243 * Returns the index of the third delimiter 235 244 */ 236 static int parse_regex_delim(c har *cmdstr, char **match, char **replace)237 { 238 c har *cmdstr_ptr = cmdstr;245 static int parse_regex_delim(const char *cmdstr, char **match, char **replace) 246 { 247 const char *cmdstr_ptr = cmdstr; 239 248 char delimiter; 240 249 int idx = 0; … … 244 253 if (*cmdstr == '\0') 245 254 bb_error_msg_and_die("bad format in substitution expression"); 246 delimiter = * (cmdstr_ptr++);255 delimiter = *cmdstr_ptr++; 247 256 248 257 /* save the match string */ … … 261 270 * returns the index in the string just past where the address ends. 262 271 */ 263 static int get_address(c har *my_str, int *linenum, regex_t ** regex)264 { 265 c har *pos = my_str;272 static int get_address(const char *my_str, int *linenum, regex_t ** regex) 273 { 274 const char *pos = my_str; 266 275 267 276 if (isdigit(*my_str)) { 268 *linenum = strtol(my_str, &pos, 10);277 *linenum = strtol(my_str, (char**)&pos, 10); 269 278 /* endstr shouldnt ever equal NULL */ 270 279 } else if (*my_str == '$') { … … 276 285 char *temp; 277 286 278 if (*my_str == '\\') delimiter = *(++pos);279 else delimiter = '/';287 delimiter = '/'; 288 if (*my_str == '\\') delimiter = *++pos; 280 289 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); 284 293 free(temp); 285 294 /* Move position to next character after last delimiter */ … … 290 299 291 300 /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ 292 static int parse_file_cmd(sed_cmd_t *sed_cmd, c har *filecmdstr, char **retval)293 { 294 int start = 0, idx, hack =0;301 static int parse_file_cmd(sed_cmd_t *sed_cmd, const char *filecmdstr, char **retval) 302 { 303 int start = 0, idx, hack = 0; 295 304 296 305 /* 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 300 312 /* 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] = '\\'; 305 320 306 321 return idx; 307 322 } 308 323 309 static int parse_subst_cmd(sed_cmd_t *sed_cmd, c har *substr)310 { 311 int cflags = bbg.regex_type;324 static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) 325 { 326 int cflags = G.regex_type; 312 327 char *match; 313 int idx = 0;328 int idx; 314 329 315 330 /* … … 328 343 /* process the flags */ 329 344 330 sed_cmd->which_match =1;345 sed_cmd->which_match = 1; 331 346 while (substr[++idx]) { 332 347 /* Parse match number */ 333 if (isdigit(substr[idx])) {334 if (match[0]!='^') {348 if (isdigit(substr[idx])) { 349 if (match[0] != '^') { 335 350 /* 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; 339 355 } 340 356 continue; 341 357 } 342 358 /* Skip spaces */ 343 if (isspace(substr[idx])) continue;359 if (isspace(substr[idx])) continue; 344 360 345 361 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"); 376 391 } 377 392 } … … 380 395 if (*match != '\0') { 381 396 /* 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)); 383 398 xregcomp(sed_cmd->sub_match, match, cflags); 384 399 } … … 391 406 * Process the commands arguments 392 407 */ 393 static c har *parse_cmd_args(sed_cmd_t *sed_cmd,char *cmdstr)408 static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) 394 409 { 395 410 /* 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); 397 413 /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ 398 414 else if (strchr("aic", sed_cmd->cmd)) { … … 400 416 bb_error_msg_and_die 401 417 ("only a beginning address can be specified for edit commands"); 402 for (;;) {403 if (*cmdstr=='\n' || *cmdstr=='\\') {418 for (;;) { 419 if (*cmdstr == '\n' || *cmdstr == '\\') { 404 420 cmdstr++; 405 421 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); 411 429 cmdstr += strlen(cmdstr); 412 430 /* handle file cmds: (r)ead */ 413 } else if (strchr("rw", sed_cmd->cmd)) {431 } else if (strchr("rw", sed_cmd->cmd)) { 414 432 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"); 416 434 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 } 419 439 /* handle branch commands */ 420 440 } else if (strchr(":btT", sed_cmd->cmd)) { 421 441 int length; 422 442 423 while(isspace(*cmdstr)) cmdstr++;443 cmdstr = skip_whitespace(cmdstr); 424 444 length = strcspn(cmdstr, semicolon_whitespace); 425 445 if (length) { 426 sed_cmd->string = bb_xstrndup(cmdstr, length);446 sed_cmd->string = xstrndup(cmdstr, length); 427 447 cmdstr += length; 428 448 } … … 431 451 else if (sed_cmd->cmd == 'y') { 432 452 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; 436 456 /* \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); 439 459 440 460 sed_cmd->string = xzalloc((strlen(match) + 1) * 2); 441 461 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]; 444 464 } 445 465 free(match); … … 450 470 */ 451 471 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); 453 473 } 454 474 455 475 /* give back whatever's left over */ 456 return (cmdstr);476 return cmdstr; 457 477 } 458 478 … … 460 480 /* Parse address+command sets, skipping comment lines. */ 461 481 462 static void add_cmd(c har *cmdstr)482 static void add_cmd(const char *cmdstr) 463 483 { 464 484 sed_cmd_t *sed_cmd; … … 466 486 467 487 /* Append this line to any unfinished line from last time. */ 468 if ( bbg.add_cmd_line) {469 c mdstr = 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; 472 492 } 473 493 474 494 /* 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'; 479 500 return; 480 501 } 481 502 482 503 /* Loop parsing all commands in this line. */ 483 while (*cmdstr) {504 while (*cmdstr) { 484 505 /* Skip leading whitespace and semicolons */ 485 506 cmdstr += strspn(cmdstr, semicolon_whitespace); 486 507 487 508 /* If no more commands, exit. */ 488 if (!*cmdstr) break;509 if (!*cmdstr) break; 489 510 490 511 /* if this is a comment, jump past it and keep going */ 491 512 if (*cmdstr == '#') { 492 513 /* "#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; 495 518 continue; 496 519 } … … 513 536 cmdstr++; 514 537 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"); 516 540 cmdstr += idx; 517 541 } 518 542 519 543 /* skip whitespace before the command */ 520 while (isspace(*cmdstr)) cmdstr++;544 cmdstr = skip_whitespace(cmdstr); 521 545 522 546 /* Check for inversion flag */ … … 526 550 527 551 /* skip whitespace before the command */ 528 while (isspace(*cmdstr)) cmdstr++;552 cmdstr = skip_whitespace(cmdstr); 529 553 } 530 554 531 555 /* 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"); 533 558 sed_cmd->cmd = *(cmdstr++); 534 559 cmdstr = parse_cmd_args(sed_cmd, cmdstr); 535 560 536 561 /* 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; 539 564 } 540 565 541 566 /* 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; 544 569 } 545 570 … … 550 575 static void pipe_putc(char c) 551 576 { 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; 558 583 } 559 584 … … 565 590 for (i = 0; replace[i]; i++) { 566 591 /* 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 } 579 610 /* 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 } 583 617 /* Otherwise just output the character. */ 584 elsepipe_putc(replace[i]);618 pipe_putc(replace[i]); 585 619 } 586 620 } … … 590 624 char *oldline = *line; 591 625 int altered = 0; 592 int match_count =0;626 int match_count = 0; 593 627 regex_t *current_regex; 594 628 595 629 /* Handle empty regex. */ 596 630 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; 601 636 602 637 /* 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)) 604 639 return 0; 605 640 606 641 /* 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; 610 645 611 646 /* Now loop through, substituting for matches */ … … 617 652 The match_count check is so not to break 618 653 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++); 621 656 continue; 622 657 } … … 626 661 /* If we aren't interested in this match, output old line to 627 662 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++); 631 666 continue; 632 667 } 633 668 634 669 /* 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]); 636 672 637 673 /* then print the substitution string */ … … 639 675 640 676 /* advance past the match */ 641 oldline += bbg.regmatch[0].rm_eo;677 oldline += G.regmatch[0].rm_eo; 642 678 /* flag that something has changed */ 643 679 altered++; … … 645 681 /* if we're not doing this globally, get out now */ 646 682 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)); 648 684 649 685 /* Copy rest of string into output pipeline */ 650 686 651 while(*oldline) pipe_putc(*(oldline++)); 687 while (*oldline) 688 pipe_putc(*oldline++); 652 689 pipe_putc(0); 653 690 654 691 free(*line); 655 *line = bbg.pipeline.buf;692 *line = G.pipeline.buf; 656 693 return altered; 657 694 } … … 662 699 sed_cmd_t *sed_cmd; 663 700 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); 670 707 } 671 708 672 709 static void append(char *s) 673 710 { 674 llist_add_to_end(& bbg.append_head, bb_xstrdup(s));711 llist_add_to_end(&G.append_head, xstrdup(s)); 675 712 } 676 713 … … 680 717 681 718 /* 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); 684 721 free(data); 685 722 } … … 688 725 static void add_input_file(FILE *file) 689 726 { 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 and727 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 696 733 * noting if we ran out of files without a newline on the last line we read. 697 734 */ 698 static char *get_next_line(int *no_newline) 699 { 700 char *temp=NULL; 735 enum { 736 NO_EOL_CHAR = 1, 737 LAST_IS_NUL = 2, 738 }; 739 static char *get_next_line(char *gets_char) 740 { 741 char *temp = NULL; 701 742 int len; 743 char gc; 702 744 703 745 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); 706 756 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 */ 709 771 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; 714 786 return temp; 715 787 } 716 788 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 */ 803 static 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... */ 729 832 bb_error_msg_and_die(bb_msg_write_error); 730 833 } 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 839 static 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 } 736 846 737 847 /* Process all the lines in all the files */ … … 740 850 { 741 851 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; 744 857 745 858 /* Prime the pump */ 746 next_line = get_next_line(&next_ no_newline);859 next_line = get_next_line(&next_gets_char); 747 860 748 861 /* 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 758 759 next_line = get_next_line(&next_no_newline);760 862 again: 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++; 761 874 restart: 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 775 885 /* 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) 779 888 /* 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)) 782 890 /* 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)) 786 892 /* 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 {"); 821 924 } 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]; 840 1107 break; 841 1108 } 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;1049 1109 } 1050 1110 } 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; 1067 1189 } 1068 1190 1069 1191 /* 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 */ 1071 1196 1072 1197 static void add_cmd_block(char *cmdstr) 1073 1198 { 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 1226 int sed_main(int argc, char **argv); 1087 1227 int sed_main(int argc, char **argv) 1088 1228 { 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(); 1092 1237 1093 1238 /* destroy command strings on exit */ … … 1095 1240 1096 1241 /* Lie to autoconf when it starts asking stupid questions. */ 1097 if (argc==2 && !strcmp(argv[1],"--version")) {1098 p rintf("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; 1100 1245 } 1101 1246 1102 1247 /* 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) 1136 1280 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--; 1146 1283 } 1147 1284 /* Flush any unfinished commands. */ … … 1149 1286 1150 1287 /* By default, we write to stdout */ 1151 bbg.nonstdout=stdout;1152 1153 /* argv[ (optind)..(argc-1)] should be names of file to process. If no1288 G.nonstdout = stdout; 1289 1290 /* argv[0..(argc-1)] should be names of file to process. If no 1154 1291 * files were specified or '-' was specified, take input from stdin. 1155 1292 * 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"); 1158 1296 add_input_file(stdin); 1159 1297 process_files(); … … 1162 1300 FILE *file; 1163 1301 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)) { 1166 1307 add_input_file(stdin); 1167 1308 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(); 1201 1344 } 1202 1345 -
branches/stable/mindi-busybox/editors/vi.c
r821 r1770 14 14 * add :help command 15 15 * :map macros 16 * how about mode lines: vi: set sw=8 ts=8:17 16 * if mark[] values were line numbers rather than pointers 18 17 * it would be easier to change the mark when add/delete lines … … 23 22 */ 24 23 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 41 29 #define Isprint(c) isprint((c)) 42 30 #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 35 enum { 36 MAX_LINELEN = CONFIG_FEATURE_VI_MAX_LEN, 37 MAX_SCR_COLS = CONFIG_FEATURE_VI_MAX_LEN, 38 }; 47 39 48 40 // Misc. non-Ascii keys that report an escape sequence 49 #define VI_K_UP 128 // cursor key Up50 #define VI_K_DOWN 129 // cursor key Down51 #define VI_K_RIGHT 130 // Cursor Key Right52 #define VI_K_LEFT 131 // cursor key Left53 #define VI_K_HOME 132 // Cursor Key Home54 #define VI_K_END 133 // Cursor Key End55 #define VI_K_INSERT 134 // Cursor Key Insert56 #define VI_K_PAGEUP 135 // Cursor Key Page Up57 #define VI_K_PAGEDOWN 136 // Cursor Key Page Down58 #define VI_K_FUN1 137 // Function Key F159 #define VI_K_FUN2 138 // Function Key F260 #define VI_K_FUN3 139 // Function Key F361 #define VI_K_FUN4 140 // Function Key F462 #define VI_K_FUN5 141 // Function Key F563 #define VI_K_FUN6 142 // Function Key F664 #define VI_K_FUN7 143 // Function Key F765 #define VI_K_FUN8 144 // Function Key F866 #define VI_K_FUN9 145 // Function Key F967 #define VI_K_FUN10 146 // Function Key F1068 #define VI_K_FUN11 147 // Function Key F1169 #define VI_K_FUN12 148 // Function Key F1241 #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 70 62 71 63 /* vt102 typical ESC sequence */ 72 64 /* terminal standout start/normal ESC sequence */ 73 static const char SOs[] = "\033[7m";74 static const char SOn[] = "\033[0m";65 static const char SOs[] ALIGN1 = "\033[7m"; 66 static const char SOn[] ALIGN1 = "\033[0m"; 75 67 /* terminal bell sequence */ 76 static const char bell[] = "\007";68 static const char bell[] ALIGN1 = "\007"; 77 69 /* 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";70 static const char Ceol[] ALIGN1 = "\033[0K"; 71 static const char Ceos[] ALIGN1 = "\033[0J"; 80 72 /* Cursor motion arbitrary destination ESC sequence */ 81 static const char CMrc[] = "\033[%d;%dH";73 static const char CMrc[] ALIGN1 = "\033[%d;%dH"; 82 74 /* Cursor motion up and down ESC sequence */ 83 static const char CMup[] = "\033[A";84 static const char CMdown[] = "\n";75 static const char CMup[] ALIGN1 = "\033[A"; 76 static const char CMdown[] ALIGN1 = "\n"; 85 77 86 78 … … 97 89 S_OVER_WS = 3, // used in skip_thing() for moving "dot" 98 90 S_END_PUNCT = 4, // used in skip_thing() for moving "dot" 99 S_END_ALNUM = 5 91 S_END_ALNUM = 5, // used in skip_thing() for moving "dot" 100 92 }; 101 93 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 98 static smallint vi_setops; 105 99 #define VI_AUTOINDENT 1 106 100 #define VI_SHOWMATCH 2 … … 114 108 115 109 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 110 static smallint editing; // >0 while we are editing a file 111 // [code audit says "can be 0 or 1 only"] 112 static smallint cmd_mode; // 0=command 1=insert 2=replace 113 static smallint file_modified; // buffer contents changed 114 static smallint last_file_modified = -1; 115 static int fn_start; // index of first cmd line file name 116 static int save_argc; // how many file names on cmd line 117 static int cmdcnt; // repetition count 118 static int rows, columns; // the terminal screen is this size 119 static int crow, ccol, offset; // cursor is on Crow x Ccol with Horz Ofset 120 static char *status_buffer; // mesages to the user 128 121 #define STATUS_BUFFER_LEN 200 129 122 static int have_status_msg; // is default edit status needed? 123 // [don't make smallint!] 130 124 static int last_status_cksum; // hash of current status line 131 static Byte *cfn; // previous, current, and next file name132 static Byte *text, *end, *textend;// pointers to the user data in memory133 static Byte *screen;// pointer to the virtual screen buffer134 static int screensize; 135 static Byte *screenbegin;// index into text[], of top line on the screen136 static Byte *dot;// where all the action takes place125 static char *current_filename; // current file name 126 //static char *text, *end; // pointers to the user data in memory 127 static char *screen; // pointer to the virtual screen buffer 128 static int screensize; // and its size 129 static char *screenbegin; // index into text[], of top line on the screen 130 //static char *dot; // where all the action takes place 137 131 static 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 132 static char erase_char; // the users erase character 133 static char last_input_char; // last char read from user 134 static char last_forward_char; // last char searched for with 'f' 135 136 #if ENABLE_FEATURE_VI_READONLY 137 //static smallint vi_readonly, readonly; 138 static 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 150 static smallint adding2q; // are we currently adding user input to q 151 static char *last_modifying_cmd; // last modifying cmd for "." 152 static char *ioq, *ioq_start; // pointer to string for get_one_char to "read" 153 #endif 154 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 144 155 static 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 150 158 static int my_pid; 151 159 #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 161 static char *modifying_cmds; // cmds that modify text[] 162 #endif 163 #if ENABLE_FEATURE_VI_SEARCH 164 static char *last_search_pattern; // last pattern from a '/' or '?' search 165 #endif 166 167 /* Moving biggest data to malloced space... */ 168 struct 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 204 static int init_text_buffer(char *); // init from file or create new 205 static void edit_file(char *); // edit one file 206 static void do_cmd(char); // execute a command 207 static int next_tabstop(int); 208 static void sync_cursor(char *, int *, int *); // synchronize the screen cursor to dot 209 static char *begin_line(char *); // return pointer to cur line B-o-l 210 static char *end_line(char *); // return pointer to cur line E-o-l 211 static char *prev_line(char *); // return pointer to prev line B-o-l 212 static char *next_line(char *); // return pointer to next line B-o-l 213 static char *end_screen(void); // get pointer to last char on screen 214 static int count_lines(char *, char *); // count line from start to stop 215 static char *find_line(int); // find begining of line #li 216 static char *move_to_col(char *, int); // move "p" to column l 186 217 static void dot_left(void); // move dot left- dont leave line 187 218 static void dot_right(void); // move dot right- dont leave line … … 193 224 static void dot_skip_over_ws(void); // move dot pat WS 194 225 static 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 226 static char *bound_dot(char *); // make sure text[0] <= P < "end" 227 static char *new_screen(int, int); // malloc virtual screen memory 228 static char *char_insert(char *, char); // insert the char c at 'p' 229 static char *stupid_insert(char *, char); // stupidly insert the char c at 'p' 230 static char find_range(char **, char **, char); // return pointers for an object 231 static int st_test(char *, int, int, char *); // helper for skip_thing() 232 static char *skip_thing(char *, int, int, int); // skip some object 233 static char *find_pair(char *, char); // find matching pair () [] {} 234 static char *text_hole_delete(char *, char *); // at "p", delete a 'size' byte hole 235 static char *text_hole_make(char *, int); // at "p", make a 'size' byte hole 236 static char *yank_delete(char *, char *, int, int); // yank text[] into register then delete 207 237 static void show_help(void); // display some help info 208 238 static void rawmode(void); // set "raw" mode on tty 209 239 static void cookmode(void); // return to "cooked" mode on tty 210 240 static 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 *); 241 static char readit(void); // read (maybe cursor) key from stdin 242 static char get_one_char(void); // read 1 char from stdin 243 static int file_size(const char *); // what is the byte size of "fn" 244 #if ENABLE_FEATURE_VI_READONLY 245 static int file_insert(const char *, char *, int); 246 #else 247 static int file_insert(const char *, char *); 248 #endif 249 static int file_write(char *, char *, char *); 216 250 static void place_cursor(int, int, int); 217 251 static void screen_erase(void); … … 224 258 static void psb(const char *, ...); // Print Status Buf 225 259 static void psbs(const char *, ...); // Print Status Buf in standout mode 226 static void ni( Byte*); // display messages260 static void ni(const char *); // display messages 227 261 static int format_edit_status(void); // format file status on status line 228 262 static void redraw(int); // force a full screen refresh 229 static void format_line( Byte*, Byte*, int);263 static void format_line(char*, char*, int); 230 264 static void refresh(int); // update the terminal from screen[] 231 265 … … 234 268 static void Hit_Return(void); 235 269 236 #if def CONFIG_FEATURE_VI_SEARCH237 static Byte *char_search(Byte *, Byte*, int, int); // search for pattern starting at p238 static int mycmp( Byte *, Byte*, int); // string cmp based in "ignorecase"239 #endif /* CONFIG_FEATURE_VI_SEARCH */240 #if def CONFIG_FEATURE_VI_COLON241 static Byte *get_one_address(Byte*, int *); // get colon addr, if present242 static Byte *get_address(Byte*, int *, int *); // get two colon addrs, if present243 static void colon( Byte*); // execute the "colon" mode cmds244 #endif /* CONFIG_FEATURE_VI_COLON */245 #if def CONFIG_FEATURE_VI_USE_SIGNALS270 #if ENABLE_FEATURE_VI_SEARCH 271 static char *char_search(char *, const char *, int, int); // search for pattern starting at p 272 static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase" 273 #endif 274 #if ENABLE_FEATURE_VI_COLON 275 static char *get_one_address(char *, int *); // get colon addr, if present 276 static char *get_address(char *, int *, int *); // get two colon addrs, if present 277 static void colon(char *); // execute the "colon" mode cmds 278 #endif 279 #if ENABLE_FEATURE_VI_USE_SIGNALS 246 280 static void winch_sig(int); // catch window size changes 247 281 static void suspend_sig(int); // catch ctrl-Z 248 282 static void catch_sig(int); // catch ctrl-C and alarm time-outs 249 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */250 #if def CONFIG_FEATURE_VI_DOT_CMD251 static void start_new_cmd_q( Byte); // new queue for command283 #endif 284 #if ENABLE_FEATURE_VI_DOT_CMD 285 static void start_new_cmd_q(char); // new queue for command 252 286 static 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 #if def CONFIG_FEATURE_VI_SETOPTS257 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 #if def CONFIG_FEATURE_VI_YANKMARK263 static Byte *text_yank(Byte *, Byte*, int); // save copy of "p" into a register264 static Bytewhat_reg(void); // what is letter of current YDreg265 static void check_context( Byte); // remember context for '' command266 #endif /* CONFIG_FEATURE_VI_YANKMARK */267 #if def CONFIG_FEATURE_VI_CRASHME287 #else 288 #define end_cmd_q() ((void)0) 289 #endif 290 #if ENABLE_FEATURE_VI_SETOPTS 291 static 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 294 static char *string_insert(char *, char *); // insert the string at 'p' 295 #endif 296 #if ENABLE_FEATURE_VI_YANKMARK 297 static char *text_yank(char *, char *, int); // save copy of "p" into a register 298 static char what_reg(void); // what is letter of current YDreg 299 static void check_context(char); // remember context for '' command 300 #endif 301 #if ENABLE_FEATURE_VI_CRASHME 268 302 static void crash_dummy(); 269 303 static void crash_test(); 270 304 static int crashme = 0; 271 #endif /* CONFIG_FEATURE_VI_CRASHME */305 #endif 272 306 273 307 … … 277 311 } 278 312 313 int vi_main(int argc, char **argv); 279 314 int vi_main(int argc, char **argv) 280 315 { … … 282 317 RESERVE_CONFIG_BUFFER(STATUS_BUFFER, STATUS_BUFFER_LEN); 283 318 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 288 320 my_pid = getpid(); 289 321 #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; 295 330 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 304 340 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) 315 349 // 2- process EXINIT variable from environment 316 350 // 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) { 318 359 switch (c) { 319 #if def CONFIG_FEATURE_VI_CRASHME360 #if ENABLE_FEATURE_VI_CRASHME 320 361 case 'C': 321 362 crashme = 1; 322 363 break; 323 #endif /* CONFIG_FEATURE_VI_CRASHME */324 #if def CONFIG_FEATURE_VI_READONLY364 #endif 365 #if ENABLE_FEATURE_VI_READONLY 325 366 case 'R': // Read-only flag 326 readonly = TRUE; 327 vi_readonly = TRUE; 367 SET_READONLY_MODE(readonly_mode); 328 368 break; 329 #endif /* CONFIG_FEATURE_VI_READONLY */369 #endif 330 370 //case 'r': // recover flag- ignore- we don't use tmp file 331 371 //case 'x': // encryption flag- ignore 332 372 //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; 333 378 //case 'h': // help -- just use default 379 #endif 334 380 default: 335 381 show_help(); … … 345 391 //----- This is the main file handling loop -------------- 346 392 if (optind >= argc) { 347 editing = 1; // 0= exit, 1= one file, 2= multiple files348 393 edit_file(0); 349 394 } else { 350 395 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]); 355 397 } 356 398 } 357 399 //----------------------------------------------------------- 358 400 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 */ 406 static 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 439 static void edit_file(char * fn) 440 { 441 char c; 442 int size; 443 444 #if ENABLE_FEATURE_VI_USE_SIGNALS 368 445 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 374 452 rawmode(); 375 453 rows = 24; 376 454 columns = 80; 377 ch= -1;455 size = 0; 378 456 if (ENABLE_FEATURE_VI_WIN_RESIZE) 379 457 get_terminal_width_height(0, &columns, &rows); 380 458 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 395 462 YDreg = 26; // default Yank/Delete reg 396 463 Ureg = 27; // hold orig line for "U" cmd 397 for (cnt = 0; cnt < 28; cnt++) {398 mark[cnt] = 0;399 } // init the marks400 464 mark[26] = mark[27] = text; // init "previous context" 401 #endif /* CONFIG_FEATURE_VI_YANKMARK */465 #endif 402 466 403 467 last_forward_char = last_input_char = '\0'; … … 405 469 ccol = 0; 406 470 407 #if def CONFIG_FEATURE_VI_USE_SIGNALS471 #if ENABLE_FEATURE_VI_USE_SIGNALS 408 472 catch_sig(0); 409 473 signal(SIGWINCH, winch_sig); … … 413 477 screenbegin = dot = text; 414 478 } 415 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */ 416 417 editing = 1; 479 #endif 480 418 481 cmd_mode = 0; // 0=command 1=insert 2='R'eplace 419 482 cmdcnt = 0; … … 421 484 offset = 0; // no horizontal offset 422 485 c = '\0'; 423 #if def CONFIG_FEATURE_VI_DOT_CMD486 #if ENABLE_FEATURE_VI_DOT_CMD 424 487 free(last_modifying_cmd); 425 488 free(ioq_start); 426 ioq = ioq_start = last_modifying_cmd = 0;489 ioq = ioq_start = last_modifying_cmd = NULL; 427 490 adding2q = 0; 428 #endif /* CONFIG_FEATURE_VI_DOT_CMD */491 #endif 429 492 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 432 515 //------This is the main Vi cmd handling loop ----------------------- 433 516 while (editing > 0) { 434 #if def CONFIG_FEATURE_VI_CRASHME517 #if ENABLE_FEATURE_VI_CRASHME 435 518 if (crashme > 0) { 436 519 if ((end - text) > 1) { … … 438 521 } else { 439 522 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 442 524 refresh(FALSE); 443 525 } 444 526 } 445 #endif /* CONFIG_FEATURE_VI_CRASHME */527 #endif 446 528 last_input_char = c = get_one_char(); // get a cmd from user 447 #if def CONFIG_FEATURE_VI_YANKMARK529 #if ENABLE_FEATURE_VI_YANKMARK 448 530 // save a copy of the current line- for the 'U" command 449 531 if (begin_line(dot) != cur_line) { … … 451 533 text_yank(begin_line(dot), end_line(dot), Ureg); 452 534 } 453 #endif /* CONFIG_FEATURE_VI_YANKMARK */454 #if def CONFIG_FEATURE_VI_DOT_CMD535 #endif 536 #if ENABLE_FEATURE_VI_DOT_CMD 455 537 // These are commands that change text[]. 456 538 // Remember the input for the "." command 457 539 if (!adding2q && ioq_start == 0 458 && strchr((char *) modifying_cmds, c) != NULL) { 540 && strchr(modifying_cmds, c) 541 ) { 459 542 start_new_cmd_q(c); 460 543 } 461 #endif /* CONFIG_FEATURE_VI_DOT_CMD */544 #endif 462 545 do_cmd(c); // execute the user command 463 546 // … … 470 553 show_status_line(); 471 554 } 472 #if def CONFIG_FEATURE_VI_CRASHME555 #if ENABLE_FEATURE_VI_CRASHME 473 556 if (crashme > 0) 474 557 crash_test(); // test editor variables 475 #endif /* CONFIG_FEATURE_VI_CRASHME */558 #endif 476 559 } 477 560 //------------------------------------------------------------------- … … 483 566 484 567 //----- The Colon commands ------------------------------------- 485 #if def CONFIG_FEATURE_VI_COLON486 static Byte *get_one_address(Byte* p, int *addr) // get colon addr, if present568 #if ENABLE_FEATURE_VI_COLON 569 static char *get_one_address(char * p, int *addr) // get colon addr, if present 487 570 { 488 571 int st; 489 Byte*q;490 491 #if def CONFIG_FEATURE_VI_YANKMARK492 Bytec;493 #endif /* CONFIG_FEATURE_VI_YANKMARK */494 #if def CONFIG_FEATURE_VI_SEARCH495 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 497 580 498 581 *addr = -1; // assume no addr … … 501 584 q = begin_line(dot); 502 585 *addr = count_lines(text, q); 503 #if def CONFIG_FEATURE_VI_YANKMARK586 #if ENABLE_FEATURE_VI_YANKMARK 504 587 } else if (*p == '\'') { // is this a mark addr 505 588 p++; … … 509 592 // we have a mark 510 593 c = c - 'a'; 511 q = mark[( int) c];594 q = mark[(unsigned char) c]; 512 595 if (q != NULL) { // is mark valid 513 596 *addr = count_lines(text, q); // count lines 514 597 } 515 598 } 516 #endif /* CONFIG_FEATURE_VI_YANKMARK */517 #if def CONFIG_FEATURE_VI_SEARCH599 #endif 600 #if ENABLE_FEATURE_VI_SEARCH 518 601 } else if (*p == '/') { // a search pattern 519 602 q = buf; … … 524 607 *q = '\0'; 525 608 } 526 pat = (Byte *) bb_xstrdup((char *)buf); // save copy of pattern609 pat = xstrdup(buf); // save copy of pattern 527 610 if (*p == '/') 528 611 p++; … … 532 615 } 533 616 free(pat); 534 #endif /* CONFIG_FEATURE_VI_SEARCH */617 #endif 535 618 } else if (*p == '$') { // the last line in file 536 619 p++; … … 538 621 *addr = count_lines(text, q); 539 622 } else if (isdigit(*p)) { // specific line number 540 sscanf( (char *)p, "%d%n", addr, &st);623 sscanf(p, "%d%n", addr, &st); 541 624 p += st; 542 625 } else { // I don't reconise this … … 544 627 *addr = -1; 545 628 } 546 return (p);547 } 548 549 static Byte *get_address(Byte*p, int *b, int *e) // get two colon addrs, if present629 return p; 630 } 631 632 static char *get_address(char *p, int *b, int *e) // get two colon addrs, if present 550 633 { 551 634 //----- get the address' i.e., 1,3 'a,'b ----- 552 635 // get FIRST addr, if present 553 while (isbl nk(*p))636 while (isblank(*p)) 554 637 p++; // skip over leading spaces 555 638 if (*p == '%') { // alias for 1,$ … … 560 643 } 561 644 p = get_one_address(p, b); 562 while (isbl nk(*p))645 while (isblank(*p)) 563 646 p++; 564 647 if (*p == ',') { // is there a address separator 565 648 p++; 566 while (isbl nk(*p))649 while (isblank(*p)) 567 650 p++; 568 651 // get SECOND addr, if present 569 652 p = get_one_address(p, e); 570 653 } 571 ga0:572 while (isbl nk(*p))654 ga0: 655 while (isblank(*p)) 573 656 p++; // skip over trailing spaces 574 return (p);575 } 576 577 #if def CONFIG_FEATURE_VI_SETOPTS578 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 661 static void setops(const char *args, const char *opname, int flg_no, 579 662 const char *short_opname, int opt) 580 663 { 581 const char *a = (char *)args + flg_no;664 const char *a = args + flg_no; 582 665 int l = strlen(opname) - 1; /* opname have + ' ' */ 583 666 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) 587 671 vi_setops &= ~opt; 588 672 else 589 673 vi_setops |= opt; 590 674 } … … 592 676 #endif 593 677 594 static void colon( Byte* buf)595 { 596 Bytec, *orig_buf, *buf1, *q, *r;597 Byte *fn, cmd[BUFSIZ], args[BUFSIZ];598 int i, l, li, ch, st,b, e;678 static 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; 599 683 int useforce = FALSE, forced = FALSE; 600 struct stat st_buf;601 684 602 685 // :3154 // if (-e line 3154) goto it else stay put … … 615 698 // 616 699 617 if ( strlen((char *) buf) <= 0)700 if (!buf[0]) 618 701 goto vc1; 619 702 if (*buf == ':') 620 703 buf++; // move past the ':' 621 704 622 li = st =ch = i = 0;705 li = ch = i = 0; 623 706 b = e = -1; 624 707 q = text; // assume 1,$ for the range 625 708 r = end - 1; 626 709 li = count_lines(text, end - 1); 627 fn = c fn; // default to current file628 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[] 630 713 631 714 // look for optional address(es) :. :1 :1,9 :'q,'a :% … … 643 726 } 644 727 // get any ARGuments 645 while (isbl nk(*buf))728 while (isblank(*buf)) 646 729 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, '!'); 649 732 if (buf1) { 650 733 useforce = TRUE; … … 668 751 } 669 752 // ------------ now look for the command ------------ 670 i = strlen( (char *)cmd);753 i = strlen(cmd); 671 754 if (i == 0) { // :123CR goto line #123 672 755 if (b >= 0) { … … 674 757 dot_skip_over_ws(); 675 758 } 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; 677 763 // :!ls run the <cmd> 678 (void)alarm(0); // wait for input- no alarms764 alarm(0); // wait for input- no alarms 679 765 place_cursor(rows - 1, 0, FALSE); // go to Status line 680 766 clear_to_eol(); // clear the line 681 767 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); 683 771 rawmode(); 684 772 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 687 777 if (b < 0) { // no addr given- use defaults 688 778 b = e = count_lines(text, dot); 689 779 } 690 780 psb("%d", b); 691 } else if (strncasecmp( (char *)cmd, "delete", i) == 0) { // delete lines781 } else if (strncasecmp(cmd, "delete", i) == 0) { // delete lines 692 782 if (b < 0) { // no addr given- use defaults 693 783 q = begin_line(dot); // assume .,. for the range … … 696 786 dot = yank_delete(q, r, 1, YANKDEL); // save, then delete lines 697 787 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 701 789 // don't edit, if the current file has been modified 702 790 if (file_modified && ! useforce) { … … 704 792 goto vc1; 705 793 } 706 if ( strlen((char*)args) > 0) {794 if (args[0]) { 707 795 // the user supplied a file name 708 fn = args;709 } else if (c fn != 0 && strlen((char*)cfn) > 0) {796 fn = args; 797 } else if (current_filename && current_filename[0]) { 710 798 // no user supplied name- use the current filename 711 fn= cfn; 712 goto vc5; 799 // fn = current_filename; was set by default 713 800 } else { 714 801 // no user file name, no current name- punt … … 717 804 } 718 805 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 760 810 if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { 761 811 free(reg[Ureg]); // free orig line reg- for 'U' … … 766 816 reg[YDreg]= 0; 767 817 } 768 for (li = 0; li < 28; li++) { 769 mark[li] = 0; 770 } // init the marks 771 #endif /* CONFIG_FEATURE_VI_YANKMARK */ 818 #endif 772 819 // how many lines in text[]? 773 820 li = count_lines(text, end - 1); 774 821 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 ) 783 828 li, ch); 784 } else if (strncasecmp( (char *)cmd, "file", i) == 0) { // what File is this829 } else if (strncasecmp(cmd, "file", i) == 0) { // what File is this 785 830 if (b != -1 || e != -1) { 786 ni( (Byte *)"No address allowed on this command");831 ni("No address allowed on this command"); 787 832 goto vc1; 788 833 } 789 if ( strlen((char *) args) > 0) {834 if (args[0]) { 790 835 // user wants a new filename 791 free(c fn);792 c fn = (Byte *) bb_xstrdup((char *)args);836 free(current_filename); 837 current_filename = xstrdup(args); 793 838 } else { 794 839 // user wants file status info 795 840 last_status_cksum = 0; // force status update 796 841 } 797 } else if (strncasecmp( (char *)cmd, "features", i) == 0) { // what features are available842 } else if (strncasecmp(cmd, "features", i) == 0) { // what features are available 798 843 // print out values of all features 799 844 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen … … 803 848 rawmode(); 804 849 Hit_Return(); 805 } else if (strncasecmp( (char *)cmd, "list", i) == 0) { // literal print line850 } else if (strncasecmp(cmd, "list", i) == 0) { // literal print line 806 851 if (b < 0) { // no addr given- use defaults 807 852 q = begin_line(dot); // assume .,. for the range … … 815 860 816 861 c = *q; 817 c_is_no_print = c > 127&& !Isprint(c);862 c_is_no_print = (c & 0x80) && !Isprint(c); 818 863 if (c_is_no_print) { 819 864 c = '.'; … … 824 869 } else if (c < ' ' || c == 127) { 825 870 putchar('^'); 826 if (c == 127)871 if (c == 127) 827 872 c = '?'; 828 829 c += '@';873 else 874 c += '@'; 830 875 } 831 876 putchar(c); … … 833 878 standout_end(); 834 879 } 835 #if def CONFIG_FEATURE_VI_SET836 837 #endif /* CONFIG_FEATURE_VI_SET */880 #if ENABLE_FEATURE_VI_SET 881 vc2: 882 #endif 838 883 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 ) { 841 887 if (useforce) { 842 888 // force end of argv list … … 863 909 } 864 910 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[] 866 912 fn = args; 867 if ( strlen((char *) fn) <= 0) {913 if (!fn[0]) { 868 914 psbs("No filename given"); 869 915 goto vc1; … … 875 921 if (b != 0) 876 922 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)); 884 924 if (ch < 0) 885 925 goto vc1; // nothing was inserted … … 887 927 li = count_lines(q, q + ch - 1); 888 928 psb("\"%s\"" 889 #ifdef CONFIG_FEATURE_VI_READONLY 890 "%s" 891 #endif /* CONFIG_FEATURE_VI_READONLY */ 929 USE_FEATURE_VI_READONLY("%s") 892 930 " %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]" : ""),) 896 932 li, ch); 897 933 if (ch > 0) { … … 901 937 file_modified++; 902 938 } 903 } else if (strncasecmp( (char *)cmd, "rewind", i) == 0) { // rewind cmd line args939 } else if (strncasecmp(cmd, "rewind", i) == 0) { // rewind cmd line args 904 940 if (file_modified && ! useforce) { 905 941 psbs("No write since last change (:rewind! overrides)"); … … 909 945 editing = 0; 910 946 } 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 913 952 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) { 915 955 // print out values of all options 916 956 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 917 957 clear_to_eol(); // clear the line 918 958 printf("----------------------------------------\r\n"); 919 #if def CONFIG_FEATURE_VI_SETOPTS959 #if ENABLE_FEATURE_VI_SETOPTS 920 960 if (!autoindent) 921 961 printf("no"); … … 931 971 printf("showmatch "); 932 972 printf("tabstop=%d ", tabstop); 933 #endif /* CONFIG_FEATURE_VI_SETOPTS */973 #endif 934 974 printf("\r\n"); 935 975 goto vc2; 936 976 } 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; 954 1002 int gflag; 955 1003 … … 960 1008 c = orig_buf[1]; // what is the delimiter 961 1009 F = orig_buf + 2; // start of "find" 962 R = (Byte *) strchr((char *)F, c); // middle delimiter1010 R = strchr(F, c); // middle delimiter 963 1011 if (!R) goto colon_s_fail; 964 1012 *R++ = '\0'; // terminate "find" 965 buf1 = (Byte *) strchr((char *)R, c);1013 buf1 = strchr(R, c); 966 1014 if (!buf1) goto colon_s_fail; 967 1015 *buf1++ = '\0'; // terminate "replace" … … 979 1027 for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 980 1028 ls = q; // orig line start 981 1029 vc4: 982 1030 buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" 983 if (buf1 != NULL) {984 // we found the "find" pattern - delete it985 (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); 986 1034 // inset the "replace" patern 987 (void)string_insert(buf1, R); // insert the string1035 string_insert(buf1, R); // insert the string 988 1036 // check for "global" :s/foo/bar/g 989 1037 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); 992 1040 goto vc4; // don't let q move past cur line 993 1041 } … … 996 1044 q = next_line(ls); 997 1045 } 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 ) { 1005 1054 // is there a file name to write to? 1006 if ( strlen((char *) args) > 0) {1055 if (args[0]) { 1007 1056 fn = args; 1008 1057 } 1009 #if def CONFIG_FEATURE_VI_READONLY1010 if ( (vi_readonly || readonly) && !useforce) {1058 #if ENABLE_FEATURE_VI_READONLY 1059 if (readonly_mode && !useforce) { 1011 1060 psbs("\"%s\" File is read only", fn); 1012 1061 goto vc3; 1013 1062 } 1014 #endif /* CONFIG_FEATURE_VI_READONLY */1063 #endif 1015 1064 // how many lines in text[]? 1016 1065 li = count_lines(q, r); … … 1032 1081 if (l < 0) { 1033 1082 if (l == -1) 1034 psbs(" Write error: %s", strerror(errno));1083 psbs("\"%s\" %s", fn, strerror(errno)); 1035 1084 } else { 1036 1085 psb("\"%s\" %dL, %dC", fn, li, l); … … 1045 1094 } 1046 1095 } 1047 #if def CONFIG_FEATURE_VI_READONLY1048 1049 #endif /* CONFIG_FEATURE_VI_READONLY */1050 #if def CONFIG_FEATURE_VI_YANKMARK1051 } else if (strncasecmp( (char *)cmd, "yank", i) == 0) { // yank lines1096 #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 1052 1101 if (b < 0) { // no addr given- use defaults 1053 1102 q = begin_line(dot); // assume .,. for the range … … 1057 1106 li = count_lines(q, r); 1058 1107 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 1061 1110 } else { 1062 1111 // cmd unknown 1063 ni( (Byte *)cmd);1064 } 1065 1112 ni(cmd); 1113 } 1114 vc1: 1066 1115 dot = bound_dot(dot); // make sure "dot" is valid 1067 1116 return; 1068 #if def CONFIG_FEATURE_VI_SEARCH1069 colon_s_fail:1117 #if ENABLE_FEATURE_VI_SEARCH 1118 colon_s_fail: 1070 1119 psb(":s expression missing delimiters"); 1071 1120 #endif 1072 1121 } 1073 1122 1074 #endif /* CONFIG_FEATURE_VI_COLON */1123 #endif /* FEATURE_VI_COLON */ 1075 1124 1076 1125 static void Hit_Return(void) … … 1086 1135 } 1087 1136 1137 static int next_tabstop(int col) 1138 { 1139 return col + ((tabstop - 1) - (col % tabstop)); 1140 } 1141 1088 1142 //----- 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" line1092 Byte *beg_scr,*end_scr; // begin and end of screen1093 Byte*tp;1143 static 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; 1094 1148 int cnt, ro, co; 1095 1149 1096 1150 beg_cur = begin_line(d); // first char of cur line 1097 1151 1098 beg_scr = end_scr = screenbegin; // first char of screen1099 1152 end_scr = end_screen(); // last char of screen 1100 1153 … … 1103 1156 // how many lines do we have to move 1104 1157 cnt = count_lines(beg_cur, screenbegin); 1105 1158 sc1: 1106 1159 screenbegin = beg_cur; 1107 1160 if (cnt > (rows - 1) / 2) { … … 1139 1192 break; 1140 1193 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 } 1143 1199 } else if (*tp < ' ' || *tp == 127) { 1144 1200 co++; // display as ^X, use 2 columns … … 1177 1233 1178 1234 //----- Text Movement Routines --------------------------------- 1179 static Byte *begin_line(Byte* p) // return pointer to first char cur line1235 static char *begin_line(char * p) // return pointer to first char cur line 1180 1236 { 1181 1237 while (p > text && p[-1] != '\n') 1182 1238 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 line1239 return p; 1240 } 1241 1242 static char *end_line(char * p) // return pointer to NL of cur line line 1187 1243 { 1188 1244 while (p < end - 1 && *p != '\n') 1189 1245 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 line1246 return p; 1247 } 1248 1249 static inline char *dollar_line(char * p) // return pointer to just before NL line 1194 1250 { 1195 1251 while (p < end - 1 && *p != '\n') … … 1198 1254 if (*p == '\n' && (p - begin_line(p)) > 0) 1199 1255 p--; 1200 return (p);1201 } 1202 1203 static Byte *prev_line(Byte* p) // return pointer first char prev line1256 return p; 1257 } 1258 1259 static char *prev_line(char * p) // return pointer first char prev line 1204 1260 { 1205 1261 p = begin_line(p); // goto begining of cur line … … 1207 1263 p--; // step to prev line 1208 1264 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 line1265 return p; 1266 } 1267 1268 static char *next_line(char * p) // return pointer first char next line 1213 1269 { 1214 1270 p = end_line(p); 1215 1271 if (*p == '\n' && p < end - 1) 1216 1272 p++; // step to next line 1217 return (p);1273 return p; 1218 1274 } 1219 1275 1220 1276 //----- Text Information Routines ------------------------------ 1221 static Byte*end_screen(void)1222 { 1223 Byte*q;1277 static char *end_screen(void) 1278 { 1279 char *q; 1224 1280 int cnt; 1225 1281 … … 1229 1285 q = next_line(q); 1230 1286 q = end_line(q); 1231 return (q);1232 } 1233 1234 static int count_lines( Byte * start, Byte* stop) // count line from start to stop1235 { 1236 Byte*q;1287 return q; 1288 } 1289 1290 static int count_lines(char * start, char * stop) // count line from start to stop 1291 { 1292 char *q; 1237 1293 int cnt; 1238 1294 … … 1248 1304 cnt++; 1249 1305 } 1250 return (cnt);1251 } 1252 1253 static Byte*find_line(int li) // find begining of line #li1254 { 1255 Byte*q;1306 return cnt; 1307 } 1308 1309 static char *find_line(int li) // find begining of line #li 1310 { 1311 char *q; 1256 1312 1257 1313 for (q = text; li > 1; li--) { 1258 1314 q = next_line(q); 1259 1315 } 1260 return (q);1316 return q; 1261 1317 } 1262 1318 … … 1284 1340 } 1285 1341 1286 static Byte *move_to_col(Byte* p, int l)1342 static char *move_to_col(char * p, int l) 1287 1343 { 1288 1344 int co; … … 1294 1350 break; 1295 1351 if (*p == '\t') { 1296 // 7 - (co % 8 ) 1297 co += ((tabstop - 1) - (co % tabstop)); 1352 co = next_tabstop(co); 1298 1353 } else if (*p < ' ' || *p == 127) { 1299 1354 co++; // display as ^X, use 2 columns 1300 1355 } 1301 1356 } while (++co <= l && p++ < end); 1302 return (p);1357 return p; 1303 1358 } 1304 1359 … … 1315 1370 static void dot_scroll(int cnt, int dir) 1316 1371 { 1317 Byte*q;1372 char *q; 1318 1373 1319 1374 for (; cnt > 0; cnt--) { … … 1346 1401 static void dot_delete(void) // delete the char at 'dot' 1347 1402 { 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 1406 static char *bound_dot(char * p) // make sure text[0] <= P < "end" 1352 1407 { 1353 1408 if (p >= end && end > text) { … … 1359 1414 indicate_error('2'); 1360 1415 } 1361 return (p);1416 return p; 1362 1417 } 1363 1418 … … 1375 1430 */ 1376 1431 1377 static Byte*new_screen(int ro, int co)1432 static char *new_screen(int ro, int co) 1378 1433 { 1379 1434 int li; … … 1381 1436 free(screen); 1382 1437 screensize = ro * co + 8; 1383 screen = (Byte *)xmalloc(screensize);1438 screen = xmalloc(screensize); 1384 1439 // initialize the new screen. assume this will be a empty file. 1385 1440 screen_erase(); … … 1388 1443 screen[(li * co) + 0] = '~'; 1389 1444 } 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 1449 static int mycmp(const char * s1, const char * s2, int len) 1408 1450 { 1409 1451 int i; 1410 1452 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 1461 static char *char_search(char * p, const char * pat, int dir, int range) 1421 1462 { 1422 1463 #ifndef REGEX_SEARCH 1423 Byte*start, *stop;1464 char *start, *stop; 1424 1465 int len; 1425 1466 1426 len = strlen( (char *)pat);1467 len = strlen(pat); 1427 1468 if (dir == FORWARD) { 1428 1469 stop = end - 1; // assume range is p - end-1 … … 1431 1472 for (start = p; start < stop; start++) { 1432 1473 if (mycmp(start, pat, len) == 0) { 1433 return (start);1474 return start; 1434 1475 } 1435 1476 } … … 1440 1481 for (start = p - len; start >= stop; start--) { 1441 1482 if (mycmp(start, pat, len) == 0) { 1442 return (start);1483 return start; 1443 1484 } 1444 1485 } 1445 1486 } 1446 1487 // pattern not found 1447 return (NULL);1448 #else /*REGEX_SEARCH */1488 return NULL; 1489 #else /* REGEX_SEARCH */ 1449 1490 char *q; 1450 1491 struct re_pattern_buffer preg; … … 1473 1514 range = q - p; 1474 1515 1475 q = (char *) re_compile_pattern(pat, strlen((char *)pat), &preg);1516 q = re_compile_pattern(pat, strlen(pat), &preg); 1476 1517 if (q != 0) { 1477 1518 // The pattern was not compiled … … 1500 1541 i = 0; // return NULL if pattern not found 1501 1542 } 1502 1543 cs1: 1503 1544 if (dir == FORWARD) { 1504 1545 p = p + i; … … 1506 1547 p = p - i; 1507 1548 } 1508 return (p);1509 #endif /*REGEX_SEARCH */1510 } 1511 #endif /* CONFIG_FEATURE_VI_SEARCH */1512 1513 static Byte *char_insert(Byte * p, Bytec) // insert the char c at 'p'1549 return p; 1550 #endif /* REGEX_SEARCH */ 1551 } 1552 #endif /* FEATURE_VI_SEARCH */ 1553 1554 static char *char_insert(char * p, char c) // insert the char c at 'p' 1514 1555 { 1515 1556 if (c == 22) { // Is this an ctrl-V? … … 1526 1567 end_cmd_q(); // stop adding to q 1527 1568 last_status_cksum = 0; // force status update 1528 if ((p[-1] != '\n') && (dot >text)) {1569 if ((p[-1] != '\n') && (dot > text)) { 1529 1570 p--; 1530 1571 } … … 1537 1578 } else { 1538 1579 // insert a char into text[] 1539 Byte*sp; // "save p"1580 char *sp; // "save p" 1540 1581 1541 1582 if (c == 13) … … 1543 1584 sp = p; // remember addr of insert 1544 1585 p = stupid_insert(p, c); // insert the char 1545 #if def CONFIG_FEATURE_VI_SETOPTS1586 #if ENABLE_FEATURE_VI_SETOPTS 1546 1587 if (showmatch && strchr(")]}", *sp) != NULL) { 1547 1588 showmatching(sp); 1548 1589 } 1549 1590 if (autoindent && c == '\n') { // auto indent the new line 1550 Byte*q;1591 char *q; 1551 1592 1552 1593 q = prev_line(p); // use prev line as templet 1553 for (; isbl nk(*q); q++) {1594 for (; isblank(*q); q++) { 1554 1595 p = stupid_insert(p, *q); // insert the char 1555 1596 } 1556 1597 } 1557 #endif /* CONFIG_FEATURE_VI_SETOPTS */1558 } 1559 return (p);1560 } 1561 1562 static Byte *stupid_insert(Byte * p, Bytec) // stupidly insert the char c at 'p'1598 #endif 1599 } 1600 return p; 1601 } 1602 1603 static char *stupid_insert(char * p, char c) // stupidly insert the char c at 'p' 1563 1604 { 1564 1605 p = text_hole_make(p, 1); … … 1568 1609 p++; 1569 1610 } 1570 return (p);1571 } 1572 1573 static Byte find_range(Byte ** start, Byte ** stop, Bytec)1574 { 1575 Byte*save_dot, *p, *q;1611 return p; 1612 } 1613 1614 static char find_range(char ** start, char ** stop, char c) 1615 { 1616 char *save_dot, *p, *q; 1576 1617 int cnt; 1577 1618 … … 1625 1666 } 1626 1667 dot = save_dot; 1627 return (c);1628 } 1629 1630 static int st_test( Byte * p, int type, int dir, Byte* tested)1631 { 1632 Bytec, c0, ci;1668 return c; 1669 } 1670 1671 static int st_test(char * p, int type, int dir, char * tested) 1672 { 1673 char c, c0, ci; 1633 1674 int test, inc; 1634 1675 … … 1659 1700 } 1660 1701 *tested = c; 1661 return (test);1662 } 1663 1664 static Byte *skip_thing(Byte* p, int linecnt, int dir, int type)1665 { 1666 Bytec;1702 return test; 1703 } 1704 1705 static char *skip_thing(char * p, int linecnt, int dir, int type) 1706 { 1707 char c; 1667 1708 1668 1709 while (st_test(p, type, dir, &c)) { … … 1676 1717 p += dir; // move to next char 1677 1718 } 1678 return (p);1719 return p; 1679 1720 } 1680 1721 1681 1722 // find matching char of pair () [] {} 1682 static Byte *find_pair(Byte * p, Bytec)1683 { 1684 Bytematch, *q;1723 static char *find_pair(char * p, char c) 1724 { 1725 char match, *q; 1685 1726 int dir, level; 1686 1727 … … 1722 1763 if (level != 0) 1723 1764 q = NULL; // indicate no match 1724 return (q);1725 } 1726 1727 #if def CONFIG_FEATURE_VI_SETOPTS1765 return q; 1766 } 1767 1768 #if ENABLE_FEATURE_VI_SETOPTS 1728 1769 // show the matching char of a pair, () [] {} 1729 static void showmatching( Byte* p)1730 { 1731 Byte*q, *save_dot;1770 static void showmatching(char * p) 1771 { 1772 char *q, *save_dot; 1732 1773 1733 1774 // we found half of a pair … … 1740 1781 dot = q; // go to new loc 1741 1782 refresh(FALSE); // let the user see it 1742 (void)mysleep(40); // give user some time1783 mysleep(40); // give user some time 1743 1784 dot = save_dot; // go back to old loc 1744 1785 refresh(FALSE); 1745 1786 } 1746 1787 } 1747 #endif /* CONFIG_FEATURE_VI_SETOPTS */1788 #endif /* FEATURE_VI_SETOPTS */ 1748 1789 1749 1790 // open a hole in text[] 1750 static Byte *text_hole_make(Byte* p, int size) // at "p", make a 'size' byte hole1751 { 1752 Byte*src, *dest;1791 static char *text_hole_make(char * p, int size) // at "p", make a 'size' byte hole 1792 { 1793 char *src, *dest; 1753 1794 int cnt; 1754 1795 … … 1758 1799 dest = p + size; 1759 1800 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) { 1761 1803 psbs("can't create room for new characters"); 1804 p = NULL; 1805 goto thm0; 1762 1806 } 1763 1807 memset(p, ' ', size); // clear new hole 1764 end = end + size;// adjust the new END1808 end += size; // adjust the new END 1765 1809 file_modified++; // has the file been modified 1766 1767 return (p);1810 thm0: 1811 return p; 1768 1812 } 1769 1813 1770 1814 // close a hole in text[] 1771 static Byte *text_hole_delete(Byte * p, Byte* q) // delete "p" thru "q", inclusive1772 { 1773 Byte*src, *dest;1815 static char *text_hole_delete(char * p, char * q) // delete "p" thru "q", inclusive 1816 { 1817 char *src, *dest; 1774 1818 int cnt, hole_size; 1775 1819 … … 1793 1837 psbs("can't delete the character"); 1794 1838 } 1795 1839 thd_atend: 1796 1840 end = end - hole_size; // adjust the new END 1797 1841 if (dest >= end) … … 1800 1844 dest = end = text; // keep pointers valid 1801 1845 file_modified++; // has the file been modified 1802 1803 return (dest);1846 thd0: 1847 return dest; 1804 1848 } 1805 1849 … … 1807 1851 // if dist <= 0, do not include, or go past, a NewLine 1808 1852 // 1809 static Byte *yank_delete(Byte * start, Byte* stop, int dist, int yf)1810 { 1811 Byte*p;1853 static char *yank_delete(char * start, char * stop, int dist, int yf) 1854 { 1855 char *p; 1812 1856 1813 1857 // make sure start <= stop … … 1819 1863 } 1820 1864 if (dist <= 0) { 1821 // we can 1865 // we cannot cross NL boundaries 1822 1866 p = start; 1823 1867 if (*p == '\n') 1824 return (p);1868 return p; 1825 1869 // dont go past a NewLine 1826 1870 for (; p + 1 <= stop; p++) { … … 1832 1876 } 1833 1877 p = start; 1834 #if def CONFIG_FEATURE_VI_YANKMARK1878 #if ENABLE_FEATURE_VI_YANKMARK 1835 1879 text_yank(start, stop, YDreg); 1836 #endif /* CONFIG_FEATURE_VI_YANKMARK */1880 #endif 1837 1881 if (yf == YANKDEL) { 1838 1882 p = text_hole_delete(start, stop); 1839 1883 } // delete lines 1840 return (p);1884 return p; 1841 1885 } 1842 1886 … … 1844 1888 { 1845 1889 puts("These features are available:" 1846 #if def CONFIG_FEATURE_VI_SEARCH1890 #if ENABLE_FEATURE_VI_SEARCH 1847 1891 "\n\tPattern searches with / and ?" 1848 #endif /* CONFIG_FEATURE_VI_SEARCH */1849 #if def CONFIG_FEATURE_VI_DOT_CMD1892 #endif 1893 #if ENABLE_FEATURE_VI_DOT_CMD 1850 1894 "\n\tLast command repeat with \'.\'" 1851 #endif /* CONFIG_FEATURE_VI_DOT_CMD */1852 #if def CONFIG_FEATURE_VI_YANKMARK1895 #endif 1896 #if ENABLE_FEATURE_VI_YANKMARK 1853 1897 "\n\tLine marking with 'x" 1854 1898 "\n\tNamed buffers with \"x" 1855 #endif /* CONFIG_FEATURE_VI_YANKMARK */1856 #if def CONFIG_FEATURE_VI_READONLY1899 #endif 1900 #if ENABLE_FEATURE_VI_READONLY 1857 1901 "\n\tReadonly if vi is called as \"view\"" 1858 1902 "\n\tReadonly with -R command line arg" 1859 #endif /* CONFIG_FEATURE_VI_READONLY */1860 #if def CONFIG_FEATURE_VI_SET1903 #endif 1904 #if ENABLE_FEATURE_VI_SET 1861 1905 "\n\tSome colon mode commands with \':\'" 1862 #endif /* CONFIG_FEATURE_VI_SET */1863 #if def CONFIG_FEATURE_VI_SETOPTS1906 #endif 1907 #if ENABLE_FEATURE_VI_SETOPTS 1864 1908 "\n\tSettable options with \":set\"" 1865 #endif /* CONFIG_FEATURE_VI_SETOPTS */1866 #if def CONFIG_FEATURE_VI_USE_SIGNALS1909 #endif 1910 #if ENABLE_FEATURE_VI_USE_SIGNALS 1867 1911 "\n\tSignal catching- ^C" 1868 1912 "\n\tJob suspend and resume with ^Z" 1869 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */1870 #if def CONFIG_FEATURE_VI_WIN_RESIZE1913 #endif 1914 #if ENABLE_FEATURE_VI_WIN_RESIZE 1871 1915 "\n\tAdapt to window re-sizes" 1872 #endif /* CONFIG_FEATURE_VI_WIN_RESIZE */1916 #endif 1873 1917 ); 1874 1918 } 1875 1919 1876 static inline void print_literal(Byte * buf, Byte * s) // copy s to buf, convert unprintable 1877 { 1878 Byte c, b[2]; 1920 static inline void print_literal(char * buf, const char * s) // copy s to buf, convert unprintable 1921 { 1922 unsigned char c; 1923 char b[2]; 1879 1924 1880 1925 b[1] = '\0'; 1881 strcpy((char *) buf, ""); // init buf1882 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++) { 1885 1930 int c_is_no_print; 1886 1931 1887 1932 c = *s; 1888 c_is_no_print = c > 127&& !Isprint(c);1933 c_is_no_print = (c & 0x80) && !Isprint(c); 1889 1934 if (c_is_no_print) { 1890 strcat( (char *)buf, SOn);1935 strcat(buf, SOn); 1891 1936 c = '.'; 1892 1937 } 1893 1938 if (c < ' ' || c == 127) { 1894 strcat( (char *)buf, "^");1895 if (c == 127)1939 strcat(buf, "^"); 1940 if (c == 127) 1896 1941 c = '?'; 1897 1898 c += '@';1942 else 1943 c += '@'; 1899 1944 } 1900 1945 b[0] = c; 1901 strcat( (char *) buf, (char *)b);1946 strcat(buf, b); 1902 1947 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 1955 static void start_new_cmd_q(char c) 1912 1956 { 1913 1957 // release old cmd 1914 1958 free(last_modifying_cmd); 1915 1959 // 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); 1918 1961 // if there is a current cmd count put it in the buffer first 1919 1962 if (cmdcnt > 0) 1920 sprintf( (char *)last_modifying_cmd, "%d%c", cmdcnt, c);1963 sprintf(last_modifying_cmd, "%d%c", cmdcnt, c); 1921 1964 else // just save char c onto queue 1922 1965 last_modifying_cmd[0] = c; … … 1926 1969 static void end_cmd_q(void) 1927 1970 { 1928 #if def CONFIG_FEATURE_VI_YANKMARK1971 #if ENABLE_FEATURE_VI_YANKMARK 1929 1972 YDreg = 26; // go back to default Yank/Delete reg 1930 #endif /* CONFIG_FEATURE_VI_YANKMARK */1973 #endif 1931 1974 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 1981 static char *string_insert(char * p, char * s) // insert the string at 'p' 1938 1982 { 1939 1983 int cnt, i; 1940 1984 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 2001 static char *text_yank(char * p, char * q, int dest) // copy text into a register 2002 { 2003 char *t; 1959 2004 int cnt; 1960 2005 … … 1967 2012 t = reg[dest]; 1968 2013 free(t); // if already a yank register, free it 1969 t = (Byte *)xmalloc(cnt + 1); // get a new register2014 t = xmalloc(cnt + 1); // get a new register 1970 2015 memset(t, '\0', cnt + 1); // clear new text[] 1971 strncpy( (char *) t, (char *)p, cnt); // copy text[] into bufer2016 strncpy(t, p, cnt); // copy text[] into bufer 1972 2017 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 2021 static char what_reg(void) 2022 { 2023 char c; 2024 1982 2025 c = 'D'; // default to D-reg 1983 2026 if (0 <= YDreg && YDreg <= 25) 1984 c = 'a' + ( Byte) YDreg;2027 c = 'a' + (char) YDreg; 1985 2028 if (YDreg == 26) 1986 2029 c = 'D'; 1987 2030 if (YDreg == 27) 1988 2031 c = 'U'; 1989 return (c);1990 } 1991 1992 static void check_context( Bytecmd)2032 return c; 2033 } 2034 2035 static void check_context(char cmd) 1993 2036 { 1994 2037 // A context is defined to be "modifying text" … … 1996 2039 1997 2040 if (dot < context_start || dot > context_end) { 1998 if (strchr( (char *)modifying_cmds, cmd) != NULL) {2041 if (strchr(modifying_cmds, cmd) != NULL) { 1999 2042 // we are trying to modify text[]- make this the current context 2000 2043 mark[27] = mark[26]; // move cur to prev … … 2005 2048 } 2006 2049 } 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 2052 static inline char *swap_context(char * p) // goto new context for '' command make this the current context 2053 { 2054 char *tmp; 2013 2055 2014 2056 // the current context is in mark[26] … … 2023 2065 context_end = next_line(next_line(next_line(p))); 2024 2066 } 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 */ 2033 2070 2034 2071 //----- Set terminal attributes -------------------------------- … … 2053 2090 2054 2091 //----- Come here when we get a window resize signal --------- 2055 #if def CONFIG_FEATURE_VI_USE_SIGNALS2092 #if ENABLE_FEATURE_VI_USE_SIGNALS 2056 2093 static void winch_sig(int sig ATTRIBUTE_UNUSED) 2057 2094 { 2058 2095 signal(SIGWINCH, winch_sig); 2059 2096 if (ENABLE_FEATURE_VI_WIN_RESIZE) 2060 2097 get_terminal_width_height(0, &columns, &rows); 2061 2098 new_screen(rows, columns); // get memory for virtual screen 2062 2099 redraw(TRUE); // re-draw the screen … … 2091 2128 { 2092 2129 signal(SIGINT, catch_sig); 2093 if (sig)2130 if (sig) 2094 2131 longjmp(restart, sig); 2095 2132 } 2096 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */2133 #endif /* FEATURE_VI_USE_SIGNALS */ 2097 2134 2098 2135 static int mysleep(int hund) // sleep for 'h' 1/100 seconds 2099 2136 { 2137 fd_set rfds; 2138 struct timeval tv; 2139 2100 2140 // Don't hang- Wait 5/100 seconds- 1 Sec= 1000000 2101 2141 fflush(stdout); … … 2105 2145 tv.tv_usec = hund * 10000; 2106 2146 select(1, &rfds, NULL, NULL, &tv); 2107 return (FD_ISSET(0, &rfds));2147 return FD_ISSET(0, &rfds); 2108 2148 } 2109 2149 … … 2113 2153 2114 2154 //----- IO Routines -------------------------------------------- 2115 static Bytereadit(void) // read (maybe cursor) key from stdin2116 { 2117 Bytec;2155 static char readit(void) // read (maybe cursor) key from stdin 2156 { 2157 char c; 2118 2158 int n; 2119 2159 struct esc_cmds { 2120 2160 const char *seq; 2121 Byteval;2161 char val; 2122 2162 }; 2123 2163 2124 2164 static const struct esc_cmds esccmds[] = { 2125 {"OA", (Byte)VI_K_UP}, // cursor key Up2126 {"OB", (Byte)VI_K_DOWN}, // cursor key Down2127 {"OC", (Byte)VI_K_RIGHT}, // Cursor Key Right2128 {"OD", (Byte)VI_K_LEFT}, // cursor key Left2129 {"OH", (Byte)VI_K_HOME}, // Cursor Key Home2130 {"OF", (Byte)VI_K_END}, // Cursor Key End2131 {"[A", (Byte)VI_K_UP}, // cursor key Up2132 {"[B", (Byte)VI_K_DOWN}, // cursor key Down2133 {"[C", (Byte)VI_K_RIGHT}, // Cursor Key Right2134 {"[D", (Byte)VI_K_LEFT}, // cursor key Left2135 {"[H", (Byte)VI_K_HOME}, // Cursor Key Home2136 {"[F", (Byte)VI_K_END}, // Cursor Key End2137 {"[1~", (Byte) VI_K_HOME},// Cursor Key Home2138 {"[2~", (Byte)VI_K_INSERT}, // Cursor Key Insert2139 {"[4~", (Byte) VI_K_END},// Cursor Key End2140 {"[5~", (Byte)VI_K_PAGEUP}, // Cursor Key Page Up2141 {"[6~", (Byte) VI_K_PAGEDOWN},// Cursor Key Page Down2142 {"OP", (Byte)VI_K_FUN1}, // Function Key F12143 {"OQ", (Byte)VI_K_FUN2}, // Function Key F22144 {"OR", (Byte)VI_K_FUN3}, // Function Key F32145 {"OS", (Byte)VI_K_FUN4}, // Function Key F42146 {"[15~", (Byte)VI_K_FUN5}, // Function Key F52147 {"[17~", (Byte)VI_K_FUN6}, // Function Key F62148 {"[18~", (Byte)VI_K_FUN7}, // Function Key F72149 {"[19~", (Byte)VI_K_FUN8}, // Function Key F82150 {"[20~", (Byte)VI_K_FUN9}, // Function Key F92151 {"[21~", (Byte)VI_K_FUN10}, // Function Key F102152 {"[23~", (Byte)VI_K_FUN11}, // Function Key F112153 {"[24~", (Byte)VI_K_FUN12}, // Function Key F122154 {"[11~", (Byte)VI_K_FUN1}, // Function Key F12155 {"[12~", (Byte)VI_K_FUN2}, // Function Key F22156 {"[13~", (Byte)VI_K_FUN3}, // Function Key F32157 {"[14~", (Byte)VI_K_FUN4}, // Function Key F42165 {"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 2158 2198 }; 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 2163 2202 fflush(stdout); 2164 2203 n = readed_for_parse; 2165 2204 // get input from User- are there already input chars in Q? 2166 2205 if (n <= 0) { 2167 2206 ri0: 2168 2207 // the Q is empty, wait for a typed char 2169 n = read(0, readbuffer, BUFSIZ- 1);2208 n = read(0, readbuffer, MAX_LINELEN - 1); 2170 2209 if (n < 0) { 2171 2210 if (errno == EINTR) 2172 2211 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) 2180 2214 editing = 0; 2181 2215 errno = 0; 2182 2216 } 2183 if (n <= 0)2217 if (n <= 0) 2184 2218 return 0; // error 2185 2219 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); 2199 2236 if (r > 0) { 2200 2237 n += r; … … 2205 2242 } 2206 2243 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? 2209 2246 const struct esc_cmds *eindex; 2210 2247 … … 2212 2249 int cnt = strlen(eindex->seq); 2213 2250 2214 if (n <= cnt)2251 if (n <= cnt) 2215 2252 continue; 2216 if (strncmp(eindex->seq, (char *)readbuffer + 1, cnt))2253 if (strncmp(eindex->seq, readbuffer + 1, cnt)) 2217 2254 continue; 2218 2255 // is a Cursor key- put derived value back into Q … … 2222 2259 break; 2223 2260 } 2224 if (eindex == &esccmds[ESCCMDS_COUNT]) {2261 if (eindex == &esccmds[ESCCMDS_COUNT]) { 2225 2262 /* defined ESC sequence not found, set only one ESC */ 2226 2263 n = 1; … … 2231 2268 // remove key sequence from Q 2232 2269 readed_for_parse -= n; 2233 memmove(readbuffer, readbuffer + n, BUFSIZ- n);2234 (void)alarm(3); // we are done waiting for input, turn alarm ON2235 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; 2236 2273 } 2237 2274 2238 2275 //----- IO Routines -------------------------------------------- 2239 static Byteget_one_char(void)2240 { 2241 static Bytec;2242 2243 #if def CONFIG_FEATURE_VI_DOT_CMD2276 static char get_one_char(void) 2277 { 2278 static char c; 2279 2280 #if ENABLE_FEATURE_VI_DOT_CMD 2244 2281 // ! adding2q && ioq == 0 read() 2245 2282 // ! adding2q && ioq != 0 *ioq … … 2265 2302 c = readit(); // get the users input 2266 2303 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) { 2269 2306 psbs("last_modifying_cmd overrun"); 2270 2307 } else { … … 2274 2311 } 2275 2312 } 2276 #else /* CONFIG_FEATURE_VI_DOT_CMD */2313 #else 2277 2314 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 2319 static 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; 2286 2325 int i; 2287 static Byte *obufp = NULL; 2288 2289 strcpy((char *) buf, (char *) prompt); 2326 2327 strcpy(buf, prompt); 2290 2328 last_status_cksum = 0; // force status update 2291 2329 place_cursor(rows - 1, 0, FALSE); // go to Status line, bottom of screen 2292 2330 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) { 2296 2335 c = get_one_char(); // read user input 2297 2336 if (c == '\n' || c == '\r' || c == 27) … … 2315 2354 refresh(FALSE); 2316 2355 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 2360 static int file_size(const char *fn) // what is the byte size of "fn" 2322 2361 { 2323 2362 struct stat st_buf; 2324 int cnt, sr; 2325 2326 if (fn == 0 || strlen((char *)fn) <= 0) 2327 return (-1); 2363 int cnt; 2364 2328 2365 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 2331 2367 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 2371 static 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)); 2346 2381 goto fi0; 2347 2382 } 2348 if ( size== 0) {2349 // OK- this is just a no-op2350 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); 2351 2386 goto fi0; 2352 2387 } 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); 2355 2392 goto fi0; 2356 2393 } 2394 */ 2357 2395 if (p < text || p > end) { 2358 2396 psbs("Trying to insert file outside of memory"); … … 2360 2398 } 2361 2399 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); 2367 2402 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; 2382 2407 p = text_hole_make(p, size); 2408 if (p == NULL) 2409 goto fi0; 2383 2410 cnt = read(fd, p, size); 2384 close(fd);2385 2411 if (cnt < 0) { 2386 cnt = -1;2412 psbs("\"%s\" %s", fn, strerror(errno)); 2387 2413 p = text_hole_delete(p, p + size - 1); // un-do buffer insert 2388 psbs("could not read file \"%s\"", fn);2389 2414 } else if (cnt < size) { 2390 2415 // There was a partial read, shrink unused space text[] 2391 2416 p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert 2392 psbs("c ouldnot read all of file \"%s\"", fn);2417 psbs("cannot read all of file \"%s\"", fn); 2393 2418 } 2394 2419 if (cnt >= size) 2395 2420 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 2438 static int file_write(char * fn, char * first, char * last) 2401 2439 { 2402 2440 int fd, cnt, charcnt; … … 2404 2442 if (fn == 0) { 2405 2443 psbs("No current filename"); 2406 return (-2);2444 return -2; 2407 2445 } 2408 2446 charcnt = 0; 2409 2447 // 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); 2411 2449 if (fd < 0) 2412 return (-1);2450 return -1; 2413 2451 cnt = last - first + 1; 2414 2452 charcnt = write(fd, first, cnt); 2415 2453 if (charcnt == cnt) { 2416 2454 // good write 2417 //file_modified = FALSE; // the file has not been modified2455 //file_modified = FALSE; // the file has not been modified 2418 2456 } else { 2419 2457 charcnt = 0; 2420 2458 } 2421 2459 close(fd); 2422 return (charcnt);2460 return charcnt; 2423 2461 } 2424 2462 … … 2438 2476 static void place_cursor(int row, int col, int opti) 2439 2477 { 2440 char cm1[ BUFSIZ];2478 char cm1[MAX_LINELEN]; 2441 2479 char *cm; 2442 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2443 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 buffer2480 #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 2450 2488 2451 2489 if (row < 0) row = 0; … … 2455 2493 2456 2494 //----- 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 2462 2501 //----- find the minimum # of chars to move cursor ------------- 2463 2502 //----- 2. Try moving with discreet chars (Newline, [back]space, ...) 2464 memset(cm2, '\0', BUFSIZ - 1); // clear the buffer2503 memset(cm2, '\0', MAX_LINELEN); // clear the buffer 2465 2504 2466 2505 // move to the correct row … … 2480 2519 // just send out orignal source char to get to correct place 2481 2520 screenp = &screen[row * columns]; // start of screen line 2482 strncat(cm2, (char* )screenp, col);2521 strncat(cm2, screenp, col); 2483 2522 2484 2523 //----- 3. Try some other way of moving cursor … … 2486 2525 2487 2526 // pick the shortest cursor motion to send out 2488 cm = cm1;2527 cm = cm1; 2489 2528 if (strlen(cm2) < strlen(cm)) { 2490 cm = cm2;2529 cm = cm2; 2491 2530 } /* else if (strlen(cm3) < strlen(cm)) { 2492 2531 cm= cm3; 2493 2532 } */ 2494 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2495 2533 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2534 pc0: 2496 2535 write1(cm); // move the cursor 2497 2536 } … … 2526 2565 standout_start(); // send "start reverse video" sequence 2527 2566 redraw(TRUE); 2528 (void)mysleep(h);2567 mysleep(h); 2529 2568 standout_end(); // send "end reverse video" sequence 2530 2569 redraw(TRUE); … … 2533 2572 static void Indicate_Error(void) 2534 2573 { 2535 #if def CONFIG_FEATURE_VI_CRASHME2574 #if ENABLE_FEATURE_VI_CRASHME 2536 2575 if (crashme > 0) 2537 2576 return; // generate a random command 2538 #endif /* CONFIG_FEATURE_VI_CRASHME */2577 #endif 2539 2578 if (!err_method) { 2540 2579 write1(bell); // send out a bell character … … 2551 2590 } 2552 2591 2553 static int bufsum( unsignedchar *buf, int count)2592 static int bufsum(char *buf, int count) 2554 2593 { 2555 2594 int sum = 0; 2556 unsigned char *e = buf + count; 2595 char *e = buf + count; 2596 2557 2597 while (buf < e) 2558 sum += *buf++;2598 sum += (unsigned char) *buf++; 2559 2599 return sum; 2560 2600 } … … 2574 2614 last_status_cksum= cksum; // remember if we have seen this line 2575 2615 place_cursor(rows - 1, 0, FALSE); // put cursor on status line 2576 write1( (char*)status_buffer);2616 write1(status_buffer); 2577 2617 clear_to_eol(); 2578 2618 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)) > 2580 2620 (columns - 1) ) { 2581 2621 have_status_msg = 0; … … 2596 2636 2597 2637 va_start(args, format); 2598 strcpy( (char *)status_buffer, SOs); // Terminal standout mode on2599 vsprintf( (char *) status_buffer + strlen((char *)status_buffer), format, args);2600 strcat( (char *)status_buffer, SOn); // Terminal standout mode off2638 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 2601 2641 va_end(args); 2602 2642 2603 2643 have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; 2604 2605 return;2606 2644 } 2607 2645 … … 2612 2650 2613 2651 va_start(args, format); 2614 vsprintf( (char *)status_buffer, format, args);2652 vsprintf(status_buffer, format, args); 2615 2653 va_end(args); 2616 2654 2617 2655 have_status_msg = 1; 2618 2619 return; 2620 } 2621 2622 static void ni(Byte * s) // display messages 2623 { 2624 Byte buf[BUFSIZ]; 2656 } 2657 2658 static void ni(const char * s) // display messages 2659 { 2660 char buf[MAX_LINELEN]; 2625 2661 2626 2662 print_literal(buf, s); … … 2630 2666 static int format_edit_status(void) // show file status on status line 2631 2667 { 2668 static int tot; 2669 static const char cmd_mode_indicator[] ALIGN1 = "-IR-"; 2632 2670 int cur, percent, ret, trunc_at; 2633 static int tot;2634 2671 2635 2672 // file_modified is now a counter rather than a flag. this … … 2663 2700 columns : STATUS_BUFFER_LEN-1; 2664 2701 2665 ret = snprintf( (char *)status_buffer, trunc_at+1,2666 #if def CONFIG_FEATURE_VI_READONLY2702 ret = snprintf(status_buffer, trunc_at+1, 2703 #if ENABLE_FEATURE_VI_READONLY 2667 2704 "%c %s%s%s %d/%d %d%%", 2668 2705 #else 2669 2706 "%c %s%s %d/%d %d%%", 2670 2707 #endif 2671 (cmd_mode ? (cmd_mode == 2 ? 'R':'I'):'-'),2672 (c fn != 0 ? (char *) cfn: "No file"),2673 #if def CONFIG_FEATURE_VI_READONLY2674 ( (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]" : ""), 2677 2714 cur, tot, percent); 2678 2715 … … 2695 2732 2696 2733 //----- Format a text[] line into a buffer --------------------- 2697 static void format_line( Byte *dest, Byte*src, int li)2734 static void format_line(char *dest, char *src, int li) 2698 2735 { 2699 2736 int co; 2700 Bytec;2701 2702 for (co = 0; co < MAX_SCR_COLS; co++) {2703 c = ' '; // assume blank2737 char c; 2738 2739 for (co = 0; co < MAX_SCR_COLS; co++) { 2740 c = ' '; // assume blank 2704 2741 if (li > 0 && co == 0) { 2705 2742 c = '~'; // not first line, assume Tilde … … 2711 2748 if (c == '\n') 2712 2749 break; 2713 if ( c > 127&& !Isprint(c)) {2750 if ((c & 0x80) && !Isprint(c)) { 2714 2751 c = '.'; 2715 2752 } 2716 if ( c < ' ' || c == 127) {2753 if ((unsigned char)(c) < ' ' || c == 0x7f) { 2717 2754 if (c == '\t') { 2718 2755 c = ' '; … … 2723 2760 } else { 2724 2761 dest[co++] = '^'; 2725 if (c == 127)2762 if (c == 0x7f) 2726 2763 c = '?'; 2727 2764 else 2728 2765 c += '@'; // make it visible 2729 2766 } … … 2745 2782 { 2746 2783 static int old_offset; 2784 2747 2785 int li, changed; 2748 Bytebuf[MAX_SCR_COLS];2749 Byte*tp, *sp; // pointer into text[] and screen[]2750 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2751 int last_li = -2;// last line that changed- for optimizing cursor movement2752 #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 2753 2791 2754 2792 if (ENABLE_FEATURE_VI_WIN_RESIZE) … … 2766 2804 2767 2805 // 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*/; 2769 2807 2770 2808 // see if there are any changes between vitual screen and buf … … 2779 2817 // compare newly formatted buffer with virtual screen 2780 2818 // look forward for first difference between buf and screen 2781 for ( 2819 for (; cs <= ce; cs++) { 2782 2820 if (buf[cs + offset] != sp[cs]) { 2783 2821 changed = TRUE; // mark for redraw … … 2797 2835 // if horz offset has changed, force a redraw 2798 2836 if (offset != old_offset) { 2799 2837 re0: 2800 2838 changed = TRUE; 2801 2839 } … … 2816 2854 place_cursor(li, cs, FALSE); 2817 2855 } else { 2818 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2856 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2819 2857 // if this just the next line 2820 2858 // try to optimize cursor movement … … 2822 2860 place_cursor(li, cs, li == (last_li+1) ? TRUE : FALSE); 2823 2861 last_li= li; 2824 #else /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2862 #else 2825 2863 place_cursor(li, cs, FALSE); // use standard ESC sequence 2826 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2864 #endif /* FEATURE_VI_OPTIMIZE_CURSOR */ 2827 2865 } 2828 2866 2829 2867 // write line out to terminal 2830 2868 { 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) { 2835 2873 putchar(*out); 2836 2874 out++; 2837 2875 } 2838 2876 } 2839 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2877 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2840 2878 last_row = li; 2841 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2842 } 2843 } 2844 2845 #if def CONFIG_FEATURE_VI_OPTIMIZE_CURSOR2879 #endif 2880 } 2881 } 2882 2883 #if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR 2846 2884 place_cursor(crow, ccol, (crow == last_row) ? TRUE : FALSE); 2847 2885 last_row = crow; 2848 2886 #else 2849 2887 place_cursor(crow, ccol, FALSE); 2850 #endif /* CONFIG_FEATURE_VI_OPTIMIZE_CURSOR */2888 #endif 2851 2889 2852 2890 if (offset != old_offset) … … 2876 2914 2877 2915 //----- Execute a Vi Command ----------------------------------- 2878 static void do_cmd(Byte c) 2879 { 2880 Byte c1, *p, *q, *msg, buf[9], *save_dot; 2916 static void do_cmd(char c) 2917 { 2918 const char *msg; 2919 char c1, *p, *q, buf[9], *save_dot; 2881 2920 int cnt, i, j, dir, yf; 2882 2921 2883 2922 c1 = c; // quiet the compiler 2884 2923 cnt = yf = dir = 0; // quiet the compiler 2885 p = q = save_dot = msg= buf; // quiet the compiler2924 msg = p = q = save_dot = buf; // quiet the compiler 2886 2925 memset(buf, '\0', 9); // clear buf 2887 2926 … … 2903 2942 if (cmd_mode == 2) { 2904 2943 // flip-flop Insert/Replace mode 2905 if (c == VI_K_INSERT) goto dc_i; 2944 if (c == VI_K_INSERT) 2945 goto dc_i; 2906 2946 // we are 'R'eplacing the current *dot with new char 2907 2947 if (*dot == '\n') { … … 2927 2967 } 2928 2968 2929 key_cmd_mode:2969 key_cmd_mode: 2930 2970 switch (c) { 2931 2971 //case 0x01: // soh … … 2937 2977 //case 0x11: // dc1 2938 2978 //case 0x13: // dc3 2939 #if def CONFIG_FEATURE_VI_CRASHME2979 #if ENABLE_FEATURE_VI_CRASHME 2940 2980 case 0x14: // dc4 ctrl-T 2941 2981 crashme = (crashme == 0) ? 1 : 0; 2942 2982 break; 2943 #endif /* CONFIG_FEATURE_VI_CRASHME */2983 #endif 2944 2984 //case 0x16: // syn 2945 2985 //case 0x17: // etb … … 2980 3020 buf[2] = '\0'; 2981 3021 } 2982 ni( (Byte *)buf);3022 ni(buf); 2983 3023 end_cmd_q(); // stop adding to q 2984 3024 case 0x00: // nul- ignore … … 2988 3028 dot_scroll(rows - 2, -1); 2989 3029 break; 2990 #if def CONFIG_FEATURE_VI_USE_SIGNALS3030 #if ENABLE_FEATURE_VI_USE_SIGNALS 2991 3031 case 0x03: // ctrl-C interrupt 2992 3032 longjmp(restart, 1); … … 2995 3035 suspend_sig(SIGTSTP); 2996 3036 break; 2997 #endif /* CONFIG_FEATURE_VI_USE_SIGNALS */3037 #endif 2998 3038 case 4: // ctrl-D scroll down half screen 2999 3039 dot_scroll((rows - 2) / 2, 1); … … 3012 3052 case VI_K_LEFT: // cursor key Left 3013 3053 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) 3015 3055 if (cmdcnt-- > 1) { 3016 3056 do_cmd(c); … … 3031 3071 place_cursor(0, 0, FALSE); // put cursor in correct place 3032 3072 clear_to_eos(); // tel terminal to erase display 3033 (void)mysleep(10);3073 mysleep(10); 3034 3074 screen_erase(); // erase the internal screen buffer 3035 3075 last_status_cksum = 0; // force status update … … 3065 3105 dot_right(); 3066 3106 break; 3067 #if def CONFIG_FEATURE_VI_YANKMARK3107 #if ENABLE_FEATURE_VI_YANKMARK 3068 3108 case '"': // "- name a register to use for Delete/Yank 3069 3109 c1 = get_one_char(); … … 3081 3121 c1 = c1 - 'a'; 3082 3122 // get the b-o-l 3083 q = mark[( int) c1];3123 q = mark[(unsigned char) c1]; 3084 3124 if (text <= q && q < end) { 3085 3125 dot = q; … … 3118 3158 } 3119 3159 // are we putting whole lines or strings 3120 if (strchr( (char *)p, '\n') != NULL) {3160 if (strchr(p, '\n') != NULL) { 3121 3161 if (c == 'P') { 3122 3162 dot_begin(); // putting lines- Put above … … 3147 3187 } 3148 3188 break; 3149 #endif /* CONFIG_FEATURE_VI_YANKMARK */3189 #endif /* FEATURE_VI_YANKMARK */ 3150 3190 case '$': // $- goto end of line 3151 3191 case VI_K_END: // Cursor Key End … … 3181 3221 do_cmd(';'); 3182 3222 } // repeat cnt 3183 if (last_forward_char == 0) break; 3223 if (last_forward_char == 0) 3224 break; 3184 3225 q = dot + 1; 3185 3226 while (q < end - 1 && *q != '\n' && *q != last_forward_char) { … … 3196 3237 dot_skip_over_ws(); 3197 3238 break; 3198 #if def CONFIG_FEATURE_VI_DOT_CMD3239 #if ENABLE_FEATURE_VI_DOT_CMD 3199 3240 case '.': // .- repeat the last modifying command 3200 3241 // Stuff the last_modifying_cmd back into stdin 3201 3242 // and let it be re-executed. 3202 3243 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 #if def CONFIG_FEATURE_VI_SEARCH3244 ioq = ioq_start = xstrdup(last_modifying_cmd); 3245 } 3246 break; 3247 #endif 3248 #if ENABLE_FEATURE_VI_SEARCH 3208 3249 case '?': // /- search for a pattern 3209 3250 case '/': // /- search for a pattern … … 3211 3252 buf[1] = '\0'; 3212 3253 q = get_input_line(buf); // get input line- use "status line" 3213 if ( strlen((char *) q) == 1)3214 goto dc3; 3215 if ( strlen((char *) q) > 1) { //new pat- save it and find3254 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 3216 3257 // there is a new pat 3217 3258 free(last_search_pattern); 3218 last_search_pattern = (Byte *) bb_xstrdup((char *)q);3259 last_search_pattern = xstrdup(q); 3219 3260 goto dc3; // now find the pattern 3220 3261 } … … 3239 3280 do_cmd(c); 3240 3281 } // repeat cnt 3241 3282 dc3: 3242 3283 if (last_search_pattern == 0) { 3243 msg = (Byte *)"No previous regular expression";3284 msg = "No previous regular expression"; 3244 3285 goto dc2; 3245 3286 } … … 3252 3293 p = dot - 1; 3253 3294 } 3254 3295 dc4: 3255 3296 q = char_search(p, last_search_pattern + 1, dir, FULL); 3256 3297 if (q != NULL) { 3257 3298 dot = q; // good search, update "dot" 3258 msg = (Byte *)"";3299 msg = ""; 3259 3300 goto dc2; 3260 3301 } … … 3267 3308 if (q != NULL) { // found something 3268 3309 dot = q; // found new pattern- goto it 3269 msg = (Byte *)"search hit BOTTOM, continuing at TOP";3310 msg = "search hit BOTTOM, continuing at TOP"; 3270 3311 if (dir == BACK) { 3271 msg = (Byte *)"search hit TOP, continuing at BOTTOM";3312 msg = "search hit TOP, continuing at BOTTOM"; 3272 3313 } 3273 3314 } 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); 3278 3320 break; 3279 3321 case '{': // {- move backward paragraph 3280 q = char_search(dot, (Byte *)"\n\n", BACK, FULL);3322 q = char_search(dot, "\n\n", BACK, FULL); 3281 3323 if (q != NULL) { // found blank line 3282 3324 dot = next_line(q); // move to next blank line … … 3284 3326 break; 3285 3327 case '}': // }- move forward paragraph 3286 q = char_search(dot, (Byte *)"\n\n", FORWARD, FULL);3328 q = char_search(dot, "\n\n", FORWARD, FULL); 3287 3329 if (q != NULL) { // found blank line 3288 3330 dot = next_line(q); // move to next blank line 3289 3331 } 3290 3332 break; 3291 #endif /* CONFIG_FEATURE_VI_SEARCH */3333 #endif /* FEATURE_VI_SEARCH */ 3292 3334 case '0': // 0- goto begining of line 3293 3335 case '1': // 1- … … 3307 3349 break; 3308 3350 case ':': // :- the colon mode commands 3309 p = get_input_line( (Byte *)":"); // get input line- use "status line"3310 #if def CONFIG_FEATURE_VI_COLON3351 p = get_input_line(":"); // get input line- use "status line" 3352 #if ENABLE_FEATURE_VI_COLON 3311 3353 colon(p); // execute the command 3312 #else /* CONFIG_FEATURE_VI_COLON */3354 #else 3313 3355 if (*p == ':') 3314 3356 p++; // move past the ':' 3315 cnt = strlen( (char *)p);3357 cnt = strlen(p); 3316 3358 if (cnt <= 0) 3317 3359 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 ) { 3320 3363 if (file_modified && p[1] != '!') { 3321 3364 psbs("No write since last change (:quit! overrides)"); … … 3323 3366 editing = 0; 3324 3367 } 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); 3330 3374 if (cnt < 0) { 3331 3375 if (cnt == -1) … … 3334 3378 file_modified = 0; 3335 3379 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 ) { 3339 3384 editing = 0; 3340 3385 } 3341 3386 } 3342 } else if (strncasecmp( (char *) p, "file", cnt) == 0) {3387 } else if (strncasecmp(p, "file", cnt) == 0) { 3343 3388 last_status_cksum = 0; // force status update 3344 } else if (sscanf( (char *)p, "%d", &j) > 0) {3389 } else if (sscanf(p, "%d", &j) > 0) { 3345 3390 dot = find_line(j); // go to line # j 3346 3391 dot_skip_over_ws(); 3347 3392 } else { // unrecognised cmd 3348 ni( (Byte *)p);3349 } 3350 #endif /* CONFIG_FEATURE_VI_COLON */3393 ni(p); 3394 } 3395 #endif /* !FEATURE_VI_COLON */ 3351 3396 break; 3352 3397 case '<': // <- Left shift something … … 3355 3400 c1 = get_one_char(); // get the type of thing to delete 3356 3401 find_range(&p, &q, c1); 3357 (void)yank_delete(p, q, 1, YANKONLY); // save copy before change3402 yank_delete(p, q, 1, YANKONLY); // save copy before change 3358 3403 p = begin_line(p); 3359 3404 q = end_line(q); … … 3364 3409 if (*p == '\t') { 3365 3410 // shrink buffer 1 char 3366 (void)text_hole_delete(p, p);3411 text_hole_delete(p, p); 3367 3412 } else if (*p == ' ') { 3368 3413 // we should be calculating columns, not just SPACE 3369 3414 for (j = 0; *p == ' ' && j < tabstop; j++) { 3370 (void)text_hole_delete(p, p);3415 text_hole_delete(p, p); 3371 3416 } 3372 3417 } 3373 3418 } else if (c == '>') { 3374 3419 // shift right -- add tab or 8 spaces 3375 (void)char_insert(p, '\t');3420 char_insert(p, '\t'); 3376 3421 } 3377 3422 } … … 3412 3457 if (c == 'C') 3413 3458 goto dc_i; // start inserting 3414 #if def CONFIG_FEATURE_VI_DOT_CMD3459 #if ENABLE_FEATURE_VI_DOT_CMD 3415 3460 if (c == 'D') 3416 3461 end_cmd_q(); // stop adding to q 3417 #endif /* CONFIG_FEATURE_VI_DOT_CMD */3462 #endif 3418 3463 break; 3419 3464 case 'G': // G- goto to a line number (default= E-O-F) … … 3440 3485 case 'i': // i- insert before current char 3441 3486 case VI_K_INSERT: // Cursor Key Insert 3442 3487 dc_i: 3443 3488 cmd_mode = 1; // start insrting 3444 3489 break; … … 3451 3496 *dot++ = ' '; // replace NL with space 3452 3497 file_modified++; 3453 while (isbl nk(*dot)) { // delete leading WS3498 while (isblank(*dot)) { // delete leading WS 3454 3499 dot_delete(); 3455 3500 } … … 3489 3534 break; 3490 3535 case 'R': // R- continuous Replace char 3491 3536 dc5: 3492 3537 cmd_mode = 2; 3493 3538 break; … … 3518 3563 } 3519 3564 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); 3527 3570 if (cnt < 0) { 3528 3571 if (cnt == -1) … … 3561 3604 case 'c': // c- change something 3562 3605 case 'd': // d- delete something 3563 #if def CONFIG_FEATURE_VI_YANKMARK3606 #if ENABLE_FEATURE_VI_YANKMARK 3564 3607 case 'y': // y- yank something 3565 3608 case 'Y': // Y- Yank a line 3566 #endif /* CONFIG_FEATURE_VI_YANKMARK */3609 #endif 3567 3610 yf = YANKDEL; // assume either "c" or "d" 3568 #if def CONFIG_FEATURE_VI_YANKMARK3611 #if ENABLE_FEATURE_VI_YANKMARK 3569 3612 if (c == 'y' || c == 'Y') 3570 3613 yf = YANKONLY; 3571 #endif /* CONFIG_FEATURE_VI_YANKMARK */3614 #endif 3572 3615 c1 = 'y'; 3573 3616 if (c != 'Y') … … 3579 3622 if (c == 'c') { 3580 3623 // don't include trailing WS as part of word 3581 while (isbl nk(*q)) {3624 while (isblank(*q)) { 3582 3625 if (q <= text || q[-1] == '\n') 3583 3626 break; … … 3610 3653 // if CHANGING, not deleting, start inserting after the delete 3611 3654 if (c == 'c') { 3612 strcpy( (char *)buf, "Change");3655 strcpy(buf, "Change"); 3613 3656 goto dc_i; // start inserting 3614 3657 } 3615 3658 if (c == 'd') { 3616 strcpy( (char *)buf, "Delete");3617 } 3618 #if def CONFIG_FEATURE_VI_YANKMARK3659 strcpy(buf, "Delete"); 3660 } 3661 #if ENABLE_FEATURE_VI_YANKMARK 3619 3662 if (c == 'y' || c == 'Y') { 3620 strcpy( (char *)buf, "Yank");3663 strcpy(buf, "Yank"); 3621 3664 } 3622 3665 p = reg[YDreg]; 3623 q = p + strlen( (char *)p);3666 q = p + strlen(p); 3624 3667 for (cnt = 0; p <= q; p++) { 3625 3668 if (*p == '\n') … … 3627 3670 } 3628 3671 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 3631 3674 end_cmd_q(); // stop adding to q 3632 3675 } … … 3717 3760 } 3718 3761 3719 3762 dc1: 3720 3763 // if text[] just became empty, add back an empty line 3721 3764 if (end == text) { 3722 (void)char_insert(text, '\n'); // start empty buf with dummy line3765 char_insert(text, '\n'); // start empty buf with dummy line 3723 3766 dot = text; 3724 3767 } … … 3727 3770 dot = bound_dot(dot); // make sure "dot" is valid 3728 3771 } 3729 #if def CONFIG_FEATURE_VI_YANKMARK3772 #if ENABLE_FEATURE_VI_YANKMARK 3730 3773 check_context(c); // update the current context 3731 #endif /* CONFIG_FEATURE_VI_YANKMARK */3774 #endif 3732 3775 3733 3776 if (!isdigit(c)) … … 3739 3782 } 3740 3783 3741 #if def CONFIG_FEATURE_VI_CRASHME3784 #if ENABLE_FEATURE_VI_CRASHME 3742 3785 static int totalcmds = 0; 3743 3786 static int Mp = 85; // Movement command Probability … … 3748 3791 static int Pp = 99; // Put command Probability 3749 3792 static 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", 3793 const char chars[20] = "\t012345 abcdABCD-=.$"; 3794 const char *const words[20] = { 3795 "this", "is", "a", "test", 3752 3796 "broadcast", "the", "emergency", "of", 3753 3797 "system", "quick", "brown", "fox", … … 3755 3799 "back", "January", "Febuary", "March" 3756 3800 }; 3757 c har *lines[20] = {3801 const char *const lines[20] = { 3758 3802 "You should have received a copy of the GNU General Public License\n", 3759 3803 "char c, cm, *cmd, *cmd1;\n", … … 3813 3857 if (readed_for_parse > 0) 3814 3858 goto cd1; 3815 3859 cd0: 3816 3860 startrbi = rbi = 0; 3817 3861 sleeptime = 0; // how long to pause between commands 3818 memset(readbuffer, '\0', BUFSIZ); // clear the read buffer3862 memset(readbuffer, '\0', MAX_LINELEN); // clear the read buffer 3819 3863 // generate a command by percentages 3820 3864 percent = (int) lrand48() % 100; // get a number from 0-99 … … 3875 3919 readbuffer[rbi++] = chars[((int) lrand48() % strlen(chars))]; 3876 3920 } 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, " "); 3879 3923 sleeptime = 0; // how fast to type 3880 3924 } else if (thing == 2) { // insert lines 3881 strcat( (char *)readbuffer, lines[(int) lrand48() % 20]);3925 strcat(readbuffer, lines[(int) lrand48() % 20]); 3882 3926 sleeptime = 0; // how fast to type 3883 3927 } else { // insert multi-lines 3884 strcat( (char *)readbuffer, multilines[(int) lrand48() % 20]);3928 strcat(readbuffer, multilines[(int) lrand48() % 20]); 3885 3929 sleeptime = 0; // how fast to type 3886 3930 } 3887 3931 } 3888 strcat( (char *)readbuffer, "\033");3932 strcat(readbuffer, "\033"); 3889 3933 } 3890 3934 readed_for_parse = strlen(readbuffer); 3891 3935 cd1: 3892 3936 totalcmds++; 3893 3937 if (sleeptime > 0) 3894 (void)mysleep(sleeptime); // sleep 1/100 sec3938 mysleep(sleeptime); // sleep 1/100 sec 3895 3939 } 3896 3940 … … 3899 3943 { 3900 3944 static time_t oldtim; 3945 3901 3946 time_t tim; 3902 char d[2], msg[ BUFSIZ];3947 char d[2], msg[MAX_LINELEN]; 3903 3948 3904 3949 msg[0] = '\0'; 3905 3950 if (end < text) { 3906 strcat( (char *)msg, "end<text ");3951 strcat(msg, "end<text "); 3907 3952 } 3908 3953 if (end > textend) { 3909 strcat( (char *)msg, "end>textend ");3954 strcat(msg, "end>textend "); 3910 3955 } 3911 3956 if (dot < text) { 3912 strcat( (char *)msg, "dot<text ");3957 strcat(msg, "dot<text "); 3913 3958 } 3914 3959 if (dot > end) { 3915 strcat( (char *)msg, "dot>end ");3960 strcat(msg, "dot>end "); 3916 3961 } 3917 3962 if (screenbegin < text) { 3918 strcat( (char *)msg, "screenbegin<text ");3963 strcat(msg, "screenbegin<text "); 3919 3964 } 3920 3965 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]) { 3925 3970 alarm(0); 3926 3971 printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", … … 3935 3980 tim = (time_t) time((time_t *) 0); 3936 3981 if (tim >= (oldtim + 3)) { 3937 sprintf( (char *)status_buffer,3982 sprintf(status_buffer, 3938 3983 "Tot=%d: M=%d N=%d I=%d D=%d Y=%d P=%d U=%d size=%d", 3939 3984 totalcmds, M, N, I, D, Y, P, U, end - text + 1); 3940 3985 oldtim = tim; 3941 3986 } 3942 return; 3943 } 3944 #endif /* CONFIG_FEATURE_VI_CRASHME */ 3987 } 3988 #endif
Note:
See TracChangeset
for help on using the changeset viewer.