aboutsummaryrefslogtreecommitdiff
path: root/editors
diff options
context:
space:
mode:
Diffstat (limited to 'editors')
-rw-r--r--editors/awk.c266
1 files changed, 139 insertions, 127 deletions
diff --git a/editors/awk.c b/editors/awk.c
index 2245cad03..8bc56756c 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -283,88 +283,80 @@ enum {
283#define OC_B OC_BUILTIN 283#define OC_B OC_BUILTIN
284 284
285static const char tokenlist[] ALIGN1 = 285static const char tokenlist[] ALIGN1 =
286 "\1(" NTC 286 "\1(" NTC
287 "\1)" NTC 287 "\1)" NTC
288 "\1/" NTC /* REGEXP */ 288 "\1/" NTC /* REGEXP */
289 "\2>>" "\1>" "\1|" NTC /* OUTRDR */ 289 "\2>>" "\1>" "\1|" NTC /* OUTRDR */
290 "\2++" "\2--" NTC /* UOPPOST */ 290 "\2++" "\2--" NTC /* UOPPOST */
291 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ 291 "\2++" "\2--" "\1$" NTC /* UOPPRE1 */
292 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ 292 "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */
293 "\2*=" "\2/=" "\2%=" "\2^=" 293 "\2*=" "\2/=" "\2%=" "\2^="
294 "\1+" "\1-" "\3**=" "\2**" 294 "\1+" "\1-" "\3**=" "\2**"
295 "\1/" "\1%" "\1^" "\1*" 295 "\1/" "\1%" "\1^" "\1*"
296 "\2!=" "\2>=" "\2<=" "\1>" 296 "\2!=" "\2>=" "\2<=" "\1>"
297 "\1<" "\2!~" "\1~" "\2&&" 297 "\1<" "\2!~" "\1~" "\2&&"
298 "\2||" "\1?" "\1:" NTC 298 "\2||" "\1?" "\1:" NTC
299 "\2in" NTC 299 "\2in" NTC
300 "\1," NTC 300 "\1," NTC
301 "\1|" NTC 301 "\1|" NTC
302 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ 302 "\1+" "\1-" "\1!" NTC /* UOPPRE2 */
303 "\1]" NTC 303 "\1]" NTC
304 "\1{" NTC 304 "\1{" NTC
305 "\1}" NTC 305 "\1}" NTC
306 "\1;" NTC 306 "\1;" NTC
307 "\1\n" NTC 307 "\1\n" NTC
308 "\2if" "\2do" "\3for" "\5break" /* STATX */ 308 "\2if" "\2do" "\3for" "\5break" /* STATX */
309 "\10continue" "\6delete" "\5print" 309 "\10continue" "\6delete" "\5print"
310 "\6printf" "\4next" "\10nextfile" 310 "\6printf" "\4next" "\10nextfile"
311 "\6return" "\4exit" NTC 311 "\6return" "\4exit" NTC
312 "\5while" NTC 312 "\5while" NTC
313 "\4else" NTC 313 "\4else" NTC
314 314
315 "\3and" "\5compl" "\6lshift" "\2or" 315 "\3and" "\5compl" "\6lshift" "\2or"
316 "\6rshift" "\3xor" 316 "\6rshift" "\3xor"
317 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ 317 "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */
318 "\3cos" "\3exp" "\3int" "\3log" 318 "\3cos" "\3exp" "\3int" "\3log"
319 "\4rand" "\3sin" "\4sqrt" "\5srand" 319 "\4rand" "\3sin" "\4sqrt" "\5srand"
320 "\6gensub" "\4gsub" "\5index" "\6length" 320 "\6gensub" "\4gsub" "\5index" "\6length"
321 "\5match" "\5split" "\7sprintf" "\3sub" 321 "\5match" "\5split" "\7sprintf" "\3sub"
322 "\6substr" "\7systime" "\10strftime" "\6mktime" 322 "\6substr" "\7systime" "\10strftime" "\6mktime"
323 "\7tolower" "\7toupper" NTC 323 "\7tolower" "\7toupper" NTC
324 "\7getline" NTC 324 "\7getline" NTC
325 "\4func" "\10function" NTC 325 "\4func" "\10function" NTC
326 "\5BEGIN" NTC 326 "\5BEGIN" NTC
327 "\3END" "\0" 327 "\3END"
328 /* compiler adds trailing "\0" */
328 ; 329 ;
329 330
330static const uint32_t tokeninfo[] = { 331static const uint32_t tokeninfo[] = {
331 0, 332 0,
332 0, 333 0,
333 OC_REGEXP, 334 OC_REGEXP,
334 xS|'a', xS|'w', xS|'|', 335 xS|'a', xS|'w', xS|'|',
335 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', 336 OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m',
336 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', 337 OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5),
337 OC_FIELD|xV|P(5), 338 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-',
338 OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), 339 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&',
339 OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', 340 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&',
340 OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', 341 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
341 OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', 342 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
342 OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', 343 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
343 OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', 344 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':',
344 OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', 345 OC_IN|SV|P(49), /* in */
345 OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*',
346 OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3,
347 OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1,
348 OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!',
349 OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55),
350 OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?',
351 OC_COLON|xx|P(67)|':',
352 OC_IN|SV|P(49),
353 OC_COMMA|SS|P(80), 346 OC_COMMA|SS|P(80),
354 OC_PGETLINE|SV|P(37), 347 OC_PGETLINE|SV|P(37),
355 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', 348 OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!',
356 OC_UNARY|xV|P(19)|'!', 349 0, /* ] */
357 0, 350 0,
358 0, 351 0,
359 0, 352 0,
360 0, 353 0, /* \n */
361 0, 354 ST_IF, ST_DO, ST_FOR, OC_BREAK,
362 ST_IF, ST_DO, ST_FOR, OC_BREAK, 355 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT,
363 OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, 356 OC_PRINTF, OC_NEXT, OC_NEXTFILE,
364 OC_PRINTF, OC_NEXT, OC_NEXTFILE, 357 OC_RETURN|Vx, OC_EXIT|Nx,
365 OC_RETURN|Vx, OC_EXIT|Nx,
366 ST_WHILE, 358 ST_WHILE,
367 0, 359 0, /* else */
368 360
369 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), 361 OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83),
370 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), 362 OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83),
@@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = {
376 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), 368 OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b),
377 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), 369 OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49),
378 OC_GETLINE|SV|P(0), 370 OC_GETLINE|SV|P(0),
379 0, 0, 371 0, 0,
380 0, 372 0,
381 0 373 0 /* END */
382}; 374};
383 375
384/* internal variable names and their initial values */ 376/* internal variable names and their initial values */
@@ -532,9 +524,7 @@ static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
532static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; 524static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
533static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; 525static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
534static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; 526static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
535#if !ENABLE_FEATURE_AWK_LIBM
536static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; 527static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
537#endif
538 528
539static void zero_out_var(var *vp) 529static void zero_out_var(var *vp)
540{ 530{
@@ -692,8 +682,11 @@ static char nextchar(char **s)
692 pps = *s; 682 pps = *s;
693 if (c == '\\') 683 if (c == '\\')
694 c = bb_process_escape_sequence((const char**)s); 684 c = bb_process_escape_sequence((const char**)s);
695 if (c == '\\' && *s == pps) 685 if (c == '\\' && *s == pps) { /* unrecognized \z? */
696 c = *(*s)++; 686 c = *(*s); /* yes, fetch z */
687 if (c)
688 (*s)++; /* advance unless z = NUL */
689 }
697 return c; 690 return c;
698} 691}
699 692
@@ -705,8 +698,7 @@ static ALWAYS_INLINE int isalnum_(int c)
705static double my_strtod(char **pp) 698static double my_strtod(char **pp)
706{ 699{
707 char *cp = *pp; 700 char *cp = *pp;
708#if ENABLE_DESKTOP 701 if (ENABLE_DESKTOP && cp[0] == '0') {
709 if (cp[0] == '0') {
710 /* Might be hex or octal integer: 0x123abc or 07777 */ 702 /* Might be hex or octal integer: 0x123abc or 07777 */
711 char c = (cp[1] | 0x20); 703 char c = (cp[1] | 0x20);
712 if (c == 'x' || isdigit(cp[1])) { 704 if (c == 'x' || isdigit(cp[1])) {
@@ -723,7 +715,6 @@ static double my_strtod(char **pp)
723 */ 715 */
724 } 716 }
725 } 717 }
726#endif
727 return strtod(cp, pp); 718 return strtod(cp, pp);
728} 719}
729 720
@@ -1015,9 +1006,10 @@ static uint32_t next_token(uint32_t expected)
1015 /* it's a string */ 1006 /* it's a string */
1016 t_string = s = ++p; 1007 t_string = s = ++p;
1017 while (*p != '\"') { 1008 while (*p != '\"') {
1018 char *pp = p; 1009 char *pp;
1019 if (*p == '\0' || *p == '\n') 1010 if (*p == '\0' || *p == '\n')
1020 syntax_error(EMSG_UNEXP_EOS); 1011 syntax_error(EMSG_UNEXP_EOS);
1012 pp = p;
1021 *s++ = nextchar(&pp); 1013 *s++ = nextchar(&pp);
1022 p = pp; 1014 p = pp;
1023 } 1015 }
@@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v)
1836 int fd, so, eo, r, rp; 1828 int fd, so, eo, r, rp;
1837 char c, *m, *s; 1829 char c, *m, *s;
1838 1830
1831 debug_printf_eval("entered %s()\n", __func__);
1832
1839 /* we're using our own buffer since we need access to accumulating 1833 /* we're using our own buffer since we need access to accumulating
1840 * characters 1834 * characters
1841 */ 1835 */
@@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v)
1922 rsm->pos = p - eo; 1916 rsm->pos = p - eo;
1923 rsm->size = size; 1917 rsm->size = size;
1924 1918
1919 debug_printf_eval("returning from %s(): %d\n", __func__, r);
1920
1925 return r; 1921 return r;
1926} 1922}
1927 1923
@@ -2168,11 +2164,10 @@ static NOINLINE var *exec_builtin(node *op, var *res)
2168 switch (info) { 2164 switch (info) {
2169 2165
2170 case B_a2: 2166 case B_a2:
2171#if ENABLE_FEATURE_AWK_LIBM 2167 if (ENABLE_FEATURE_AWK_LIBM)
2172 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); 2168 setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1])));
2173#else 2169 else
2174 syntax_error(EMSG_NO_MATH); 2170 syntax_error(EMSG_NO_MATH);
2175#endif
2176 break; 2171 break;
2177 2172
2178 case B_sp: { 2173 case B_sp: {
@@ -2347,6 +2342,8 @@ static var *evaluate(node *op, var *res)
2347 if (!op) 2342 if (!op)
2348 return setvar_s(res, NULL); 2343 return setvar_s(res, NULL);
2349 2344
2345 debug_printf_eval("entered %s()\n", __func__);
2346
2350 v1 = nvalloc(2); 2347 v1 = nvalloc(2);
2351 2348
2352 while (op) { 2349 while (op) {
@@ -2367,7 +2364,7 @@ static var *evaluate(node *op, var *res)
2367 opn = (opinfo & OPNMASK); 2364 opn = (opinfo & OPNMASK);
2368 g_lineno = op->lineno; 2365 g_lineno = op->lineno;
2369 op1 = op->l.n; 2366 op1 = op->l.n;
2370 debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK)); 2367 debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn);
2371 2368
2372 /* execute inevitable things */ 2369 /* execute inevitable things */
2373 if (opinfo & OF_RES1) 2370 if (opinfo & OF_RES1)
@@ -2387,6 +2384,7 @@ static var *evaluate(node *op, var *res)
2387 debug_printf_eval("L_d:%f\n", L_d); 2384 debug_printf_eval("L_d:%f\n", L_d);
2388 } 2385 }
2389 2386
2387 debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK));
2390 switch (XC(opinfo & OPCLSMASK)) { 2388 switch (XC(opinfo & OPCLSMASK)) {
2391 2389
2392 /* -- iterative node type -- */ 2390 /* -- iterative node type -- */
@@ -2642,8 +2640,6 @@ static var *evaluate(node *op, var *res)
2642 2640
2643 /* simple builtins */ 2641 /* simple builtins */
2644 case XC( OC_FBLTIN ): { 2642 case XC( OC_FBLTIN ): {
2645 int i;
2646 rstream *rsm;
2647 double R_d = R_d; /* for compiler */ 2643 double R_d = R_d; /* for compiler */
2648 2644
2649 switch (opn) { 2645 switch (opn) {
@@ -2654,35 +2650,40 @@ static var *evaluate(node *op, var *res)
2654 case F_rn: 2650 case F_rn:
2655 R_d = (double)rand() / (double)RAND_MAX; 2651 R_d = (double)rand() / (double)RAND_MAX;
2656 break; 2652 break;
2657#if ENABLE_FEATURE_AWK_LIBM 2653
2658 case F_co: 2654 case F_co:
2659 R_d = cos(L_d); 2655 if (ENABLE_FEATURE_AWK_LIBM) {
2660 break; 2656 R_d = cos(L_d);
2657 break;
2658 }
2661 2659
2662 case F_ex: 2660 case F_ex:
2663 R_d = exp(L_d); 2661 if (ENABLE_FEATURE_AWK_LIBM) {
2664 break; 2662 R_d = exp(L_d);
2663 break;
2664 }
2665 2665
2666 case F_lg: 2666 case F_lg:
2667 R_d = log(L_d); 2667 if (ENABLE_FEATURE_AWK_LIBM) {
2668 break; 2668 R_d = log(L_d);
2669 break;
2670 }
2669 2671
2670 case F_si: 2672 case F_si:
2671 R_d = sin(L_d); 2673 if (ENABLE_FEATURE_AWK_LIBM) {
2672 break; 2674 R_d = sin(L_d);
2675 break;
2676 }
2673 2677
2674 case F_sq: 2678 case F_sq:
2675 R_d = sqrt(L_d); 2679 if (ENABLE_FEATURE_AWK_LIBM) {
2676 break; 2680 R_d = sqrt(L_d);
2677#else 2681 break;
2678 case F_co: 2682 }
2679 case F_ex: 2683
2680 case F_lg:
2681 case F_si:
2682 case F_sq:
2683 syntax_error(EMSG_NO_MATH); 2684 syntax_error(EMSG_NO_MATH);
2684 break; 2685 break;
2685#endif 2686
2686 case F_sr: 2687 case F_sr:
2687 R_d = (double)seed; 2688 R_d = (double)seed;
2688 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); 2689 seed = op1 ? (unsigned)L_d : (unsigned)time(NULL);
@@ -2709,26 +2710,37 @@ static var *evaluate(node *op, var *res)
2709 if (!op1) { 2710 if (!op1) {
2710 fflush(stdout); 2711 fflush(stdout);
2711 } else if (L.s && *L.s) { 2712 } else if (L.s && *L.s) {
2712 rsm = newfile(L.s); 2713 rstream *rsm = newfile(L.s);
2713 fflush(rsm->F); 2714 fflush(rsm->F);
2714 } else { 2715 } else {
2715 fflush_all(); 2716 fflush_all();
2716 } 2717 }
2717 break; 2718 break;
2718 2719
2719 case F_cl: 2720 case F_cl: {
2720 i = 0; 2721 rstream *rsm;
2722 int err = 0;
2721 rsm = (rstream *)hash_search(fdhash, L.s); 2723 rsm = (rstream *)hash_search(fdhash, L.s);
2724 debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm);
2722 if (rsm) { 2725 if (rsm) {
2723 i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); 2726 debug_printf_eval("OC_FBLTIN F_cl "
2727 "rsm->is_pipe:%d, ->F:%p\n",
2728 rsm->is_pipe, rsm->F);
2729 /* Can be NULL if open failed. Example:
2730 * getline line <"doesnt_exist";
2731 * close("doesnt_exist"); <--- here rsm->F is NULL
2732 */
2733 if (rsm->F)
2734 err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F);
2724 free(rsm->buffer); 2735 free(rsm->buffer);
2725 hash_remove(fdhash, L.s); 2736 hash_remove(fdhash, L.s);
2726 } 2737 }
2727 if (i != 0) 2738 if (err)
2728 setvar_i(intvar[ERRNO], errno); 2739 setvar_i(intvar[ERRNO], errno);
2729 R_d = (double)i; 2740 R_d = (double)err;
2730 break; 2741 break;
2731 } 2742 }
2743 } /* switch */
2732 setvar_i(res, R_d); 2744 setvar_i(res, R_d);
2733 break; 2745 break;
2734 } 2746 }
@@ -2822,11 +2834,10 @@ static var *evaluate(node *op, var *res)
2822 L_d /= R_d; 2834 L_d /= R_d;
2823 break; 2835 break;
2824 case '&': 2836 case '&':
2825#if ENABLE_FEATURE_AWK_LIBM 2837 if (ENABLE_FEATURE_AWK_LIBM)
2826 L_d = pow(L_d, R_d); 2838 L_d = pow(L_d, R_d);
2827#else 2839 else
2828 syntax_error(EMSG_NO_MATH); 2840 syntax_error(EMSG_NO_MATH);
2829#endif
2830 break; 2841 break;
2831 case '%': 2842 case '%':
2832 if (R_d == 0) 2843 if (R_d == 0)
@@ -2877,6 +2888,7 @@ static var *evaluate(node *op, var *res)
2877 } /* while (op) */ 2888 } /* while (op) */
2878 2889
2879 nvfree(v1); 2890 nvfree(v1);
2891 debug_printf_eval("returning from %s(): %p\n", __func__, res);
2880 return res; 2892 return res;
2881#undef fnargs 2893#undef fnargs
2882#undef seed 2894#undef seed
@@ -2917,21 +2929,21 @@ static int awk_exit(int r)
2917 * otherwise return 0 */ 2929 * otherwise return 0 */
2918static int is_assignment(const char *expr) 2930static int is_assignment(const char *expr)
2919{ 2931{
2920 char *exprc, *s, *s0, *s1; 2932 char *exprc, *val, *s, *s1;
2921 2933
2922 exprc = xstrdup(expr); 2934 if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) {
2923 if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) {
2924 free(exprc);
2925 return FALSE; 2935 return FALSE;
2926 } 2936 }
2927 2937
2928 *s++ = '\0'; 2938 exprc = xstrdup(expr);
2929 s0 = s1 = s; 2939 val = exprc + (val - expr);
2930 while (*s) 2940 *val++ = '\0';
2931 *s1++ = nextchar(&s); 2941
2942 s = s1 = val;
2943 while ((*s1 = nextchar(&s)) != '\0')
2944 s1++;
2932 2945
2933 *s1 = '\0'; 2946 setvar_u(newvar(exprc), val);
2934 setvar_u(newvar(exprc), s0);
2935 free(exprc); 2947 free(exprc);
2936 return TRUE; 2948 return TRUE;
2937} 2949}