From fb28c3c8c707a6c289553a7480922134bfb0e110 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 6 Apr 2016 13:03:44 +0200 Subject: [PATCH 1/4] Add safe ctype.h wrappers From the C99 spec: The header declares several functions useful for classifying and mapping characters. In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined. The behavior of these functions is affected by the current locale. Implementations using a superset of ASCII are assumed. --- compiler/src/CFCUtil.c | 49 ++++++++++++++++++++++++++++++++++++++++++ compiler/src/CFCUtil.h | 27 +++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c index f505cac8..83c30e22 100644 --- a/compiler/src/CFCUtil.c +++ b/compiler/src/CFCUtil.c @@ -308,6 +308,55 @@ CFCUtil_wrapped_free(void *ptr) { free(ptr); } +// Avoid -Wtype-limits warning. +#if CHAR_MAX <= 127 + #define IS_ASCII(c) ((c) >= 0) +#else + #define IS_ASCII(c) ((c) >= 0 && (c) <= 127) +#endif + +int +CFCUtil_isalnum(char c) { + return IS_ASCII(c) && isalnum(c); +} + +int +CFCUtil_isalpha(char c) { + return IS_ASCII(c) && isalpha(c); +} + +int +CFCUtil_isdigit(char c) { + return IS_ASCII(c) && isdigit(c); +} + +int +CFCUtil_islower(char c) { + return IS_ASCII(c) && islower(c); +} + +int +CFCUtil_isspace(char c) { + return IS_ASCII(c) && isspace(c); +} + +int +CFCUtil_isupper(char c) { + return IS_ASCII(c) && isupper(c); +} + +char +CFCUtil_tolower(char c) { + if (!IS_ASCII(c)) { return c; } + return (char)tolower(c); +} + +char +CFCUtil_toupper(char c) { + if (!IS_ASCII(c)) { return c; } + return (char)toupper(c); +} + int CFCUtil_current(const char *orig, const char *dest) { // If the destination file doesn't exist, we're not current. diff --git a/compiler/src/CFCUtil.h b/compiler/src/CFCUtil.h index 73286efe..ea66400a 100644 --- a/compiler/src/CFCUtil.h +++ b/compiler/src/CFCUtil.h @@ -153,6 +153,33 @@ CFCUtil_wrapped_free(void *ptr); #define FREEMEM(_ptr) \ CFCUtil_wrapped_free(_ptr) +/** Safe wrappers for ctype.h functions. + */ + +int +CFCUtil_isalnum(char c); + +int +CFCUtil_isalpha(char c); + +int +CFCUtil_isdigit(char c); + +int +CFCUtil_islower(char c); + +int +CFCUtil_isspace(char c); + +int +CFCUtil_isupper(char c); + +char +CFCUtil_tolower(char c); + +char +CFCUtil_toupper(char c); + /** Given two filepaths, return true if the second exists and has a * modification time which more recent than that of the first. */ From a6bfd289edd6dba8cd73aed9b655fd56ae52b20b Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 6 Apr 2016 13:24:36 +0200 Subject: [PATCH 2/4] Switch to safe ctype.h wrappers --- compiler/src/CFCCHtml.c | 1 - compiler/src/CFCCallable.c | 1 - compiler/src/CFCClass.c | 13 ++++++------- compiler/src/CFCDocuComment.c | 20 ++++++++++++-------- compiler/src/CFCFile.c | 5 ++--- compiler/src/CFCFileSpec.c | 1 - compiler/src/CFCFunction.c | 5 +++-- compiler/src/CFCGo.c | 1 - compiler/src/CFCGoFunc.c | 3 +-- compiler/src/CFCGoMethod.c | 1 - compiler/src/CFCGoTypeMap.c | 13 ++++++------- compiler/src/CFCHierarchy.c | 1 - compiler/src/CFCMethod.c | 7 +++---- compiler/src/CFCParcel.c | 11 +++++------ compiler/src/CFCPerl.c | 8 ++++---- compiler/src/CFCPerlClass.c | 2 +- compiler/src/CFCPerlMethod.c | 3 +-- compiler/src/CFCPerlPod.c | 13 ++++++------- compiler/src/CFCPyClass.c | 3 +-- compiler/src/CFCPyMethod.c | 5 ++--- compiler/src/CFCPython.c | 5 ++--- compiler/src/CFCRuby.c | 8 ++++---- compiler/src/CFCSymbol.c | 5 ++--- compiler/src/CFCType.c | 13 ++++++------- compiler/src/CFCUri.c | 5 ++--- compiler/src/CFCUtil.c | 4 ++-- compiler/src/CFCVersion.c | 5 ++--- 27 files changed, 73 insertions(+), 89 deletions(-) diff --git a/compiler/src/CFCCHtml.c b/compiler/src/CFCCHtml.c index a054cb88..222f5fda 100644 --- a/compiler/src/CFCCHtml.c +++ b/compiler/src/CFCCHtml.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include #include diff --git a/compiler/src/CFCCallable.c b/compiler/src/CFCCallable.c index ccb3931c..8071761e 100644 --- a/compiler/src/CFCCallable.c +++ b/compiler/src/CFCCallable.c @@ -15,7 +15,6 @@ */ #include -#include #ifndef true #define true 1 diff --git a/compiler/src/CFCClass.c b/compiler/src/CFCClass.c index 77e0158e..319b1ae7 100644 --- a/compiler/src/CFCClass.c +++ b/compiler/src/CFCClass.c @@ -16,7 +16,6 @@ #include #include -#include #ifndef true #define true 1 @@ -139,22 +138,22 @@ CFCClass_validate_class_name(const char *class_name) { for (;;substring++) { if (*substring == 0) { return false; } else if (*substring == ':') { return false; } - else if (islower(*substring)) { break; } + else if (CFCUtil_islower(*substring)) { break; } } // Must be UpperCamelCase, separated by "::". const char *ptr = class_name; - if (!isupper(*ptr)) { return false; } + if (!CFCUtil_isupper(*ptr)) { return false; } while (*ptr != 0) { if (*ptr == 0) { break; } else if (*ptr == ':') { ptr++; if (*ptr != ':') { return false; } ptr++; - if (!isupper(*ptr)) { return false; } + if (!CFCUtil_isupper(*ptr)) { return false; } ptr++; } - else if (!isalnum(*ptr)) { return false; } + else if (!CFCUtil_isalnum(*ptr)) { return false; } else { ptr++; } } @@ -178,7 +177,7 @@ S_validate_nickname(const char *nickname) { if (strlen(nickname)) { return true; } else { break; } } - else if (!isupper(*ptr)) { break; } + else if (!CFCUtil_isupper(*ptr)) { break; } } // Same as one component of a class name. @@ -274,7 +273,7 @@ CFCClass_do_create(CFCClass *self, struct CFCParcel *parcel, char *short_class_var = (char*)MALLOCATE(struct_sym_len + 1); size_t i; for (i = 0; i < struct_sym_len; i++) { - short_class_var[i] = (char)toupper(struct_sym[i]); + short_class_var[i] = CFCUtil_toupper(struct_sym[i]); } short_class_var[struct_sym_len] = '\0'; self->short_class_var = short_class_var; diff --git a/compiler/src/CFCDocuComment.c b/compiler/src/CFCDocuComment.c index 2bcc4951..26eb059b 100644 --- a/compiler/src/CFCDocuComment.c +++ b/compiler/src/CFCDocuComment.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include @@ -50,7 +49,7 @@ S_strip(char *comment) { // Capture text minus beginning "/**", ending "*/", and left border. size_t i = 3; size_t max = len - 2; - while ((isspace(comment[i]) || comment[i] == '*') && i < max) { + while ((CFCUtil_isspace(comment[i]) || comment[i] == '*') && i < max) { i++; } size_t j = 0; @@ -58,7 +57,10 @@ S_strip(char *comment) { while (comment[i] == '\n' && i < max) { scratch[j++] = comment[i]; i++; - while (isspace(comment[i]) && comment[i] != '\n' && i < max) { + while (CFCUtil_isspace(comment[i]) + && comment[i] != '\n' + && i < max + ) { i++; } if (comment[i] == '*') { i++; } @@ -104,7 +106,7 @@ CFCDocuComment_parse(const char *raw_text) { } while (ptr < limit) { if (*ptr == '.' - && ((ptr == limit - 1) || isspace(*(ptr + 1))) + && ((ptr == limit - 1) || CFCUtil_isspace(*(ptr + 1))) ) { ptr++; size_t brief_len = (size_t)(ptr - text); @@ -130,19 +132,21 @@ CFCDocuComment_parse(const char *raw_text) { while (candidate) { // Extract param name. char *ptr = candidate + sizeof("@param") - 1; - if (!isspace(*ptr) || ptr > text_limit) { + if (!CFCUtil_isspace(*ptr) || ptr > text_limit) { CFCUtil_die("Malformed @param directive in '%s'", raw_text); } - while (isspace(*ptr) && ptr < text_limit) { ptr++; } + while (CFCUtil_isspace(*ptr) && ptr < text_limit) { ptr++; } char *param_name = ptr; - while ((isalnum(*ptr) || *ptr == '_') && ptr < text_limit) { ptr++; } + while ((CFCUtil_isalnum(*ptr) || *ptr == '_') && ptr < text_limit) { + ptr++; + } size_t param_name_len = (size_t)(ptr - param_name); if (!param_name_len) { CFCUtil_die("Malformed @param directive in '%s'", raw_text); } // Extract param description. - while (isspace(*ptr) && ptr < text_limit) { ptr++; } + while (CFCUtil_isspace(*ptr) && ptr < text_limit) { ptr++; } char *param_doc = ptr; while (ptr < text_limit && (*ptr != '@' diff --git a/compiler/src/CFCFile.c b/compiler/src/CFCFile.c index 1e03a3e7..d8620f24 100644 --- a/compiler/src/CFCFile.c +++ b/compiler/src/CFCFile.c @@ -18,7 +18,6 @@ #include #include -#include #ifndef true #define true 1 @@ -80,8 +79,8 @@ CFCFile_init(CFCFile *self, CFCParcel *parcel, CFCFileSpec *spec) { if (c == CHY_DIR_SEP_CHAR) { self->guard_name[j++] = '_'; } - else if (isalnum(c)) { - self->guard_name[j++] = (char)toupper(c); + else if (CFCUtil_isalnum(c)) { + self->guard_name[j++] = CFCUtil_toupper(c); } } self->guard_name[j] = '\0'; diff --git a/compiler/src/CFCFileSpec.c b/compiler/src/CFCFileSpec.c index 90e3b768..4523f20e 100644 --- a/compiler/src/CFCFileSpec.c +++ b/compiler/src/CFCFileSpec.c @@ -18,7 +18,6 @@ #include #include -#include #ifndef true #define true 1 diff --git a/compiler/src/CFCFunction.c b/compiler/src/CFCFunction.c index bbfc88c4..d7390072 100644 --- a/compiler/src/CFCFunction.c +++ b/compiler/src/CFCFunction.c @@ -15,7 +15,6 @@ */ #include -#include #ifndef true #define true 1 @@ -58,7 +57,9 @@ S_validate_function_name(const char *name) { if (!len) { return false; } for (size_t i = 0; i < len; i++) { char c = name[i]; - if (!islower(c) && !isdigit(c) && c != '_') { return false; } + if (!CFCUtil_islower(c) && !CFCUtil_isdigit(c) && c != '_') { + return false; + } } return true; } diff --git a/compiler/src/CFCGo.c b/compiler/src/CFCGo.c index c263bfdb..56c43bf8 100644 --- a/compiler/src/CFCGo.c +++ b/compiler/src/CFCGo.c @@ -19,7 +19,6 @@ #include #include #include -#include #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" diff --git a/compiler/src/CFCGoFunc.c b/compiler/src/CFCGoFunc.c index 8607d8fd..7abf90fa 100644 --- a/compiler/src/CFCGoFunc.c +++ b/compiler/src/CFCGoFunc.c @@ -17,7 +17,6 @@ #include #include -#include #include "charmony.h" @@ -49,7 +48,7 @@ char* CFCGoFunc_go_meth_name(const char *orig, int is_public) { char *go_name = CFCUtil_strdup(orig); if (!is_public) { - go_name[0] = (char)tolower(go_name[0]); + go_name[0] = CFCUtil_tolower(go_name[0]); } for (size_t i = 1, j = 1, max = strlen(go_name) + 1; i < max; i++) { if (go_name[i] != '_') { diff --git a/compiler/src/CFCGoMethod.c b/compiler/src/CFCGoMethod.c index 7de4f096..241e4daf 100644 --- a/compiler/src/CFCGoMethod.c +++ b/compiler/src/CFCGoMethod.c @@ -17,7 +17,6 @@ #include #include -#include #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" diff --git a/compiler/src/CFCGoTypeMap.c b/compiler/src/CFCGoTypeMap.c index ad91817b..197051f1 100644 --- a/compiler/src/CFCGoTypeMap.c +++ b/compiler/src/CFCGoTypeMap.c @@ -16,7 +16,6 @@ #include #include -#include #include #include "CFCGoTypeMap.h" @@ -113,7 +112,7 @@ CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { const char *specifier = CFCType_get_specifier(type); size_t prefix_len = 0; for (size_t max = strlen(specifier); prefix_len < max; prefix_len++) { - if (isupper(specifier[prefix_len])) { + if (CFCUtil_isupper(specifier[prefix_len])) { break; } } @@ -153,7 +152,7 @@ CFCGoTypeMap_go_type_name(CFCType *type, CFCParcel *current_parcel) { } char *result = CFCUtil_sprintf("%s.%s", package_name, struct_sym); for (int i = 0; result[i] != '.'; i++) { - result[i] = (char)tolower(result[i]); + result[i] = CFCUtil_tolower(result[i]); } return result; } @@ -184,7 +183,7 @@ CFCGoTypeMap_go_short_package(CFCParcel *parcel) { // parcel names. char *go_short_package = CFCUtil_strdup(parcel_frag); for (int i = 0; go_short_package[i] != '\0'; i++) { - go_short_package[i] = (char)tolower(go_short_package[i]); + go_short_package[i] = CFCUtil_tolower(go_short_package[i]); } return go_short_package; } @@ -206,8 +205,8 @@ CFCGoTypeMap_go_meth_receiever(const char *struct_name, // Find the first letter of the type and lowercase it. for (size_t i = 0, max = strlen(struct_name); i < max; i++) { - if (isupper(struct_name[i])) { - buf[0] = (char)tolower(struct_name[i]); + if (CFCUtil_isupper(struct_name[i])) { + buf[0] = CFCUtil_tolower(struct_name[i]); buf[1] = '\0'; break; } @@ -265,7 +264,7 @@ CFCGoTypeMap_go_arg_name(CFCParamList *param_list, size_t tick, char *buf, continue; } else if (last_was_underscore) { - buf[dest_tick] = (char)toupper(orig[i]); + buf[dest_tick] = CFCUtil_toupper(orig[i]); } else { buf[dest_tick] = orig[i]; diff --git a/compiler/src/CFCHierarchy.c b/compiler/src/CFCHierarchy.c index 57d3bfc5..5b1e636e 100644 --- a/compiler/src/CFCHierarchy.c +++ b/compiler/src/CFCHierarchy.c @@ -21,7 +21,6 @@ #include #include #include -#include #ifndef true #define true 1 diff --git a/compiler/src/CFCMethod.c b/compiler/src/CFCMethod.c index 8a142d14..a8585fb9 100644 --- a/compiler/src/CFCMethod.c +++ b/compiler/src/CFCMethod.c @@ -15,7 +15,6 @@ */ #include -#include #include #define CFC_NEED_CALLABLE_STRUCT_DEF @@ -66,15 +65,15 @@ S_validate_meth_name(const char *meth_name) { int need_upper = true; int need_letter = true; for (;; meth_name++) { - if (need_upper && !isupper(*meth_name)) { return false; } - if (need_letter && !isalpha(*meth_name)) { return false; } + if (need_upper && !CFCUtil_isupper(*meth_name)) { return false; } + if (need_letter && !CFCUtil_isalpha(*meth_name)) { return false; } need_upper = false; need_letter = false; // We've reached NULL-termination without problems, so succeed. if (!*meth_name) { return true; } - if (!isalnum(*meth_name)) { + if (!CFCUtil_isalnum(*meth_name)) { if (*meth_name != '_') { return false; } need_upper = true; } diff --git a/compiler/src/CFCParcel.c b/compiler/src/CFCParcel.c index cbfd2a53..5379d638 100644 --- a/compiler/src/CFCParcel.c +++ b/compiler/src/CFCParcel.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include @@ -143,7 +142,7 @@ static int S_validate_name_or_nickname(const char *orig) { const char *ptr = orig; for (; *ptr != 0; ptr++) { - if (!isalpha(*ptr)) { return false; } + if (!CFCUtil_isalpha(*ptr)) { return false; } } return true; } @@ -209,8 +208,8 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *nickname, self->Prefix[nickname_len] = '\0'; } for (size_t i = 0; i < amount; i++) { - self->prefix[i] = (char)tolower(self->Prefix[i]); - self->PREFIX[i] = (char)toupper(self->Prefix[i]); + self->prefix[i] = CFCUtil_tolower(self->Prefix[i]); + self->PREFIX[i] = CFCUtil_toupper(self->Prefix[i]); } self->prefix[prefix_len] = '\0'; self->Prefix[prefix_len] = '\0'; @@ -221,7 +220,7 @@ CFCParcel_init(CFCParcel *self, const char *name, const char *nickname, self->privacy_sym = (char*)MALLOCATE(privacy_sym_len + 1); memcpy(self->privacy_sym, "CFP_", 4); for (size_t i = 0; i < nickname_len; i++) { - self->privacy_sym[i+4] = (char)toupper(self->nickname[i]); + self->privacy_sym[i+4] = CFCUtil_toupper(self->nickname[i]); } self->privacy_sym[privacy_sym_len] = '\0'; @@ -805,7 +804,7 @@ S_parse_json_null(const char **json) { static void S_skip_whitespace(const char **json) { - while (isspace(json[0][0])) { *json = *json + 1; } + while (CFCUtil_isspace(json[0][0])) { *json = *json + 1; } } static void diff --git a/compiler/src/CFCPerl.c b/compiler/src/CFCPerl.c index ccd548bd..34bd0cb7 100644 --- a/compiler/src/CFCPerl.c +++ b/compiler/src/CFCPerl.c @@ -18,7 +18,7 @@ #include #include -#include + #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" #include "CFCPerl.h" @@ -108,7 +108,7 @@ CFCPerl_init(CFCPerl *self, CFCHierarchy *hierarchy, const char *lib_dir, // Derive the name of the bootstrap function. self->boot_func = CFCUtil_sprintf("cfish_%s_bootstrap", boot_class); for (int i = 0; self->boot_func[i] != 0; i++) { - if (!isalnum(self->boot_func[i])) { + if (!CFCUtil_isalnum(self->boot_func[i])) { self->boot_func[i] = '_'; } } @@ -279,8 +279,8 @@ S_write_boot_h(CFCPerl *self) { char *guard = CFCUtil_sprintf("%s_BOOT", self->boot_class); S_replace_double_colons(guard, '_'); for (char *ptr = guard; *ptr != '\0'; ptr++) { - if (isalpha(*ptr)) { - *ptr = (char)toupper(*ptr); + if (CFCUtil_isalpha(*ptr)) { + *ptr = CFCUtil_toupper(*ptr); } } diff --git a/compiler/src/CFCPerlClass.c b/compiler/src/CFCPerlClass.c index cb26d4d2..30dc1d63 100644 --- a/compiler/src/CFCPerlClass.c +++ b/compiler/src/CFCPerlClass.c @@ -15,9 +15,9 @@ */ #include -#include #include #include + #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" #include "CFCPerlClass.h" diff --git a/compiler/src/CFCPerlMethod.c b/compiler/src/CFCPerlMethod.c index f6148962..313176df 100644 --- a/compiler/src/CFCPerlMethod.c +++ b/compiler/src/CFCPerlMethod.c @@ -16,7 +16,6 @@ #include #include -#include #define CFC_NEED_PERLSUB_STRUCT_DEF 1 #include "CFCPerlSub.h" @@ -133,7 +132,7 @@ CFCPerlMethod_perl_name(CFCMethod *method) { const char *name = CFCMethod_get_name(method); char *perl_name = CFCUtil_strdup(name); for (size_t i = 0; perl_name[i] != '\0'; i++) { - perl_name[i] = (char)tolower(perl_name[i]); + perl_name[i] = CFCUtil_tolower(perl_name[i]); } return perl_name; diff --git a/compiler/src/CFCPerlPod.c b/compiler/src/CFCPerlPod.c index 09be538d..63105da3 100644 --- a/compiler/src/CFCPerlPod.c +++ b/compiler/src/CFCPerlPod.c @@ -17,7 +17,6 @@ #include "charmony.h" #include -#include #include @@ -533,7 +532,7 @@ S_perl_var_name(CFCType *type, int is_ctor_retval) { } else { // Skip parcel prefix. - if (islower(*specifier)) { + if (CFCUtil_islower(*specifier)) { for (specifier++; *specifier; specifier++) { if (*specifier == '_') { specifier++; @@ -570,21 +569,21 @@ S_camel_to_lower(const char *camel) { size_t alloc = 1; for (size_t i = 1; camel[i]; i++) { - if (isupper(camel[i]) && islower(camel[i+1])) { + if (CFCUtil_isupper(camel[i]) && CFCUtil_islower(camel[i+1])) { alloc += 1; } alloc += 1; } char *lower = (char*)MALLOCATE(alloc + 1); - lower[0] = (char)tolower(camel[0]); + lower[0] = CFCUtil_tolower(camel[0]); size_t j = 1; for (size_t i = 1; camel[i]; i++) { // Only insert underscore if next char is lowercase. - if (isupper(camel[i]) && islower(camel[i+1])) { + if (CFCUtil_isupper(camel[i]) && CFCUtil_islower(camel[i+1])) { lower[j++] = '_'; } - lower[j++] = (char)tolower(camel[i]); + lower[j++] = CFCUtil_tolower(camel[i]); } lower[j] = '\0'; @@ -948,7 +947,7 @@ S_convert_link(cmark_node *link, CFCClass *doc_class, int header_level) { char *perl_name = CFCUtil_strdup(name); for (size_t i = 0; perl_name[i] != '\0'; ++i) { - perl_name[i] = (char)tolower(perl_name[i]); + perl_name[i] = CFCUtil_tolower(perl_name[i]); } // The Perl POD only contains sections for novel methods. Link diff --git a/compiler/src/CFCPyClass.c b/compiler/src/CFCPyClass.c index 1e80ebb8..7e597156 100644 --- a/compiler/src/CFCPyClass.c +++ b/compiler/src/CFCPyClass.c @@ -15,7 +15,6 @@ */ #include -#include #include #define CFC_NEED_BASE_STRUCT_DEF 1 @@ -204,7 +203,7 @@ S_pytype_struct_def(CFCPyClass *self) { char *pymod_name = CFCUtil_strdup(parcel_name); // TODO: Stop lowercasing when parcels are restricted to lowercase. for (int i = 0; pymod_name[i] != '\0'; i++) { - pymod_name[i] = (char)tolower(pymod_name[i]); + pymod_name[i] = CFCUtil_tolower(pymod_name[i]); } const char *struct_sym = CFCClass_get_struct_sym(klass); diff --git a/compiler/src/CFCPyMethod.c b/compiler/src/CFCPyMethod.c index 168bfb80..ec29846b 100644 --- a/compiler/src/CFCPyMethod.c +++ b/compiler/src/CFCPyMethod.c @@ -15,7 +15,6 @@ */ #include -#include #include "CFCPyMethod.h" #include "CFCPyTypeMap.h" @@ -277,7 +276,7 @@ S_build_pymeth_invocation(CFCMethod *method) { CFCUtil_die("Unexpectedly long type name: %s", ret_type_str); } for (size_t i = 0, max = strlen(ret_type_str) + 1; i < max; i++) { - type_upcase[i] = (char)toupper(ret_type_str[i]); + type_upcase[i] = CFCUtil_toupper(ret_type_str[i]); } const char pattern[] = " %s cfcb_RESULT = CALL_PYMETH_%s((PyObject*)self, \"%s\", cfcb_ARGS);"; @@ -646,7 +645,7 @@ CFCPyMethod_pymethoddef(CFCMethod *method, CFCClass *invoker) { char *meth_sym = CFCMethod_full_method_sym(method, invoker); char *micro_sym = CFCUtil_strdup(CFCSymbol_get_name((CFCSymbol*)method)); for (int i = 0; micro_sym[i] != 0; i++) { - micro_sym[i] = (char)tolower(micro_sym[i]); + micro_sym[i] = CFCUtil_tolower(micro_sym[i]); } char pattern[] = diff --git a/compiler/src/CFCPython.c b/compiler/src/CFCPython.c index 0dff7e26..f81cfd45 100644 --- a/compiler/src/CFCPython.c +++ b/compiler/src/CFCPython.c @@ -19,7 +19,6 @@ #include #include #include -#include #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" @@ -447,7 +446,7 @@ S_write_module_file(CFCPython *self, CFCParcel *parcel, const char *dest) { char *pymod_name = CFCUtil_strdup(parcel_name); // TODO: Stop lowercasing when parcels are restricted to lowercase. for (int i = 0; pymod_name[i] != '\0'; i++) { - pymod_name[i] = (char)tolower(pymod_name[i]); + pymod_name[i] = CFCUtil_tolower(pymod_name[i]); } const char *last_dot = strrchr(pymod_name, '.'); const char *last_component = last_dot != NULL @@ -455,7 +454,7 @@ S_write_module_file(CFCPython *self, CFCParcel *parcel, const char *dest) { : pymod_name; char *helper_mod_name = CFCUtil_sprintf("%s._%s", pymod_name, last_component); for (int i = 0; helper_mod_name[i] != '\0'; i++) { - helper_mod_name[i] = (char)tolower(helper_mod_name[i]); + helper_mod_name[i] = CFCUtil_tolower(helper_mod_name[i]); } CFCClass **ordered = CFCHierarchy_ordered_classes(self->hierarchy); diff --git a/compiler/src/CFCRuby.c b/compiler/src/CFCRuby.c index 0e2c146d..bf25b687 100644 --- a/compiler/src/CFCRuby.c +++ b/compiler/src/CFCRuby.c @@ -18,7 +18,7 @@ #include #include -#include + #define CFC_NEED_BASE_STRUCT_DEF #include "CFCBase.h" #include "CFCClass.h" @@ -89,7 +89,7 @@ CFCRuby_init(CFCRuby *self, CFCParcel *parcel, CFCHierarchy *hierarchy, self->boot_func = CFCUtil_sprintf("%s%s_bootstrap", prefix, boot_class); for (int i = 0; self->boot_func[i] != 0; i++) { - if (!isalnum(self->boot_func[i])) { + if (!CFCUtil_isalnum(self->boot_func[i])) { self->boot_func[i] = '_'; } } @@ -134,8 +134,8 @@ S_write_boot_h(CFCRuby *self) { "_BOOT", NULL); S_replace_double_colons(guard, '_'); for (char *ptr = guard; *ptr != '\0'; ptr++) { - if (isalpha(*ptr)) { - *ptr = (char)toupper(*ptr); + if (CFCUtil_isalpha(*ptr)) { + *ptr = CFCUtil_toupper(*ptr); } } diff --git a/compiler/src/CFCSymbol.c b/compiler/src/CFCSymbol.c index 2dd7ddc4..ab37b4eb 100644 --- a/compiler/src/CFCSymbol.c +++ b/compiler/src/CFCSymbol.c @@ -15,7 +15,6 @@ */ #include -#include #ifndef true #define true 1 @@ -56,9 +55,9 @@ S_validate_exposure(const char *exposure) { static int S_validate_identifier(const char *identifier) { const char *ptr = identifier; - if (!isalpha(*ptr) && *ptr != '_') { return false; } + if (!CFCUtil_isalpha(*ptr) && *ptr != '_') { return false; } for (; *ptr != 0; ptr++) { - if (!isalnum(*ptr) && *ptr != '_') { return false; } + if (!CFCUtil_isalnum(*ptr) && *ptr != '_') { return false; } } return true; } diff --git a/compiler/src/CFCType.c b/compiler/src/CFCType.c index a45c1741..5dd3136b 100644 --- a/compiler/src/CFCType.c +++ b/compiler/src/CFCType.c @@ -16,7 +16,6 @@ #include #include -#include #include "charmony.h" @@ -221,12 +220,12 @@ CFCType_new_object(int flags, CFCParcel *parcel, const char *specifier, S_check_flags(flags, acceptable_flags, "Object"); // Validate specifier. - if (!isalpha(*specifier)) { + if (!CFCUtil_isalpha(*specifier)) { CFCUtil_die("Invalid specifier: '%s'", specifier); } const char *small_specifier = specifier; - while (!isupper(*small_specifier)) { - if (!isalnum(*small_specifier) && *small_specifier != '_') { + while (!CFCUtil_isupper(*small_specifier)) { + if (!CFCUtil_isalnum(*small_specifier) && *small_specifier != '_') { CFCUtil_die("Invalid specifier: '%s'", specifier); } small_specifier++; @@ -276,7 +275,7 @@ CFCType* CFCType_new_arbitrary(CFCParcel *parcel, const char *specifier) { // Validate specifier. for (size_t i = 0, max = strlen(specifier); i < max; i++) { - if (!isalnum(specifier[i]) && specifier[i] != '_') { + if (!CFCUtil_isalnum(specifier[i]) && specifier[i] != '_') { CFCUtil_die("Illegal specifier: '%s'", specifier); } } @@ -295,7 +294,7 @@ CFCType_resolve(CFCType *self) { } char *specifier = self->specifier; - if (isupper(specifier[0])) { + if (CFCUtil_isupper(specifier[0])) { CFCParcel *parcel = CFCParcel_lookup_struct_sym(self->parcel, specifier); if (!parcel) { @@ -384,7 +383,7 @@ CFCType_get_class_var(CFCType *self) { if (!self->class_var) { self->class_var = CFCUtil_strdup(self->specifier); for (int i = 0; self->class_var[i] != 0; i++) { - self->class_var[i] = (char)toupper(self->class_var[i]); + self->class_var[i] = CFCUtil_toupper(self->class_var[i]); } } return self->class_var; diff --git a/compiler/src/CFCUri.c b/compiler/src/CFCUri.c index 7ac8a7e5..c16c43e3 100644 --- a/compiler/src/CFCUri.c +++ b/compiler/src/CFCUri.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #include @@ -110,7 +109,7 @@ S_parse(CFCUri *self) { char *iter = buf; const char *component = S_next_component(&iter); - if (islower(component[0])) { + if (CFCUtil_islower(component[0])) { // Parcel parcel = component; component = S_next_component(&iter); @@ -179,7 +178,7 @@ S_resolve(CFCUri *self, const char *parcel, const char *struct_sym, CFCBase_incref((CFCBase*)klass); if (callable) { - if (islower(callable[0])) { + if (CFCUtil_islower(callable[0])) { CFCFunction *function = CFCClass_function(klass, callable); if (!function) { diff --git a/compiler/src/CFCUtil.c b/compiler/src/CFCUtil.c index 83c30e22..c5444fd9 100644 --- a/compiler/src/CFCUtil.c +++ b/compiler/src/CFCUtil.c @@ -130,13 +130,13 @@ CFCUtil_trim_whitespace(char *text) { // Find start. char *ptr = text; - while (*ptr != '\0' && isspace(*ptr)) { ptr++; } + while (*ptr != '\0' && CFCUtil_isspace(*ptr)) { ptr++; } // Find end. size_t orig_len = strlen(text); char *limit = text + orig_len; for (; limit > text; limit--) { - if (!isspace(*(limit - 1))) { break; } + if (!CFCUtil_isspace(*(limit - 1))) { break; } } // Modify string in place and NULL-terminate. diff --git a/compiler/src/CFCVersion.c b/compiler/src/CFCVersion.c index 97727a87..74d3c395 100644 --- a/compiler/src/CFCVersion.c +++ b/compiler/src/CFCVersion.c @@ -15,7 +15,6 @@ */ #include -#include #ifndef true #define true 1 @@ -49,7 +48,7 @@ CFCVersion_new(const char *vstring) { CFCVersion* CFCVersion_init(CFCVersion *self, const char *vstring) { CFCUTIL_NULL_CHECK(vstring); - if (*vstring != 'v' || !isdigit(vstring[1])) { + if (*vstring != 'v' || !CFCUtil_isdigit(vstring[1])) { CFCBase_decref((CFCBase*)self); CFCUtil_die("Bad version string: '%s'", vstring); } @@ -59,7 +58,7 @@ CFCVersion_init(CFCVersion *self, const char *vstring) { self->num_numbers = 0; self->numbers = (uint32_t*)CALLOCATE(1, sizeof(uint32_t)); while (1) { - if (isdigit(*vstring)) { + if (CFCUtil_isdigit(*vstring)) { int digit = *vstring - '0'; num = num * 10 + (uint32_t)digit; } From 8e136edacf5e531101e8bbf165fe7a8b1e005264 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 6 Apr 2016 13:29:23 +0200 Subject: [PATCH 3/4] Check code point range in Str_BaseX_To_I64 Avoid undefined behavior when calling ctype.h functions. --- runtime/core/Clownfish/String.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/core/Clownfish/String.c b/runtime/core/Clownfish/String.c index f6196737..633aa80a 100644 --- a/runtime/core/Clownfish/String.c +++ b/runtime/core/Clownfish/String.c @@ -243,7 +243,7 @@ Str_BaseX_To_I64_IMP(String *self, uint32_t base) { // Accumulate. while (code_point != STR_OOB) { - if (isalnum(code_point)) { + if (code_point <= 127 && isalnum(code_point)) { int32_t addend = isdigit(code_point) ? code_point - '0' : tolower(code_point) - 'a' + 10; From 2fda55327d59ec11b88ce1056e91b46e833ff406 Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Wed, 6 Apr 2016 13:31:30 +0200 Subject: [PATCH 4/4] Remove unneeded ctype.h includes --- runtime/core/Clownfish/ByteBuf.c | 1 - runtime/core/Clownfish/CharBuf.c | 1 - runtime/core/Clownfish/Class.c | 1 - runtime/core/Clownfish/Err.c | 1 - runtime/perl/xs/XSBind.c | 1 - 5 files changed, 5 deletions(-) diff --git a/runtime/core/Clownfish/ByteBuf.c b/runtime/core/Clownfish/ByteBuf.c index 96d31b6d..dc03cf54 100644 --- a/runtime/core/Clownfish/ByteBuf.c +++ b/runtime/core/Clownfish/ByteBuf.c @@ -20,7 +20,6 @@ #include #include #include -#include #include "Clownfish/Class.h" #include "Clownfish/ByteBuf.h" diff --git a/runtime/core/Clownfish/CharBuf.c b/runtime/core/Clownfish/CharBuf.c index 38672499..5bd5c031 100644 --- a/runtime/core/Clownfish/CharBuf.c +++ b/runtime/core/Clownfish/CharBuf.c @@ -24,7 +24,6 @@ #include #include #include -#include #include "Clownfish/CharBuf.h" diff --git a/runtime/core/Clownfish/Class.c b/runtime/core/Clownfish/Class.c index 8c5cdfe7..4608866d 100644 --- a/runtime/core/Clownfish/Class.c +++ b/runtime/core/Clownfish/Class.c @@ -23,7 +23,6 @@ #include #include #include -#include #include "Clownfish/Class.h" #include "Clownfish/String.h" diff --git a/runtime/core/Clownfish/Err.c b/runtime/core/Clownfish/Err.c index dd398e75..82daf02d 100644 --- a/runtime/core/Clownfish/Err.c +++ b/runtime/core/Clownfish/Err.c @@ -23,7 +23,6 @@ #include #include -#include #include "Clownfish/Err.h" diff --git a/runtime/perl/xs/XSBind.c b/runtime/perl/xs/XSBind.c index 17f02664..515e752d 100644 --- a/runtime/perl/xs/XSBind.c +++ b/runtime/perl/xs/XSBind.c @@ -14,7 +14,6 @@ * limitations under the License. */ -#include #include #define C_CFISH_OBJ