| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: var.c,v 1.594 2020/10/30 07:19:30 rillig Exp $ */ | | 1 | /* $NetBSD: var.c,v 1.595 2020/10/30 07:30:29 rillig Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1988, 1989, 1990, 1993 | | 4 | * Copyright (c) 1988, 1989, 1990, 1993 |
5 | * The Regents of the University of California. All rights reserved. | | 5 | * The Regents of the University of California. All rights reserved. |
6 | * | | 6 | * |
7 | * This code is derived from software contributed to Berkeley by | | 7 | * This code is derived from software contributed to Berkeley by |
8 | * Adam de Boor. | | 8 | * Adam de Boor. |
9 | * | | 9 | * |
10 | * Redistribution and use in source and binary forms, with or without | | 10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions | | 11 | * modification, are permitted provided that the following conditions |
12 | * are met: | | 12 | * are met: |
13 | * 1. Redistributions of source code must retain the above copyright | | 13 | * 1. Redistributions of source code must retain the above copyright |
14 | * notice, this list of conditions and the following disclaimer. | | 14 | * notice, this list of conditions and the following disclaimer. |
| @@ -119,27 +119,27 @@ | | | @@ -119,27 +119,27 @@ |
119 | #include <sys/types.h> | | 119 | #include <sys/types.h> |
120 | #include <regex.h> | | 120 | #include <regex.h> |
121 | #endif | | 121 | #endif |
122 | #include <inttypes.h> | | 122 | #include <inttypes.h> |
123 | #include <limits.h> | | 123 | #include <limits.h> |
124 | #include <time.h> | | 124 | #include <time.h> |
125 | | | 125 | |
126 | #include "make.h" | | 126 | #include "make.h" |
127 | #include "dir.h" | | 127 | #include "dir.h" |
128 | #include "job.h" | | 128 | #include "job.h" |
129 | #include "metachar.h" | | 129 | #include "metachar.h" |
130 | | | 130 | |
131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ | | 131 | /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ |
132 | MAKE_RCSID("$NetBSD: var.c,v 1.594 2020/10/30 07:19:30 rillig Exp $"); | | 132 | MAKE_RCSID("$NetBSD: var.c,v 1.595 2020/10/30 07:30:29 rillig Exp $"); |
133 | | | 133 | |
134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) | | 134 | #define VAR_DEBUG1(fmt, arg1) DEBUG1(VAR, fmt, arg1) |
135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) | | 135 | #define VAR_DEBUG2(fmt, arg1, arg2) DEBUG2(VAR, fmt, arg1, arg2) |
136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) | | 136 | #define VAR_DEBUG3(fmt, arg1, arg2, arg3) DEBUG3(VAR, fmt, arg1, arg2, arg3) |
137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) | | 137 | #define VAR_DEBUG4(fmt, arg1, arg2, arg3, arg4) DEBUG4(VAR, fmt, arg1, arg2, arg3, arg4) |
138 | | | 138 | |
139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, | | 139 | ENUM_FLAGS_RTTI_3(VarEvalFlags, |
140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); | | 140 | VARE_UNDEFERR, VARE_WANTRES, VARE_ASSIGN); |
141 | | | 141 | |
142 | /* | | 142 | /* |
143 | * This lets us tell if we have replaced the original environ | | 143 | * This lets us tell if we have replaced the original environ |
144 | * (which we cannot free). | | 144 | * (which we cannot free). |
145 | */ | | 145 | */ |
| @@ -182,27 +182,27 @@ static Boolean save_dollars = TRUE; | | | @@ -182,27 +182,27 @@ static Boolean save_dollars = TRUE; |
182 | * 3) the command-line context. All variables set on the command line | | 182 | * 3) the command-line context. All variables set on the command line |
183 | * are placed in this context. | | 183 | * are placed in this context. |
184 | * 4) the local context. Each target has associated with it a context | | 184 | * 4) the local context. Each target has associated with it a context |
185 | * list. On this list are located the structures describing such | | 185 | * list. On this list are located the structures describing such |
186 | * local variables as $(@) and $(*) | | 186 | * local variables as $(@) and $(*) |
187 | * The four contexts are searched in the reverse order from which they are | | 187 | * The four contexts are searched in the reverse order from which they are |
188 | * listed (but see opts.checkEnvFirst). | | 188 | * listed (but see opts.checkEnvFirst). |
189 | */ | | 189 | */ |
190 | GNode *VAR_INTERNAL; /* variables from make itself */ | | 190 | GNode *VAR_INTERNAL; /* variables from make itself */ |
191 | GNode *VAR_GLOBAL; /* variables from the makefile */ | | 191 | GNode *VAR_GLOBAL; /* variables from the makefile */ |
192 | GNode *VAR_CMDLINE; /* variables defined on the command-line */ | | 192 | GNode *VAR_CMDLINE; /* variables defined on the command-line */ |
193 | | | 193 | |
194 | typedef enum VarFindFlags { | | 194 | typedef enum VarFindFlags { |
195 | FIND_CMD = 0x01, /* look in VAR_CMDLINE when searching */ | | 195 | FIND_CMDLINE = 0x01, /* look in VAR_CMDLINE when searching */ |
196 | FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ | | 196 | FIND_GLOBAL = 0x02, /* look in VAR_GLOBAL as well */ |
197 | FIND_ENV = 0x04 /* look in the environment also */ | | 197 | FIND_ENV = 0x04 /* look in the environment also */ |
198 | } VarFindFlags; | | 198 | } VarFindFlags; |
199 | | | 199 | |
200 | typedef enum VarFlags { | | 200 | typedef enum VarFlags { |
201 | /* The variable's value is currently being used by Var_Parse or Var_Subst. | | 201 | /* The variable's value is currently being used by Var_Parse or Var_Subst. |
202 | * This marker is used to avoid endless recursion. */ | | 202 | * This marker is used to avoid endless recursion. */ |
203 | VAR_IN_USE = 0x01, | | 203 | VAR_IN_USE = 0x01, |
204 | /* The variable comes from the environment. | | 204 | /* The variable comes from the environment. |
205 | * These variables are not registered in any GNode, therefore they must | | 205 | * These variables are not registered in any GNode, therefore they must |
206 | * be freed as soon as they are not used anymore. */ | | 206 | * be freed as soon as they are not used anymore. */ |
207 | VAR_FROM_ENV = 0x02, | | 207 | VAR_FROM_ENV = 0x02, |
208 | /* The variable is exported to the environment, to be used by child | | 208 | /* The variable is exported to the environment, to be used by child |
| @@ -345,29 +345,27 @@ GNode_FindVar(GNode *ctxt, const char *v | | | @@ -345,29 +345,27 @@ GNode_FindVar(GNode *ctxt, const char *v |
345 | { | | 345 | { |
346 | return HashTable_FindValueHash(&ctxt->context, varname, hash); | | 346 | return HashTable_FindValueHash(&ctxt->context, varname, hash); |
347 | } | | 347 | } |
348 | | | 348 | |
349 | /*- | | 349 | /*- |
350 | *----------------------------------------------------------------------- | | 350 | *----------------------------------------------------------------------- |
351 | * VarFind -- | | 351 | * VarFind -- |
352 | * Find the given variable in the given context and any other contexts | | 352 | * Find the given variable in the given context and any other contexts |
353 | * indicated. | | 353 | * indicated. |
354 | * | | 354 | * |
355 | * Input: | | 355 | * Input: |
356 | * name name to find | | 356 | * name name to find |
357 | * ctxt context in which to find it | | 357 | * ctxt context in which to find it |
358 | * flags FIND_GLOBAL look in VAR_GLOBAL as well | | 358 | * flags to look on other contexts as well |
359 | * FIND_CMD look in VAR_CMDLINE as well | | | |
360 | * FIND_ENV look in the environment as well | | | |
361 | * | | 359 | * |
362 | * Results: | | 360 | * Results: |
363 | * A pointer to the structure describing the desired variable or | | 361 | * A pointer to the structure describing the desired variable or |
364 | * NULL if the variable does not exist. | | 362 | * NULL if the variable does not exist. |
365 | *----------------------------------------------------------------------- | | 363 | *----------------------------------------------------------------------- |
366 | */ | | 364 | */ |
367 | static Var * | | 365 | static Var * |
368 | VarFind(const char *name, GNode *ctxt, VarFindFlags flags) | | 366 | VarFind(const char *name, GNode *ctxt, VarFindFlags flags) |
369 | { | | 367 | { |
370 | Var *var; | | 368 | Var *var; |
371 | unsigned int nameHash; | | 369 | unsigned int nameHash; |
372 | | | 370 | |
373 | /* | | 371 | /* |
| @@ -376,27 +374,27 @@ VarFind(const char *name, GNode *ctxt, V | | | @@ -376,27 +374,27 @@ VarFind(const char *name, GNode *ctxt, V |
376 | * and substitute the short version in for 'name' if it matches one of | | 374 | * and substitute the short version in for 'name' if it matches one of |
377 | * them. | | 375 | * them. |
378 | */ | | 376 | */ |
379 | name = CanonicalVarname(name); | | 377 | name = CanonicalVarname(name); |
380 | nameHash = Hash_Hash(name); | | 378 | nameHash = Hash_Hash(name); |
381 | | | 379 | |
382 | /* | | 380 | /* |
383 | * First look for the variable in the given context. If it's not there, | | 381 | * First look for the variable in the given context. If it's not there, |
384 | * look for it in VAR_CMDLINE, VAR_GLOBAL and the environment, in that order, | | 382 | * look for it in VAR_CMDLINE, VAR_GLOBAL and the environment, in that order, |
385 | * depending on the FIND_* flags in 'flags' | | 383 | * depending on the FIND_* flags in 'flags' |
386 | */ | | 384 | */ |
387 | var = GNode_FindVar(ctxt, name, nameHash); | | 385 | var = GNode_FindVar(ctxt, name, nameHash); |
388 | | | 386 | |
389 | if (var == NULL && (flags & FIND_CMD) && ctxt != VAR_CMDLINE) | | 387 | if (var == NULL && (flags & FIND_CMDLINE) && ctxt != VAR_CMDLINE) |
390 | var = GNode_FindVar(VAR_CMDLINE, name, nameHash); | | 388 | var = GNode_FindVar(VAR_CMDLINE, name, nameHash); |
391 | | | 389 | |
392 | if (!opts.checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && | | 390 | if (!opts.checkEnvFirst && var == NULL && (flags & FIND_GLOBAL) && |
393 | ctxt != VAR_GLOBAL) | | 391 | ctxt != VAR_GLOBAL) |
394 | { | | 392 | { |
395 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); | | 393 | var = GNode_FindVar(VAR_GLOBAL, name, nameHash); |
396 | if (var == NULL && ctxt != VAR_INTERNAL) { | | 394 | if (var == NULL && ctxt != VAR_INTERNAL) { |
397 | /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ | | 395 | /* VAR_INTERNAL is subordinate to VAR_GLOBAL */ |
398 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); | | 396 | var = GNode_FindVar(VAR_INTERNAL, name, nameHash); |
399 | } | | 397 | } |
400 | } | | 398 | } |
401 | | | 399 | |
402 | if (var == NULL && (flags & FIND_ENV)) { | | 400 | if (var == NULL && (flags & FIND_ENV)) { |
| @@ -932,27 +930,27 @@ Var_Append(const char *name, const char | | | @@ -932,27 +930,27 @@ Var_Append(const char *name, const char |
932 | const char *unexpanded_name = name; | | 930 | const char *unexpanded_name = name; |
933 | (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); | | 931 | (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); |
934 | /* TODO: handle errors */ | | 932 | /* TODO: handle errors */ |
935 | name = name_freeIt; | | 933 | name = name_freeIt; |
936 | if (name[0] == '\0') { | | 934 | if (name[0] == '\0') { |
937 | VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " | | 935 | VAR_DEBUG2("Var_Append(\"%s\", \"%s\", ...) " |
938 | "name expands to empty string - ignored\n", | | 936 | "name expands to empty string - ignored\n", |
939 | unexpanded_name, val); | | 937 | unexpanded_name, val); |
940 | free(name_freeIt); | | 938 | free(name_freeIt); |
941 | return; | | 939 | return; |
942 | } | | 940 | } |
943 | } | | 941 | } |
944 | | | 942 | |
945 | v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMD | FIND_ENV) : 0); | | 943 | v = VarFind(name, ctxt, ctxt == VAR_GLOBAL ? (FIND_CMDLINE | FIND_ENV) : 0); |
946 | | | 944 | |
947 | if (v == NULL) { | | 945 | if (v == NULL) { |
948 | Var_Set(name, val, ctxt); | | 946 | Var_Set(name, val, ctxt); |
949 | } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { | | 947 | } else if (ctxt == VAR_CMDLINE || !(v->flags & VAR_FROM_CMD)) { |
950 | Buf_AddByte(&v->val, ' '); | | 948 | Buf_AddByte(&v->val, ' '); |
951 | Buf_AddStr(&v->val, val); | | 949 | Buf_AddStr(&v->val, val); |
952 | | | 950 | |
953 | VAR_DEBUG3("%s:%s = %s\n", | | 951 | VAR_DEBUG3("%s:%s = %s\n", |
954 | ctxt->name, name, Buf_GetAll(&v->val, NULL)); | | 952 | ctxt->name, name, Buf_GetAll(&v->val, NULL)); |
955 | | | 953 | |
956 | if (v->flags & VAR_FROM_ENV) { | | 954 | if (v->flags & VAR_FROM_ENV) { |
957 | HashEntry *h; | | 955 | HashEntry *h; |
958 | | | 956 | |
| @@ -979,27 +977,27 @@ Var_Append(const char *name, const char | | | @@ -979,27 +977,27 @@ Var_Append(const char *name, const char |
979 | */ | | 977 | */ |
980 | Boolean | | 978 | Boolean |
981 | Var_Exists(const char *name, GNode *ctxt) | | 979 | Var_Exists(const char *name, GNode *ctxt) |
982 | { | | 980 | { |
983 | char *name_freeIt = NULL; | | 981 | char *name_freeIt = NULL; |
984 | Var *v; | | 982 | Var *v; |
985 | | | 983 | |
986 | if (strchr(name, '$') != NULL) { | | 984 | if (strchr(name, '$') != NULL) { |
987 | (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); | | 985 | (void)Var_Subst(name, ctxt, VARE_WANTRES, &name_freeIt); |
988 | /* TODO: handle errors */ | | 986 | /* TODO: handle errors */ |
989 | name = name_freeIt; | | 987 | name = name_freeIt; |
990 | } | | 988 | } |
991 | | | 989 | |
992 | v = VarFind(name, ctxt, FIND_CMD | FIND_GLOBAL | FIND_ENV); | | 990 | v = VarFind(name, ctxt, FIND_CMDLINE | FIND_GLOBAL | FIND_ENV); |
993 | free(name_freeIt); | | 991 | free(name_freeIt); |
994 | if (v == NULL) | | 992 | if (v == NULL) |
995 | return FALSE; | | 993 | return FALSE; |
996 | | | 994 | |
997 | (void)VarFreeEnv(v, TRUE); | | 995 | (void)VarFreeEnv(v, TRUE); |
998 | return TRUE; | | 996 | return TRUE; |
999 | } | | 997 | } |
1000 | | | 998 | |
1001 | /*- | | 999 | /*- |
1002 | *----------------------------------------------------------------------- | | 1000 | *----------------------------------------------------------------------- |
1003 | * Var_Value -- | | 1001 | * Var_Value -- |
1004 | * Return the unexpanded value of the given variable in the given | | 1002 | * Return the unexpanded value of the given variable in the given |
1005 | * context, or the usual contexts. | | 1003 | * context, or the usual contexts. |
| @@ -1007,27 +1005,27 @@ Var_Exists(const char *name, GNode *ctxt | | | @@ -1007,27 +1005,27 @@ Var_Exists(const char *name, GNode *ctxt |
1007 | * Input: | | 1005 | * Input: |
1008 | * name name to find | | 1006 | * name name to find |
1009 | * ctxt context in which to search for it | | 1007 | * ctxt context in which to search for it |
1010 | * | | 1008 | * |
1011 | * Results: | | 1009 | * Results: |
1012 | * The value if the variable exists, NULL if it doesn't. | | 1010 | * The value if the variable exists, NULL if it doesn't. |
1013 | * If the returned value is not NULL, the caller must free *freeIt | | 1011 | * If the returned value is not NULL, the caller must free *freeIt |
1014 | * as soon as the returned value is no longer needed. | | 1012 | * as soon as the returned value is no longer needed. |
1015 | *----------------------------------------------------------------------- | | 1013 | *----------------------------------------------------------------------- |
1016 | */ | | 1014 | */ |
1017 | const char * | | 1015 | const char * |
1018 | Var_Value(const char *name, GNode *ctxt, char **freeIt) | | 1016 | Var_Value(const char *name, GNode *ctxt, char **freeIt) |
1019 | { | | 1017 | { |
1020 | Var *v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); | | 1018 | Var *v = VarFind(name, ctxt, FIND_CMDLINE | FIND_GLOBAL | FIND_ENV); |
1021 | char *p; | | 1019 | char *p; |
1022 | | | 1020 | |
1023 | *freeIt = NULL; | | 1021 | *freeIt = NULL; |
1024 | if (v == NULL) | | 1022 | if (v == NULL) |
1025 | return NULL; | | 1023 | return NULL; |
1026 | | | 1024 | |
1027 | p = Buf_GetAll(&v->val, NULL); | | 1025 | p = Buf_GetAll(&v->val, NULL); |
1028 | if (VarFreeEnv(v, FALSE)) | | 1026 | if (VarFreeEnv(v, FALSE)) |
1029 | *freeIt = p; | | 1027 | *freeIt = p; |
1030 | return p; | | 1028 | return p; |
1031 | } | | 1029 | } |
1032 | | | 1030 | |
1033 | | | 1031 | |
| @@ -3547,27 +3545,27 @@ Var_Parse(const char **pp, GNode *ctxt, | | | @@ -3547,27 +3545,27 @@ Var_Parse(const char **pp, GNode *ctxt, |
3547 | * If it's not bounded by braces of some sort, life is much simpler. | | 3545 | * If it's not bounded by braces of some sort, life is much simpler. |
3548 | * We just need to check for the first character and return the | | 3546 | * We just need to check for the first character and return the |
3549 | * value if it exists. | | 3547 | * value if it exists. |
3550 | */ | | 3548 | */ |
3551 | | | 3549 | |
3552 | if (!ValidShortVarname(startc, start)) { | | 3550 | if (!ValidShortVarname(startc, start)) { |
3553 | (*pp)++; | | 3551 | (*pp)++; |
3554 | *out_val = var_Error; | | 3552 | *out_val = var_Error; |
3555 | return VPR_PARSE_MSG; | | 3553 | return VPR_PARSE_MSG; |
3556 | } | | 3554 | } |
3557 | | | 3555 | |
3558 | name[0] = startc; | | 3556 | name[0] = startc; |
3559 | name[1] = '\0'; | | 3557 | name[1] = '\0'; |
3560 | v = VarFind(name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); | | 3558 | v = VarFind(name, ctxt, FIND_CMDLINE | FIND_GLOBAL | FIND_ENV); |
3561 | if (v == NULL) { | | 3559 | if (v == NULL) { |
3562 | *pp += 2; | | 3560 | *pp += 2; |
3563 | | | 3561 | |
3564 | *out_val = UndefinedShortVarValue(startc, ctxt, eflags); | | 3562 | *out_val = UndefinedShortVarValue(startc, ctxt, eflags); |
3565 | if (DEBUG(LINT) && *out_val == var_Error) { | | 3563 | if (DEBUG(LINT) && *out_val == var_Error) { |
3566 | Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); | | 3564 | Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); |
3567 | return VPR_UNDEF_MSG; | | 3565 | return VPR_UNDEF_MSG; |
3568 | } | | 3566 | } |
3569 | return eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; | | 3567 | return eflags & VARE_UNDEFERR ? VPR_UNDEF_SILENT : VPR_OK; |
3570 | } else { | | 3568 | } else { |
3571 | haveModifier = FALSE; | | 3569 | haveModifier = FALSE; |
3572 | p = start + 1; | | 3570 | p = start + 1; |
3573 | } | | 3571 | } |
| @@ -3582,27 +3580,27 @@ Var_Parse(const char **pp, GNode *ctxt, | | | @@ -3582,27 +3580,27 @@ Var_Parse(const char **pp, GNode *ctxt, |
3582 | | | 3580 | |
3583 | if (*p == ':') { | | 3581 | if (*p == ':') { |
3584 | haveModifier = TRUE; | | 3582 | haveModifier = TRUE; |
3585 | } else if (*p == endc) { | | 3583 | } else if (*p == endc) { |
3586 | haveModifier = FALSE; | | 3584 | haveModifier = FALSE; |
3587 | } else { | | 3585 | } else { |
3588 | Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); | | 3586 | Parse_Error(PARSE_FATAL, "Unclosed variable \"%s\"", varname); |
3589 | *pp = p; | | 3587 | *pp = p; |
3590 | free(varname); | | 3588 | free(varname); |
3591 | *out_val = var_Error; | | 3589 | *out_val = var_Error; |
3592 | return VPR_PARSE_MSG; | | 3590 | return VPR_PARSE_MSG; |
3593 | } | | 3591 | } |
3594 | | | 3592 | |
3595 | v = VarFind(varname, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); | | 3593 | v = VarFind(varname, ctxt, FIND_CMDLINE | FIND_GLOBAL | FIND_ENV); |
3596 | | | 3594 | |
3597 | /* At this point, p points just after the variable name, | | 3595 | /* At this point, p points just after the variable name, |
3598 | * either at ':' or at endc. */ | | 3596 | * either at ':' or at endc. */ |
3599 | | | 3597 | |
3600 | /* | | 3598 | /* |
3601 | * Check also for bogus D and F forms of local variables since we're | | 3599 | * Check also for bogus D and F forms of local variables since we're |
3602 | * in a local context and the name is the right length. | | 3600 | * in a local context and the name is the right length. |
3603 | */ | | 3601 | */ |
3604 | if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && | | 3602 | if (v == NULL && ctxt != VAR_CMDLINE && ctxt != VAR_GLOBAL && |
3605 | namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && | | 3603 | namelen == 2 && (varname[1] == 'F' || varname[1] == 'D') && |
3606 | strchr("@%?*!<>", varname[0]) != NULL) | | 3604 | strchr("@%?*!<>", varname[0]) != NULL) |
3607 | { | | 3605 | { |
3608 | /* | | 3606 | /* |