From 5953eed7dc5c9f70940000c40c6ff5237a3b1808 Mon Sep 17 00:00:00 2001 From: Benjamin Barenblat Date: Tue, 2 May 2017 13:15:51 -0400 Subject: Enable -Wunused-parameter --- src/c/urweb.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 6f2dde38..504597ef 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1519,6 +1519,7 @@ uw_Basis_string uw_Basis_maybe_onunload(uw_context ctx, uw_Basis_string s) { } const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { + (void)u; if (ctx->client == NULL) { if (ctx->needs_sig) { char *sig = ctx->app->cookie_sig(ctx); @@ -1847,6 +1848,7 @@ char *uw_Basis_attrifyChar(uw_context ctx, uw_Basis_char c) { } char *uw_Basis_attrifyCss_class(uw_context ctx, uw_Basis_css_class s) { + (void)ctx; return s; } @@ -1973,6 +1975,7 @@ char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) { } char *uw_Basis_urlifyBool(uw_context ctx, uw_Basis_bool b) { + (void)ctx; if (b == uw_Basis_False) return "0"; else @@ -2093,6 +2096,8 @@ static char *uw_unurlify_advance(char *s) { } uw_Basis_int uw_Basis_unurlifyInt(uw_context ctx, char **s) { + (void)ctx; + char *new_s = uw_unurlify_advance(*s); uw_Basis_int r; @@ -2102,6 +2107,8 @@ uw_Basis_int uw_Basis_unurlifyInt(uw_context ctx, char **s) { } uw_Basis_float uw_Basis_unurlifyFloat(uw_context ctx, char **s) { + (void)ctx; + char *new_s = uw_unurlify_advance(*s); uw_Basis_float r; @@ -2165,6 +2172,8 @@ static uw_Basis_string uw_unurlifyString_to(int fromClient, uw_context ctx, char } uw_Basis_bool uw_Basis_unurlifyBool(uw_context ctx, char **s) { + (void)ctx; + char *new_s = uw_unurlify_advance(*s); uw_Basis_bool r; @@ -2192,6 +2201,7 @@ uw_Basis_string uw_Basis_unurlifyString(uw_context ctx, char **s) { } uw_Basis_unit uw_Basis_unurlifyUnit(uw_context ctx, char **s) { + (void)ctx; *s = uw_unurlify_advance(*s); return uw_unit_v; } @@ -2345,6 +2355,7 @@ uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) { } uw_Basis_string uw_Basis_htmlifyBool(uw_context ctx, uw_Basis_bool b) { + (void)ctx; if (b == uw_Basis_False) return "False"; else @@ -2428,10 +2439,13 @@ uw_Basis_string uw_Basis_strsuffix(uw_context ctx, uw_Basis_string s, uw_Basis_i } uw_Basis_int uw_Basis_strlen(uw_context ctx, uw_Basis_string s) { + (void)ctx; return strlen(s); } uw_Basis_bool uw_Basis_strlenGe(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { + (void)ctx; + while (n > 0) { if (*s == 0) return uw_Basis_False; @@ -2444,10 +2458,12 @@ uw_Basis_bool uw_Basis_strlenGe(uw_context ctx, uw_Basis_string s, uw_Basis_int } uw_Basis_string uw_Basis_strchr(uw_context ctx, uw_Basis_string s, uw_Basis_char ch) { + (void)ctx; return strchr(s, ch); } uw_Basis_int uw_Basis_strcspn(uw_context ctx, uw_Basis_string s, uw_Basis_string chs) { + (void)ctx; return strcspn(s, chs); } @@ -2794,6 +2810,7 @@ uw_Basis_string uw_Basis_sqlifyStringN(uw_context ctx, uw_Basis_string s) { } char *uw_Basis_sqlifyBool(uw_context ctx, uw_Basis_bool b) { + (void)ctx; if (b == uw_Basis_False) return "FALSE"; else @@ -2914,6 +2931,7 @@ uw_Basis_string uw_Basis_charToString(uw_context ctx, uw_Basis_char ch) { } uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) { + (void)ctx; if (b == uw_Basis_False) return "False"; else @@ -2979,6 +2997,7 @@ uw_Basis_char *uw_Basis_stringToChar(uw_context ctx, uw_Basis_string s) { } uw_Basis_bool *uw_Basis_stringToBool(uw_context ctx, uw_Basis_string s) { + (void)ctx; static uw_Basis_bool true = uw_Basis_True; static uw_Basis_bool false = uw_Basis_False; @@ -3353,6 +3372,8 @@ static delta *allocate_delta(uw_context ctx, unsigned client) { } uw_Basis_channel uw_Basis_new_channel(uw_context ctx, uw_unit u) { + (void)u; + if (ctx->client == NULL) uw_error(ctx, FATAL, "Attempt to create channel on request not associated with a persistent connection"); @@ -3929,37 +3950,45 @@ int uw_streq(uw_Basis_string s1, uw_Basis_string s2) { } uw_Basis_string uw_Basis_sigString(uw_context ctx, uw_unit u) { + (void)u; ctx->usedSig = 1; return ctx->app->cookie_sig(ctx); } uw_Basis_string uw_Basis_fileName(uw_context ctx, uw_Basis_file f) { + (void)ctx; return f.name; } uw_Basis_string uw_Basis_fileMimeType(uw_context ctx, uw_Basis_file f) { + (void)ctx; return f.type; } uw_Basis_int uw_Basis_blobSize(uw_context ctx, uw_Basis_blob b) { + (void)ctx; return b.size; } uw_Basis_blob uw_Basis_textBlob(uw_context ctx, uw_Basis_string s) { + (void)ctx; uw_Basis_blob b = {strlen(s), s}; return b; } uw_Basis_blob uw_Basis_fileData(uw_context ctx, uw_Basis_file f) { + (void)ctx; return f.data; } uw_Basis_string uw_Basis_postType(uw_context ctx, uw_Basis_postBody pb) { + (void)ctx; return pb.type; } uw_Basis_string uw_Basis_postData(uw_context ctx, uw_Basis_postBody pb) { + (void)ctx; return pb.data; } @@ -4156,24 +4185,29 @@ uw_Basis_string uw_Basis_mstrcat(uw_context ctx, ...) { const uw_Basis_time uw_Basis_minTime = {}; uw_Basis_time uw_Basis_now(uw_context ctx) { + (void)ctx; uw_Basis_time r = { time(NULL) }; return r; } uw_Basis_time uw_Basis_addSeconds(uw_context ctx, uw_Basis_time tm, uw_Basis_int n) { + (void)ctx; tm.seconds += n; return tm; } uw_Basis_int uw_Basis_diffInSeconds(uw_context ctx, uw_Basis_time tm1, uw_Basis_time tm2) { + (void)ctx; return difftime(tm2.seconds, tm1.seconds); } uw_Basis_int uw_Basis_toMilliseconds(uw_context ctx, uw_Basis_time tm) { + (void)ctx; return tm.seconds * 1000 + tm.microseconds / 1000; } uw_Basis_time uw_Basis_fromMilliseconds(uw_context ctx, uw_Basis_int n) { + (void)ctx; uw_Basis_time tm = {n / 1000, n % 1000 * 1000}; return tm; } @@ -4183,10 +4217,12 @@ uw_Basis_int uw_Basis_diffInMilliseconds(uw_context ctx, uw_Basis_time tm1, uw_B } uw_Basis_int uw_Basis_toSeconds(uw_context ctx, uw_Basis_time tm) { + (void)ctx; return tm.seconds; } uw_Basis_time uw_Basis_fromDatetime(uw_context ctx, uw_Basis_int year, uw_Basis_int month, uw_Basis_int day, uw_Basis_int hour, uw_Basis_int minute, uw_Basis_int second) { + (void)ctx; struct tm tm = { .tm_year = year - 1900, .tm_mon = month, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second, .tm_isdst = -1 }; @@ -4195,42 +4231,49 @@ uw_Basis_time uw_Basis_fromDatetime(uw_context ctx, uw_Basis_int year, uw_Basis_ } uw_Basis_int uw_Basis_datetimeYear(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_year + 1900; } uw_Basis_int uw_Basis_datetimeMonth(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_mon; } uw_Basis_int uw_Basis_datetimeDay(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_mday; } uw_Basis_int uw_Basis_datetimeHour(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_hour; } uw_Basis_int uw_Basis_datetimeMinute(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_min; } uw_Basis_int uw_Basis_datetimeSecond(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_sec; } uw_Basis_int uw_Basis_datetimeDayOfWeek(uw_context ctx, uw_Basis_time time) { + (void)ctx; struct tm tm; localtime_r(&time.seconds, &tm); return tm.tm_wday; @@ -4272,66 +4315,82 @@ void uw_set_global(uw_context ctx, char *name, void *data, void (*free)(void*)) } uw_Basis_bool uw_Basis_isalnum(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isalnum((int)c); } uw_Basis_bool uw_Basis_isalpha(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isalpha((int)c); } uw_Basis_bool uw_Basis_isblank(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isblank((int)c); } uw_Basis_bool uw_Basis_iscntrl(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!iscntrl((int)c); } uw_Basis_bool uw_Basis_isdigit(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isdigit((int)c); } uw_Basis_bool uw_Basis_isgraph(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isgraph((int)c); } uw_Basis_bool uw_Basis_islower(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!islower((int)c); } uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isprint((int)c); } uw_Basis_bool uw_Basis_ispunct(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!ispunct((int)c); } uw_Basis_bool uw_Basis_isspace(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isspace((int)c); } uw_Basis_bool uw_Basis_isupper(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isupper((int)c); } uw_Basis_bool uw_Basis_isxdigit(uw_context ctx, uw_Basis_char c) { + (void)ctx; return !!isxdigit((int)c); } uw_Basis_char uw_Basis_tolower(uw_context ctx, uw_Basis_char c) { + (void)ctx; return tolower((int)c); } uw_Basis_char uw_Basis_toupper(uw_context ctx, uw_Basis_char c) { + (void)ctx; return toupper((int)c); } uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c) { + (void)ctx; return (unsigned char)c; } uw_Basis_char uw_Basis_chr(uw_context ctx, uw_Basis_int n) { + (void)ctx; return n; } @@ -4437,10 +4496,12 @@ uw_Basis_string uw_Basis_crypt(uw_context ctx, uw_Basis_string key, uw_Basis_str } uw_Basis_bool uw_Basis_eq_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { + (void)ctx; return !!(t1.seconds == t2.seconds && t1.microseconds == t2.microseconds); } uw_Basis_bool uw_Basis_lt_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { + (void)ctx; return !!(t1.seconds < t2.seconds || (t1.seconds == t2.seconds && t1.microseconds < t2.microseconds)); } @@ -4505,66 +4566,82 @@ uw_Basis_string uw_Basis_fresh(uw_context ctx) { } uw_Basis_float uw_Basis_floatFromInt(uw_context ctx, uw_Basis_int n) { + (void)ctx; return n; } uw_Basis_int uw_Basis_ceil(uw_context ctx, uw_Basis_float n) { + (void)ctx; return ceil(n); } uw_Basis_int uw_Basis_trunc(uw_context ctx, uw_Basis_float n) { + (void)ctx; return trunc(n); } uw_Basis_int uw_Basis_round(uw_context ctx, uw_Basis_float n) { + (void)ctx; return round(n); } uw_Basis_int uw_Basis_floor(uw_context ctx, uw_Basis_float n) { + (void)ctx; return floor(n); } uw_Basis_float uw_Basis_pow(uw_context ctx, uw_Basis_float n, uw_Basis_float m) { + (void)ctx; return pow(n,m); } uw_Basis_float uw_Basis_sqrt(uw_context ctx, uw_Basis_float n) { + (void)ctx; return sqrt(n); } uw_Basis_float uw_Basis_sin(uw_context ctx, uw_Basis_float n) { + (void)ctx; return sin(n); } uw_Basis_float uw_Basis_cos(uw_context ctx, uw_Basis_float n) { + (void)ctx; return cos(n); } uw_Basis_float uw_Basis_log(uw_context ctx, uw_Basis_float n) { + (void)ctx; return log(n); } uw_Basis_float uw_Basis_exp(uw_context ctx, uw_Basis_float n) { + (void)ctx; return exp(n); } uw_Basis_float uw_Basis_asin(uw_context ctx, uw_Basis_float n) { + (void)ctx; return asin(n); } uw_Basis_float uw_Basis_acos(uw_context ctx, uw_Basis_float n) { + (void)ctx; return acos(n); } uw_Basis_float uw_Basis_atan(uw_context ctx, uw_Basis_float n) { + (void)ctx; return atan(n); } uw_Basis_float uw_Basis_atan2(uw_context ctx, uw_Basis_float n, uw_Basis_float m) { + (void)ctx; return atan2(n, m); } uw_Basis_float uw_Basis_abs(uw_context ctx, uw_Basis_float n) { + (void)ctx; return fabs(n); } @@ -4612,14 +4689,17 @@ uw_Basis_string uw_Basis_property(uw_context ctx, uw_Basis_string s) { } uw_Basis_string uw_Basis_fieldName(uw_context ctx, uw_Basis_postField f) { + (void)ctx; return f.name; } uw_Basis_string uw_Basis_fieldValue(uw_context ctx, uw_Basis_postField f) { + (void)ctx; return f.value; } uw_Basis_string uw_Basis_remainingFields(uw_context ctx, uw_Basis_postField f) { + (void)ctx; return f.remaining; } @@ -4754,6 +4834,7 @@ static char *uw_Sqlcache_keyCopy(char *buf, char *key) { // The NUL-terminated prefix of [key] below always looks something like "_k1_k2_k3..._kn". uw_Sqlcache_Value *uw_Sqlcache_check(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) { + (void)ctx; int doBump = random() % 1024 == 0; if (doBump) { pthread_rwlock_wrlock(&cache->lockIn); @@ -4836,6 +4917,8 @@ static void uw_Sqlcache_storeCommitOne(uw_Sqlcache_Cache *cache, char **keys, uw } static void uw_Sqlcache_flushCommitOne(uw_Sqlcache_Cache *cache, char **keys) { + (void)cache; + (void)keys; } static void uw_Sqlcache_commit(void *data) { @@ -4854,6 +4937,7 @@ static void uw_Sqlcache_commit(void *data) { } static void uw_Sqlcache_free(void *data, int dontCare) { + (void)dontCare; uw_context ctx = (uw_context)data; uw_Sqlcache_Update *update = ctx->cacheUpdate; while (update) { @@ -4929,6 +5013,7 @@ void uw_Sqlcache_store(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys, uw } void uw_Sqlcache_flush(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) { + (void)ctx; // A flush has to happen immediately so that subsequent stores in the same transaction fail. // This is safe to do because we will always call [uw_Sqlcache_wlock] earlier. // If the transaction fails, the only harm done is a few extra cache misses. -- cgit v1.2.3 From 1c493e9ec47f4754dd7237078e8c4f3300925ce3 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Tue, 29 May 2018 09:49:22 -0400 Subject: Remove insecure crypto function (closes #114) --- include/urweb/urweb_cpp.h | 2 -- lib/ur/basis.urs | 5 ----- src/c/urweb.c | 5 ----- 3 files changed, 12 deletions(-) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 0d5f5e0e..2c60a781 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -358,8 +358,6 @@ uw_Basis_string uw_Basis_timef(struct uw_context *, const char *fmt, uw_Basis_ti uw_Basis_time uw_Basis_stringToTimef(struct uw_context *, const char *fmt, uw_Basis_string); uw_Basis_time uw_Basis_stringToTimef_error(struct uw_context *, const char *fmt, uw_Basis_string); -uw_Basis_string uw_Basis_crypt(struct uw_context *, uw_Basis_string key, uw_Basis_string salt); - uw_Basis_bool uw_Basis_eq_time(struct uw_context *, uw_Basis_time, uw_Basis_time); uw_Basis_bool uw_Basis_lt_time(struct uw_context *, uw_Basis_time, uw_Basis_time); uw_Basis_bool uw_Basis_le_time(struct uw_context *, uw_Basis_time, uw_Basis_time); diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index c354d784..dc1b9b76 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -192,11 +192,6 @@ val datetimeSecond : time -> int val datetimeDayOfWeek : time -> int -(** * Encryption *) - -val crypt : string -> string -> string - - (** HTTP operations *) con http_cookie :: Type -> Type diff --git a/src/c/urweb.c b/src/c/urweb.c index 504597ef..283efcdd 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4490,11 +4490,6 @@ failure_kind uw_runCallback(uw_context ctx, void (*callback)(uw_context)) { return r; } -uw_Basis_string uw_Basis_crypt(uw_context ctx, uw_Basis_string key, uw_Basis_string salt) { - char buf[14]; - return uw_strdup(ctx, DES_fcrypt(key, salt, buf)); -} - uw_Basis_bool uw_Basis_eq_time(uw_context ctx, uw_Basis_time t1, uw_Basis_time t2) { (void)ctx; return !!(t1.seconds == t2.seconds && t1.microseconds == t2.microseconds); -- cgit v1.2.3 From f3373fd5809689bece7fd390f2d737aa0b43f594 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Sun, 3 Jun 2018 15:01:24 -0400 Subject: 'filecache' .urp directive, fixing a longstanding MonoUtil bug in the process --- doc/manual.tex | 1 + include/urweb/types_cpp.h | 1 + include/urweb/urweb_cpp.h | 4 + src/c/urweb.c | 126 ++++++++++++++++++++++++- src/cjr_print.sml | 24 ++++- src/compiler.sig | 3 + src/compiler.sml | 19 +++- src/demo.sml | 1 + src/filecache.sig | 35 +++++++ src/filecache.sml | 230 ++++++++++++++++++++++++++++++++++++++++++++++ src/mono_util.sml | 6 +- src/mysql.sml | 3 +- src/postgres.sml | 3 +- src/settings.sig | 6 +- src/settings.sml | 10 +- src/sources | 3 + src/sqlite.sml | 3 +- tests/dbupload.urp | 1 + tests/dbuploadOpt.ur | 27 ++++++ tests/dbuploadOpt.urp | 7 ++ 20 files changed, 501 insertions(+), 12 deletions(-) create mode 100644 src/filecache.sig create mode 100644 src/filecache.sml create mode 100644 tests/dbuploadOpt.ur create mode 100644 tests/dbuploadOpt.urp (limited to 'src/c/urweb.c') diff --git a/doc/manual.tex b/doc/manual.tex index 985dab5b..857539db 100644 --- a/doc/manual.tex +++ b/doc/manual.tex @@ -151,6 +151,7 @@ Here is the complete list of directive forms. ``FFI'' stands for ``foreign func \item \texttt{exe FILENAME} sets the filename to which to write the output executable. The default for file \texttt{P.urp} is \texttt{P.exe}. \item \texttt{file URI FILENAME} asks for the application executable to respond to requests for \texttt{URI} by serving a snapshot of the contents of \texttt{FILENAME} as of compile time. That is, the file contents are baked into the executable. System file \texttt{/etc/mime.types} is consulted (again, at compile time) to figure out the right MIME type to suggest in the HTTP response. \item \texttt{file URI FILENAME MIME-TYPE} works like the simpler form of \texttt{file}, but the proper MIME type for the file is given directly. +\item \texttt{filecache PATH} sets a path to a directory to use for caching files stored in the SQL database. It can be expensive to schlep files back and forth between the database and an Ur/Web application, since database engines don't tend to be optimized for transferring large files. Ur/Web will still store the files in the database, as the ``version of record'' for your whole, consistent data set, but the application will try to query the database only in terms of cryptographic hashes, from which files can be retrieved from the cache. (This feature is currently only available for PostgreSQL, with the module \texttt{pgcrypto} installed, to drive SHA512 hashing. It would defeat the purpose to run the hashing operation in the application rather than the database engine!) \item \texttt{ffi FILENAME} reads the file \texttt{FILENAME.urs} to determine the interface to a new FFI module. The name of the module is calculated from \texttt{FILENAME} in the same way as for normal source files. See the files \texttt{include/urweb/urweb\_cpp.h} and \texttt{src/c/urweb.c} for examples of C headers and implementations for FFI modules. In general, every type or value \texttt{Module.ident} becomes \texttt{uw\_Module\_ident} in C. \item \texttt{html5} asks to generate HTML5 code, which primarily affects the first few lines of the output documents, like the \texttt{DOCTYPE}. This option is on by default. \item \texttt{include FILENAME} adds \texttt{FILENAME} to the list of files to be \texttt{\#include}d in C sources. This is most useful for interfacing with new FFI modules. diff --git a/include/urweb/types_cpp.h b/include/urweb/types_cpp.h index 2fa473ac..0c546d1c 100644 --- a/include/urweb/types_cpp.h +++ b/include/urweb/types_cpp.h @@ -105,6 +105,7 @@ typedef struct { uw_Basis_string time_format; int is_html5; + char *file_cache; } uw_app; typedef struct { diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 2c60a781..5f1144b8 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -430,4 +430,8 @@ void *uw_Sqlcache_flush(struct uw_context *, uw_Sqlcache_Cache *, char **); int strcmp_nullsafe(const char *, const char *); +uw_unit uw_Basis_cache_file(struct uw_context *, uw_Basis_blob contents); +uw_Basis_blob uw_Basis_check_filecache(struct uw_context *, uw_Basis_string hash); +uw_Basis_bool uw_Basis_filecache_missed(struct uw_context *); + #endif diff --git a/src/c/urweb.c b/src/c/urweb.c index 283efcdd..e7efae38 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include #include #include @@ -514,6 +514,11 @@ struct uw_context { uw_Sqlcache_Unlock *cacheUnlock; int remoteSock; + + int file_cache_missed; + // Set if we are recovering from a miss in the file cache in handling an SQL + // query that only returns hashes of files. If so, this time around we will + // run queries to return actual file contents instead. }; size_t uw_headers_max = SIZE_MAX; @@ -608,6 +613,8 @@ uw_context uw_init(int id, uw_loggers *lg) { ctx->cacheUnlock = NULL; + ctx->file_cache_missed = 0; + return ctx; } @@ -3643,6 +3650,8 @@ int uw_commit(uw_context ctx) { } } + ctx->file_cache_missed = 0; + return 0; } @@ -5058,3 +5067,118 @@ int strcmp_nullsafe(const char *str1, const char *str2) { else return 1; } + +static int is_valid_hash(uw_Basis_string hash) { + for (; *hash; ++hash) + if (!isxdigit(*hash)) + return 0; + + return 1; +} + +uw_unit uw_Basis_cache_file(uw_context ctx, uw_Basis_blob contents) { + char *dir = ctx->app->file_cache, path[1024], tempfile[1024]; + unsigned char *res, *hash; + char *hash_encoded; + int fd, len, i; + ssize_t written_so_far = 0; + + if (!dir) + return uw_unit_v; + + hash = uw_malloc(ctx, SHA512_DIGEST_LENGTH); + res = SHA512((unsigned char *)contents.data, contents.size, hash); + if (!res) + uw_error(ctx, FATAL, "Can't hash file contents"); + + hash_encoded = uw_malloc(ctx, SHA512_DIGEST_LENGTH * 2 + 1); + for (i = 0; i < SHA512_DIGEST_LENGTH; ++i) + sprintf(hash_encoded + 2 * i, "%02x", (int)hash[i]); + hash_encoded[SHA512_DIGEST_LENGTH * 2] = 0; + + len = snprintf(tempfile, sizeof tempfile, "%s/tmpXXXXXX", dir); + if (len < 0 || len >= sizeof tempfile) + uw_error(ctx, FATAL, "Error assembling file path for cache (temporary)"); + + fd = mkstemp(tempfile); + if (fd < 0) + uw_error(ctx, FATAL, "Error creating temporary file for cache"); + + while (written_so_far < contents.size) { + ssize_t written_just_now = write(fd, contents.data + written_so_far, contents.size - written_so_far); + if (written_just_now <= 0) { + close(fd); + uw_error(ctx, FATAL, "Error writing all bytes to cached file"); + } + written_so_far += written_just_now; + } + + close(fd); + + len = snprintf(path, sizeof path, "%s/%s", dir, hash_encoded); + if (len < 0 || len >= sizeof path) + uw_error(ctx, FATAL, "Error assembling file path for cache"); + + if (rename(tempfile, path)) + uw_error(ctx, FATAL, "Error renaming temporary file into cache"); + + return uw_unit_v; +} + +uw_Basis_blob uw_Basis_check_filecache(uw_context ctx, uw_Basis_string hash) { + char path[1024], *dir = ctx->app->file_cache, *filedata; + int len; + long size, read_so_far = 0; + FILE *fp; + uw_Basis_blob res; + + // Hashes come formatted for printing by Postgres, which means they start with + // two extra characters. Let's remove them. + if (!hash[0] || !hash[1]) + uw_error(ctx, FATAL, "Hash to check against file cache came in not in Postgres format: %s", hash); + hash += 2; + + if (!dir) + uw_error(ctx, FATAL, "Checking file cache when no directory is set"); + + if (!is_valid_hash(hash)) + uw_error(ctx, FATAL, "Checking file cache with invalid hash %s", hash); + + len = snprintf(path, sizeof path, "%s/%s", dir, hash); + if (len < 0 || len >= sizeof path) + uw_error(ctx, FATAL, "Error assembling file path for cache"); + + fp = fopen(path, "r"); + if (!fp) { + ctx->file_cache_missed = 1; + uw_error(ctx, UNLIMITED_RETRY, "Missed in the file cache for hash %s", hash); + } + uw_push_cleanup(ctx, (void (*)(void *))fclose, fp); + + if (fseek(fp, 0L, SEEK_END)) + uw_error(ctx, FATAL, "Error seeking to end of cached file"); + + size = ftell(fp); + if (size < 0) + uw_error(ctx, FATAL, "Error getting size of cached file"); + + rewind(fp); + filedata = uw_malloc(ctx, size); + + while (read_so_far < size) { + size_t just_read = fread(filedata + read_so_far, 1, size - read_so_far, fp); + if (just_read <= 0) + uw_error(ctx, FATAL, "Error reading all bytes of cached file"); + read_so_far += just_read; + } + + uw_pop_cleanup(ctx); + + res.size = size; + res.data = filedata; + return res; +} + +uw_Basis_bool uw_Basis_filecache_missed(uw_context ctx) { + return !!(ctx->file_cache_missed); +} diff --git a/src/cjr_print.sml b/src/cjr_print.sml index 43265fb8..c83da031 100644 --- a/src/cjr_print.sml +++ b/src/cjr_print.sml @@ -2189,6 +2189,25 @@ and p_exp' par tail env (e, loc) = string ";"]) inputs, newline, + case Settings.getFileCache () of + NONE => box [] + | SOME _ => + p_list_sepi newline + (fn i => fn (_, t) => + case t of + Settings.Blob => + box [string "uw_Basis_cache_file(ctx, arg", + string (Int.toString (i + 1)), + string ");"] + | Settings.Nullable Settings.Blob => + box [string "if (arg", + string (Int.toString (i + 1)), + string ") uw_Basis_cache_file(ctx, arg", + string (Int.toString (i + 1)), + string ");"] + | _ => box []) + inputs, + newline, string "uw_ensure_transaction(ctx);", newline, newline, @@ -3677,7 +3696,10 @@ fun p_file env (ds, ps) = "uw_input_num", "uw_cookie_sig", "uw_check_url", "uw_check_mime", "uw_check_requestHeader", "uw_check_responseHeader", "uw_check_envVar", "uw_check_meta", case onError of NONE => "NULL" | SOME _ => "uw_onError", "my_periodics", "\"" ^ Prim.toCString (Settings.getTimeFormat ()) ^ "\"", - if Settings.getIsHtml5 () then "1" else "0"], + if Settings.getIsHtml5 () then "1" else "0", + (case Settings.getFileCache () of + NONE => "NULL" + | SOME s => "\"" ^ Prim.toCString s ^ "\"")], string "};", newline] end diff --git a/src/compiler.sig b/src/compiler.sig index 0ff84f1c..bcf69fd4 100644 --- a/src/compiler.sig +++ b/src/compiler.sig @@ -60,6 +60,7 @@ signature COMPILER = sig protocol : string option, dbms : string option, sigFile : string option, + fileCache : string option, safeGets : string list, onError : (string * string list * string) option, minHeap : int, @@ -125,6 +126,7 @@ signature COMPILER = sig val pathcheck : (Mono.file, Mono.file) phase val sidecheck : (Mono.file, Mono.file) phase val sigcheck : (Mono.file, Mono.file) phase + val filecache : (Mono.file, Mono.file) phase val sqlcache : (Mono.file, Mono.file) phase val cjrize : (Mono.file, Cjr.file) phase val prepare : (Cjr.file, Cjr.file) phase @@ -191,6 +193,7 @@ signature COMPILER = sig val toPathcheck : (string, Mono.file) transform val toSidecheck : (string, Mono.file) transform val toSigcheck : (string, Mono.file) transform + val toFilecache : (string, Mono.file) transform val toSqlcache : (string, Mono.file) transform val toCjrize : (string, Cjr.file) transform val toPrepare : (string, Cjr.file) transform diff --git a/src/compiler.sml b/src/compiler.sml index 3fb0b767..f724bf56 100644 --- a/src/compiler.sml +++ b/src/compiler.sml @@ -64,6 +64,7 @@ type job = { protocol : string option, dbms : string option, sigFile : string option, + fileCache : string option, safeGets : string list, onError : (string * string list * string) option, minHeap : int, @@ -388,6 +389,7 @@ fun institutionalizeJob (job : job) = Settings.setOnError (#onError job); Settings.setMinHeap (#minHeap job); Settings.setSigFile (#sigFile job); + Settings.setFileCache (#fileCache job); Settings.setMimeFilePath (Option.getOpt (#mimeTypes job, "/etc/mime.types"))) datatype commentableLine = @@ -467,6 +469,7 @@ fun parseUrp' accLibs fname = protocol = NONE, dbms = NONE, sigFile = NONE, + fileCache = NONE, safeGets = [], onError = NONE, minHeap = 0, @@ -601,6 +604,7 @@ fun parseUrp' accLibs fname = val protocol = ref NONE val dbms = ref NONE val sigFile = ref (Settings.getSigFile ()) + val fileCache = ref (Settings.getFileCache ()) val safeGets = ref [] val onError = ref NONE val minHeap = ref 0 @@ -640,6 +644,7 @@ fun parseUrp' accLibs fname = protocol = !protocol, dbms = !dbms, sigFile = !sigFile, + fileCache = !fileCache, safeGets = rev (!safeGets), onError = !onError, minHeap = !minHeap, @@ -702,6 +707,7 @@ fun parseUrp' accLibs fname = protocol = mergeO #2 (#protocol old, #protocol new), dbms = mergeO #2 (#dbms old, #dbms new), sigFile = mergeO #2 (#sigFile old, #sigFile new), + fileCache = mergeO #2 (#fileCache old, #fileCache new), safeGets = #safeGets old @ #safeGets new, onError = mergeO #2 (#onError old, #onError new), minHeap = Int.max (#minHeap old, #minHeap new), @@ -790,6 +796,10 @@ fun parseUrp' accLibs fname = (case !sigFile of NONE => sigFile := SOME arg | SOME _ => ()) + | "filecache" => + (case !fileCache of + NONE => fileCache := SOME arg + | SOME _ => ()) | "exe" => (case !exe of NONE => exe := SOME (relify arg) @@ -1513,6 +1523,13 @@ val sigcheck = { val toSigcheck = transform sigcheck "sigcheck" o toSidecheck +val filecache = { + func = FileCache.instrument, + print = MonoPrint.p_file MonoEnv.empty +} + +val toFilecache = transform filecache "filecache" o toSigcheck + val sqlcache = { func = (fn file => if Settings.getSqlcache () @@ -1521,7 +1538,7 @@ val sqlcache = { print = MonoPrint.p_file MonoEnv.empty } -val toSqlcache = transform sqlcache "sqlcache" o toSigcheck +val toSqlcache = transform sqlcache "sqlcache" o toFilecache val cjrize = { func = Cjrize.cjrize, diff --git a/src/demo.sml b/src/demo.sml index a682d28d..1e58e2f8 100644 --- a/src/demo.sml +++ b/src/demo.sml @@ -123,6 +123,7 @@ fun make' {prefix, dirname, guided} = protocol = mergeWith #2 (#protocol combined, #protocol urp), dbms = mergeWith #2 (#dbms combined, #dbms urp), sigFile = mergeWith #2 (#sigFile combined, #sigFile urp), + fileCache = mergeWith #2 (#fileCache combined, #fileCache urp), safeGets = #safeGets combined @ #safeGets urp, onError = NONE, minHeap = 0, diff --git a/src/filecache.sig b/src/filecache.sig new file mode 100644 index 00000000..db57135f --- /dev/null +++ b/src/filecache.sig @@ -0,0 +1,35 @@ +(* Copyright (c) 2013, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +(* Instrument to check a cache in the file system, to reconsitute blobs without + * silly shipping over an SQL connection. *) + +signature FILE_CACHE = sig + + val instrument : Mono.file -> Mono.file + +end diff --git a/src/filecache.sml b/src/filecache.sml new file mode 100644 index 00000000..e2291c10 --- /dev/null +++ b/src/filecache.sml @@ -0,0 +1,230 @@ +(* Copyright (c) 2013, Adam Chlipala + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - The names of contributors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + *) + +structure FileCache :> FILE_CACHE = struct + +open Mono + +structure SS = BinarySetFn(struct + type ord_key = string + val compare = String.compare + end) + +val hasBlob = + MonoUtil.Typ.exists (fn TFfi ("Basis", "blob") => true + | _ => false) + +val unBlob = + MonoUtil.Typ.map (fn TFfi ("Basis", "blob") => TFfi ("Basis", "string") + | t => t) + +fun nodups (exps : (string * typ) list, tables : (string * (string * typ) list) list) = + let + val cols = map #1 exps @ ListUtil.mapConcat (map #1 o #2) tables + + val (_, good) = + foldl (fn (name, (names, good)) => + if SS.member(names, name) then + (names, false) + else + (SS.add (names, name), good)) (SS.empty, true) cols + in + good + end + +fun instrument file = + let + fun exp e = + case e of + EQuery {exps, tables, state, query, body, initial} => + if (List.exists (hasBlob o #2) exps + orelse List.exists (List.exists (hasBlob o #2) o #2) tables) + andalso nodups (exps, tables) then + let + val exps = ListMergeSort.sort + (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) + exps + val tables = ListMergeSort.sort + (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) + tables + val tables = map (fn (x, xts) => + (x, ListMergeSort.sort + (fn ((x, _), (y, _)) => String.compare (x, y) = GREATER) + xts)) tables + + val loc = #2 query + + fun wrapCol (name, t) = + case #1 t of + TFfi ("Basis", "blob") => + "DIGEST(" ^ name ^ ", 'sha512')" + | TOption t' => wrapCol (name, t') + | _ => name + + val mangle = Settings.mangleSql + + val cols = map (fn (name, t) => (mangle name, t)) exps + @ ListUtil.mapConcat (fn (_, cols) => + map (fn (name, t) => + (mangle name, + t)) cols) tables + + val prequery = + "SELECT " + ^ String.concatWith ", " (map wrapCol cols) + ^ " FROM (" + + val postquery = + ") AS Wrap" + + val wrapped_query = + (EStrcat ((EPrim (Prim.String (Prim.Normal, prequery)), loc), + (EStrcat (query, + (EPrim (Prim.String (Prim.Normal, postquery)), loc)), loc)), loc) + val wrapped_query = MonoOpt.optExp wrapped_query + + val exps' = map (fn (name, t) => (name, unBlob t)) exps + val tables' = map (fn (name, cols) => + (name, + map (fn (cname, t) => (cname, unBlob t)) cols)) tables + + val blob = (TFfi ("Basis", "blob"), loc) + val string = (TFfi ("Basis", "string"), loc) + + fun trycache (name, e, t : typ) = + (name, + case #1 t of + TFfi ("Basis", "blob") => + (EFfiApp ("Basis", + "check_filecache", + [(e, string)]), loc) + | TOption (TFfi ("Basis", "blob"), _) => + (ECase (e, + [((PNone string, loc), + (ENone blob, loc)), + ((PSome (string, (PVar ("hash", string), loc)), loc), + (ESome (blob, + (EFfiApp ("Basis", + "check_filecache", + [((ERel 0, loc), string)]), loc)), loc))], + {disc = (TOption string, loc), + result = (TOption blob, loc)}), loc) + | _ => e, + t) + + val wrapped_body_trycache = + (ELet ("uncached", + (TRecord (exps @ map (fn (name, cols) => + (name, (TRecord cols, loc))) tables), + loc), + (ERecord (map (fn (name, t) => + trycache (name, + (EField ((ERel 1, loc), + name), loc), + t)) exps + @ map (fn (tname, cols) => + (tname, + (ERecord (map (fn (name, t) => + trycache (name, + (EField ((EField ((ERel 1, loc), tname), loc), name), loc), + t)) cols), loc), + (TRecord cols, loc))) tables), loc), + MonoEnv.subExpInExp (2, (ERel 0, loc)) + + + (MonoEnv.liftExpInExp 0 body)), loc) + + fun maybeadd (e, t, acc) = + case #1 t of + TFfi ("Basis", "blob") => + (ESeq ((EFfiApp ("Basis", + "cache_file", + [(e, blob)]), loc), + acc), loc) + | TOption (TFfi ("Basis", "blob"), _) => + (ESeq ((ECase (e, + [((PNone blob, loc), + (ERecord [], loc)), + ((PSome (blob, (PVar ("blob", blob), loc)), loc), + (EFfiApp ("Basis", + "cache_file", + [((ERel 0, loc), blob)]), loc))], + {disc = t, + result = (TRecord [], loc)}), loc), + acc), loc) + | _ => acc + + val wrapped_body_addtocache = + foldl (fn ((name, t), e) => + maybeadd ((EField ((ERel 1, loc), name), loc), + t, e)) + (foldl (fn ((tname, cols), e) => + foldl (fn ((name, t), e) => + maybeadd ((EField ((EField ((ERel 1, loc), tname), loc), name), loc), + t, e)) e cols) body tables) + exps + in + ECase ((EFfiApp ("Basis", "filecache_missed", []), loc), + [((PCon (Enum, + PConFfi {mod = "Basis", + datatyp = "bool", + con = "False", + arg = NONE}, + NONE), loc), + (EQuery {exps = exps', + tables = tables', + state = state, + query = wrapped_query, + body = wrapped_body_trycache, + initial = initial}, loc)), + ((PCon (Enum, + PConFfi {mod = "Basis", + datatyp = "bool", + con = "True", + arg = NONE}, + NONE), loc), + (EQuery {exps = exps, + tables = tables, + state = state, + query = query, + body = wrapped_body_addtocache, + initial = initial}, loc))], + {disc = (TFfi ("Basis", "bool"), loc), + result = state}) + end + else + e + | _ => e + in + case Settings.getFileCache () of + NONE => file + | SOME _ => MonoUtil.File.map {typ = fn t => t, + exp = exp, + decl = fn d => d} file + end + +end diff --git a/src/mono_util.sml b/src/mono_util.sml index fc1a2bcb..fdf48d20 100644 --- a/src/mono_util.sml +++ b/src/mono_util.sml @@ -107,16 +107,16 @@ fun mapfold fc = | TOption t => S.map2 (mft t, fn t' => - (TOption t, loc)) + (TOption t', loc)) | TList t => S.map2 (mft t, fn t' => - (TList t, loc)) + (TList t', loc)) | TSource => S.return2 cAll | TSignal t => S.map2 (mft t, fn t' => - (TSignal t, loc)) + (TSignal t', loc)) in mft end diff --git a/src/mysql.sml b/src/mysql.sml index 52e4921e..e7cad84e 100644 --- a/src/mysql.sml +++ b/src/mysql.sml @@ -1609,6 +1609,7 @@ val () = addDbms {name = "mysql", onlyUnion = true, nestedRelops = false, windowFunctions = false, - supportsIsDistinctFrom = true} + supportsIsDistinctFrom = true, + supportsSHA512 = false} end diff --git a/src/postgres.sml b/src/postgres.sml index fac913f0..2b6bee8c 100644 --- a/src/postgres.sml +++ b/src/postgres.sml @@ -1153,7 +1153,8 @@ val () = addDbms {name = "postgres", onlyUnion = false, nestedRelops = true, windowFunctions = true, - supportsIsDistinctFrom = true} + supportsIsDistinctFrom = true, + supportsSHA512 = true} val () = setDbms "postgres" diff --git a/src/settings.sig b/src/settings.sig index 729218ac..986d6ed7 100644 --- a/src/settings.sig +++ b/src/settings.sig @@ -219,7 +219,8 @@ signature SETTINGS = sig onlyUnion : bool, nestedRelops : bool, windowFunctions : bool, - supportsIsDistinctFrom : bool + supportsIsDistinctFrom : bool, + supportsSHA512 : bool } val addDbms : dbms -> unit @@ -253,6 +254,9 @@ signature SETTINGS = sig val setSigFile : string option -> unit val getSigFile : unit -> string option + val setFileCache : string option -> unit + val getFileCache : unit -> string option + (* Which GET-able functions should be allowed to have side effects? *) val setSafeGets : string list -> unit val isSafeGet : string -> bool diff --git a/src/settings.sml b/src/settings.sml index 9e6d3e76..47a88932 100644 --- a/src/settings.sml +++ b/src/settings.sml @@ -646,7 +646,8 @@ type dbms = { onlyUnion : bool, nestedRelops : bool, windowFunctions: bool, - supportsIsDistinctFrom : bool + supportsIsDistinctFrom : bool, + supportsSHA512 : bool } val dbmses = ref ([] : dbms list) @@ -679,7 +680,8 @@ val curDb = ref ({name = "", onlyUnion = false, nestedRelops = false, windowFunctions = false, - supportsIsDistinctFrom = false} : dbms) + supportsIsDistinctFrom = false, + supportsSHA512 = false} : dbms) fun addDbms v = dbmses := v :: !dbmses fun setDbms s = @@ -724,6 +726,10 @@ val sigFile = ref (NONE : string option) fun setSigFile v = sigFile := v fun getSigFile () = !sigFile +val fileCache = ref (NONE : string option) +fun setFileCache v = fileCache := v +fun getFileCache () = !fileCache + structure SS = BinarySetFn(struct type ord_key = string val compare = String.compare diff --git a/src/sources b/src/sources index 52b1bdd7..5c0b2a84 100644 --- a/src/sources +++ b/src/sources @@ -231,6 +231,9 @@ $(SRC)/sidecheck.sml $(SRC)/sigcheck.sig $(SRC)/sigcheck.sml +$(SRC)/filecache.sig +$(SRC)/filecache.sml + $(SRC)/mono_inline.sml $(SRC)/sha1.sig diff --git a/src/sqlite.sml b/src/sqlite.sml index 0acd866b..db7052d1 100644 --- a/src/sqlite.sml +++ b/src/sqlite.sml @@ -855,6 +855,7 @@ val () = addDbms {name = "sqlite", onlyUnion = false, nestedRelops = false, windowFunctions = false, - supportsIsDistinctFrom = false} + supportsIsDistinctFrom = false, + supportsSHA512 = false} end diff --git a/tests/dbupload.urp b/tests/dbupload.urp index dd8417d1..daa68e2c 100644 --- a/tests/dbupload.urp +++ b/tests/dbupload.urp @@ -2,5 +2,6 @@ database dbname=dbupload sql dbupload.sql allow mime * rewrite all Dbupload/* +filecache /tmp/files dbupload diff --git a/tests/dbuploadOpt.ur b/tests/dbuploadOpt.ur new file mode 100644 index 00000000..466b49f3 --- /dev/null +++ b/tests/dbuploadOpt.ur @@ -0,0 +1,27 @@ +table t : { Id : int, Blob : option blob, MimeType : string } +sequence s + +fun getImage id : transaction page = + r <- oneRow1 (SELECT t.Blob, t.MimeType + FROM t + WHERE t.Id = {[id]}); + case r.Blob of + None => error Oh no! + | Some blob => returnBlob blob (blessMime r.MimeType) + +fun main () : transaction page = + let + fun handle r = + id <- nextval s; + dml (INSERT INTO t (Id, Blob, MimeType) + VALUES ({[id]}, {[if fileMimeType r.File = "image/jpeg" then Some (fileData r.File) else None]}, {[fileMimeType r.File]})); + main () + in + x <- queryX1 (SELECT t.Id FROM t) + (fn r =>
); + return +
+
+ {x} +
+ end diff --git a/tests/dbuploadOpt.urp b/tests/dbuploadOpt.urp new file mode 100644 index 00000000..816bcea1 --- /dev/null +++ b/tests/dbuploadOpt.urp @@ -0,0 +1,7 @@ +database dbname=dbuploadOpt +sql dbuploadOpt.sql +allow mime * +rewrite all DbuploadOpt/* +filecache /tmp/files + +dbuploadOpt -- cgit v1.2.3 From eb86dffeeec897d17905f3adff84e6acfd018330 Mon Sep 17 00:00:00 2001 From: Denis Redozubov Date: Wed, 22 Aug 2018 15:11:32 +0300 Subject: Rough same page anchors --- include/urweb/urweb_cpp.h | 1 + lib/js/urweb.js | 4 ++++ lib/ur/basis.urs | 1 + src/c/urweb.c | 4 ++++ src/settings.sml | 1 + 5 files changed, 11 insertions(+) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 5f1144b8..1351cfbc 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -242,6 +242,7 @@ uw_Basis_string uw_Basis_blessEnvVar(struct uw_context *, uw_Basis_string); uw_Basis_string uw_Basis_blessMeta(struct uw_context *, uw_Basis_string); uw_Basis_string uw_Basis_checkUrl(struct uw_context *, uw_Basis_string); +uw_Basis_string uw_Basis_anchorUrl(struct uw_context *, uw_Basis_string); uw_Basis_string uw_Basis_checkMime(struct uw_context *, uw_Basis_string); uw_Basis_string uw_Basis_checkRequestHeader(struct uw_context *, uw_Basis_string); uw_Basis_string uw_Basis_checkResponseHeader(struct uw_context *, uw_Basis_string); diff --git a/lib/js/urweb.js b/lib/js/urweb.js index ff4c7b7e..cd1b7005 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -2278,5 +2278,9 @@ function giveFocus(id) { er("Tried to give focus to ID not used in document: " + id); } +function anchorUrl(id) { + return "#" + id; +} + // App-specific code diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index 3b67946f..a416ba48 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -803,6 +803,7 @@ type id val fresh : transaction id val giveFocus : id -> transaction unit val show_id : show id +val anchorUrl : id -> url val dyn : ctx ::: {Unit} -> use ::: {Type} -> bind ::: {Type} -> [ctx ~ [Dyn]] => unit -> tag [Signal = signal (xml ([Dyn] ++ ctx) use bind)] ([Dyn] ++ ctx) [] use bind diff --git a/src/c/urweb.c b/src/c/urweb.c index e7efae38..ce6f4dfb 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4407,6 +4407,10 @@ uw_Basis_string uw_Basis_currentUrl(uw_context ctx) { return ctx->current_url; } +uw_Basis_string uw_Basis_anchorUrl(uw_context ctx, uw_Basis_string s) { + return uw_Basis_strcat(ctx, uw_Basis_strcat(ctx, ctx->current_url, "#"), s); +} + void uw_set_currentUrl(uw_context ctx, char *s) { ctx->current_url = s; } diff --git a/src/settings.sml b/src/settings.sml index cfbe98a5..c023a851 100644 --- a/src/settings.sml +++ b/src/settings.sml @@ -321,6 +321,7 @@ val jsFuncsBase = basisM [("alert", "alert"), ("ord", "ord"), ("checkUrl", "checkUrl"), + ("anchorUrl", "anchorUrl"), ("bless", "bless"), ("blessData", "blessData"), -- cgit v1.2.3 From d800556bd50ecb78c21343a288f9475b8b870162 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Fri, 19 Oct 2018 15:55:17 -0400 Subject: Just return None rather than crashing, when trying to read cookies within tasks (closes #143) --- src/c/urweb.c | 5 ++++- tests/task_cookie.ur | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/task_cookie.ur (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index e7efae38..2e3e18bc 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -737,7 +737,10 @@ void uw_close(uw_context ctx) { } uw_Basis_string uw_Basis_requestHeader(uw_context ctx, uw_Basis_string h) { - return ctx->get_header(ctx->get_header_data, h); + if (ctx->get_header) + return ctx->get_header(ctx->get_header_data, h); + else + return NULL; } void uw_set_headers(uw_context ctx, char *(*get_header)(void *, const char *), void *get_header_data) { diff --git a/tests/task_cookie.ur b/tests/task_cookie.ur new file mode 100644 index 00000000..39f49b0a --- /dev/null +++ b/tests/task_cookie.ur @@ -0,0 +1,9 @@ +cookie myCookie: {Value: string} + +fun main (): transaction page = return + +task initialize = fn () => + c <- getCookie myCookie; + case c of + None => debug "No cookie" + | Some {Value = v} => debug ("Cookie value: " ^ v) -- cgit v1.2.3 From c2a217f9121dd865122bc6150c53e77bd662050d Mon Sep 17 00:00:00 2001 From: fab Date: Sat, 3 Nov 2018 20:09:20 +0000 Subject: utf-8 aware functions for basis. unit-testing. --- .travis.yml | 2 +- include/urweb/types_cpp.h | 3 +- src/c/Makefile.am | 2 +- src/c/urweb.c | 197 +++++++++++++------- src/compiler.sml | 4 +- tests/Makefile | 2 + tests/utf8.py | 449 ++++++++++++++++++++++++++++++++++++++++++++++ tests/utf8.ur | 431 ++++++++++++++++++++++++++++++++++++++++++++ tests/utf8.urp | 5 + 9 files changed, 1024 insertions(+), 71 deletions(-) create mode 100644 tests/utf8.py create mode 100644 tests/utf8.ur create mode 100644 tests/utf8.urp (limited to 'src/c/urweb.c') diff --git a/.travis.yml b/.travis.yml index df4e4abc..86d731cc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ compiler: before_install: - export CONFIGURE_ARGS="" - if command -v apt-get &>/dev/null; then sudo apt-get update -qq; fi - - if command -v apt-get &>/dev/null; then sudo apt-get install -y mlton; fi + - if command -v apt-get &>/dev/null; then sudo apt-get install -y mlton lib-icudev; fi - if command -v brew &>/dev/null; then brew update; fi - if command -v brew &>/dev/null; then brew uninstall libtool; fi - if command -v brew &>/dev/null; then brew install libtool; fi diff --git a/include/urweb/types_cpp.h b/include/urweb/types_cpp.h index 0c546d1c..c6c0dd3e 100644 --- a/include/urweb/types_cpp.h +++ b/include/urweb/types_cpp.h @@ -4,11 +4,12 @@ #include #include #include +#include typedef long long uw_Basis_int; typedef double uw_Basis_float; typedef char* uw_Basis_string; -typedef char uw_Basis_char; +typedef UChar32 uw_Basis_char; typedef struct { time_t seconds; unsigned microseconds; diff --git a/src/c/Makefile.am b/src/c/Makefile.am index 027b1458..96c1d92f 100644 --- a/src/c/Makefile.am +++ b/src/c/Makefile.am @@ -11,7 +11,7 @@ AM_CFLAGS = -Wall -Wunused-parameter -Werror -Wno-format-security -Wno-deprecate liburweb_la_LDFLAGS = $(AM_LDFLAGS) $(OPENSSL_LDFLAGS) \ -export-symbols-regex '^(client_pruner|pthread_create_big|strcmp_nullsafe|uw_.*)' \ -version-info 1:0:0 -liburweb_la_LIBADD = $(PTHREAD_LIBS) -lm $(OPENSSL_LIBS) +liburweb_la_LIBADD = $(PTHREAD_LIBS) -lm $(OPENSSL_LIBS) -licui18n -licuuc -licudata liburweb_http_la_LIBADD = liburweb.la liburweb_http_la_LDFLAGS = -export-symbols-regex '^(main|uw_.*)' \ -version-info 1:0:0 diff --git a/src/c/urweb.c b/src/c/urweb.c index 2e3e18bc..69c3da94 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -20,6 +20,9 @@ #include +#include +#include + #include "types.h" #include "uthash.h" @@ -2421,28 +2424,34 @@ uw_unit uw_Basis_htmlifySource_w(uw_context ctx, uw_Basis_source src) { return uw_unit_v; } -uw_Basis_char uw_Basis_strsub(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { +uw_Basis_char uw_Basis_strsub(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { + uw_Basis_char c; + int offset = 0; + while (n >= 0) { - if (*s == 0) + + if (s[offset] == 0) uw_error(ctx, FATAL, "Out-of-bounds strsub"); + U8_NEXT(s, offset, -1, c); + if (n == 0) - return *s; + return c; --n; - ++s; } uw_error(ctx, FATAL, "Negative strsub bound"); } uw_Basis_string uw_Basis_strsuffix(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { + int offset = 0; while (n >= 0) { - if (*s == 0 || n == 0) - return s; + if (s[offset] == 0 || n == 0) + return s + offset; + U8_FWD_1(s, offset, -1); --n; - ++s; } uw_error(ctx, FATAL, "Negative strsuffix bound"); @@ -2450,40 +2459,80 @@ uw_Basis_string uw_Basis_strsuffix(uw_context ctx, uw_Basis_string s, uw_Basis_i uw_Basis_int uw_Basis_strlen(uw_context ctx, uw_Basis_string s) { (void)ctx; - return strlen(s); + int offset = 0, iterations = 0; + while (s[offset] != 0) { + U8_FWD_1(s, offset, -1); + ++iterations; + } + return iterations; } uw_Basis_bool uw_Basis_strlenGe(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { (void)ctx; - + int offset = 0; while (n > 0) { - if (*s == 0) + if (s[offset] == 0) return uw_Basis_False; - + + U8_FWD_1(s, offset, -1); --n; - ++s; } return uw_Basis_True; } +int aux_strchr(uw_Basis_string s, uw_Basis_char ch, int* o_offset) { + int u8idx = 0, offset = 0; + uw_Basis_char c; + + while (s[offset] != 0) { + U8_NEXT(s, offset, -1, c); + if (c == ch) { + *o_offset = offset; + return u8idx; + } + + ++u8idx; + } + + *o_offset = -1; + return -1; +} + uw_Basis_string uw_Basis_strchr(uw_context ctx, uw_Basis_string s, uw_Basis_char ch) { (void)ctx; - return strchr(s, ch); + int offset = -1; + if (aux_strchr(s, ch, &offset) > -1) { + return s + offset; + } + return NULL; } uw_Basis_int uw_Basis_strcspn(uw_context ctx, uw_Basis_string s, uw_Basis_string chs) { (void)ctx; - return strcspn(s, chs); + int offset = 0, u8idx = 0, offsetChs = 0; + uw_Basis_char c; + + while (s[offset] != 0) { + U8_NEXT(s, offset, -1, c); + if (aux_strchr(chs, c, &offsetChs) > -1) { + return u8idx; + } + ++u8idx; + } + + return u8idx; } uw_Basis_int *uw_Basis_strindex(uw_context ctx, uw_Basis_string s, uw_Basis_char ch) { - uw_Basis_string r = strchr(s, ch); - if (r == NULL) + (void)ctx; + int offset = -1; + int r = aux_strchr(s, ch, &offset); + if (r == -1) return NULL; else { uw_Basis_int *nr = uw_malloc(ctx, sizeof(uw_Basis_int)); - *nr = r - s; + *nr = r; return nr; } } @@ -2494,13 +2543,19 @@ uw_Basis_int *uw_Basis_strsindex(uw_context ctx, const char *haystack, const cha return NULL; else { uw_Basis_int *nr = uw_malloc(ctx, sizeof(uw_Basis_int)); - *nr = r - haystack; + int src = r - haystack, offset = 0, utf8idx = 0; + while (offset < src) { + U8_FWD_1(haystack, offset, -1); + ++utf8idx; + } + + *nr = utf8idx; return nr; } } uw_Basis_string uw_Basis_strcat(uw_context ctx, uw_Basis_string s1, uw_Basis_string s2) { - int len = uw_Basis_strlen(ctx, s1) + uw_Basis_strlen(ctx, s2) + 1; + int len = strlen(s1) + strlen(s2) + 1; char *s; uw_check_heap(ctx, len); @@ -2515,8 +2570,8 @@ uw_Basis_string uw_Basis_strcat(uw_context ctx, uw_Basis_string s1, uw_Basis_str } uw_Basis_string uw_Basis_substring(uw_context ctx, uw_Basis_string s, uw_Basis_int start, uw_Basis_int len) { - size_t full_len = uw_Basis_strlen(ctx, s); - + int full_len = uw_Basis_strlen(ctx, s); + if (start < 0) uw_error(ctx, FATAL, "substring: Negative start index"); if (len < 0) @@ -2524,32 +2579,41 @@ uw_Basis_string uw_Basis_substring(uw_context ctx, uw_Basis_string s, uw_Basis_i if (start + len > full_len) uw_error(ctx, FATAL, "substring: Start index plus length is too large"); - if (start + len == full_len) - return &s[start]; - else { - uw_Basis_string r = uw_malloc(ctx, len+1); - memcpy(r, s+start, len); - r[len] = 0; + int offset = 0; + U8_FWD_N(s, offset, -1, start); + + if (start + len == full_len) { + return s + offset; + } else { + int end = offset; + U8_FWD_N(s, end, -1, len); + + int actual_len = end - offset; + + uw_Basis_string r = uw_malloc(ctx, actual_len + 1); + memcpy(r, s + offset, actual_len); + r[actual_len] = 0; return r; } - } uw_Basis_string uw_Basis_str1(uw_context ctx, uw_Basis_char ch) { char *r; - - uw_check_heap(ctx, 2); + int req = U8_LENGTH(ch); + int offset = 0; + + uw_check_heap(ctx, req + 1); r = ctx->heap.front; - r[0] = ch; - r[1] = 0; - ctx->heap.front += 2; + U8_APPEND_UNSAFE(r, offset, ch); + r[req] = 0; - return r; + ctx->heap.front += req + 1; + return r; } uw_Basis_string uw_strdup(uw_context ctx, uw_Basis_string s1) { - int len = uw_Basis_strlen(ctx, s1) + 1; + int len = strlen(s1) + 1; char *s; uw_check_heap(ctx, len); @@ -2676,7 +2740,6 @@ uw_Basis_string uw_Basis_sqlifyString(uw_context ctx, uw_Basis_string s) { uw_Basis_string uw_Basis_sqlifyChar(uw_context ctx, uw_Basis_char c) { char *r, *s2; - uw_check_heap(ctx, 5 + uw_Estrings + strlen(uw_sqlsuffixChar)); r = s2 = ctx->heap.front; @@ -2934,10 +2997,7 @@ uw_Basis_string uw_Basis_floatToString(uw_context ctx, uw_Basis_float n) { } uw_Basis_string uw_Basis_charToString(uw_context ctx, uw_Basis_char ch) { - char *r = uw_malloc(ctx, 2); - r[0] = ch; - r[1] = 0; - return r; + return uw_Basis_str1(ctx, ch); } uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) { @@ -2997,11 +3057,12 @@ uw_Basis_char *uw_Basis_stringToChar(uw_context ctx, uw_Basis_string s) { uw_Basis_char *r = uw_malloc(ctx, 1); r[0] = 0; return r; - } else if (s[1] != 0) + } else if (uw_Basis_strlenGe(ctx, s, 2) == uw_Basis_True) return NULL; else { uw_Basis_char *r = uw_malloc(ctx, 1); - r[0] = s[0]; + int offset = 0; + U8_NEXT(s, offset, -1, *r); return r; } } @@ -3126,10 +3187,14 @@ uw_Basis_float uw_Basis_stringToFloat_error(uw_context ctx, uw_Basis_string s) { uw_Basis_char uw_Basis_stringToChar_error(uw_context ctx, uw_Basis_string s) { if (s[0] == 0) return 0; - else if (s[1] != 0) + else if (uw_Basis_strlenGe(ctx, s, 2) == uw_Basis_True) uw_error(ctx, FATAL, "Can't parse char: %s", uw_Basis_htmlifyString(ctx, s)); - else - return s[0]; + else { + uw_Basis_char c; + int offset = 0; + U8_NEXT(s, offset, -1, c); + return c; + } } uw_Basis_bool uw_Basis_stringToBool_error(uw_context ctx, uw_Basis_string s) { @@ -4328,82 +4393,82 @@ void uw_set_global(uw_context ctx, char *name, void *data, void (*free)(void*)) uw_Basis_bool uw_Basis_isalnum(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isalnum((int)c); + return !!u_hasBinaryProperty(c, UCHAR_POSIX_ALNUM); } uw_Basis_bool uw_Basis_isalpha(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isalpha((int)c); + return !!u_hasBinaryProperty(c, UCHAR_ALPHABETIC); } uw_Basis_bool uw_Basis_isblank(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isblank((int)c); + return !!u_hasBinaryProperty(c, UCHAR_POSIX_BLANK); } uw_Basis_bool uw_Basis_iscntrl(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!iscntrl((int)c); + return !!(u_charType(c)==U_CONTROL_CHAR); } uw_Basis_bool uw_Basis_isdigit(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isdigit((int)c); + return !!u_isdigit(c); } uw_Basis_bool uw_Basis_isgraph(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isgraph((int)c); + return !!u_hasBinaryProperty(c, UCHAR_POSIX_GRAPH); } uw_Basis_bool uw_Basis_islower(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!islower((int)c); + return !!u_hasBinaryProperty(c, UCHAR_LOWERCASE); } uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isprint((int)c); + return !!u_hasBinaryProperty(c, UCHAR_POSIX_PRINT); } uw_Basis_bool uw_Basis_ispunct(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!ispunct((int)c); + return !!u_ispunct(c); } uw_Basis_bool uw_Basis_isspace(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isspace((int)c); + return !!u_hasBinaryProperty(c, UCHAR_WHITE_SPACE); } uw_Basis_bool uw_Basis_isupper(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isupper((int)c); + return !!u_hasBinaryProperty(c, UCHAR_UPPERCASE); } uw_Basis_bool uw_Basis_isxdigit(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!isxdigit((int)c); + return !!u_hasBinaryProperty(c, UCHAR_POSIX_XDIGIT); } uw_Basis_char uw_Basis_tolower(uw_context ctx, uw_Basis_char c) { (void)ctx; - return tolower((int)c); + return u_tolower(c); } uw_Basis_char uw_Basis_toupper(uw_context ctx, uw_Basis_char c) { (void)ctx; - return toupper((int)c); + return u_toupper(c); } uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c) { (void)ctx; - return (unsigned char)c; + return (uw_Basis_int)c; } uw_Basis_char uw_Basis_chr(uw_context ctx, uw_Basis_int n) { (void)ctx; - return n; + return (uw_Basis_char)n; } uw_Basis_string uw_Basis_currentUrl(uw_context ctx) { @@ -4657,7 +4722,7 @@ uw_Basis_string uw_Basis_atom(uw_context ctx, uw_Basis_string s) { for (p = s; *p; ++p) { char c = *p; - if (!isalnum((int)c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#') + if (!U8_IS_SINGLE(c) && !isalnum((int)c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#') uw_error(ctx, FATAL, "Disallowed character in CSS atom"); } @@ -4669,7 +4734,7 @@ uw_Basis_string uw_Basis_css_url(uw_context ctx, uw_Basis_string s) { for (p = s; *p; ++p) { char c = *p; - if (!isalnum((int)c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' + if (!U8_IS_SINGLE(c) && !isalnum((int)c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' && c != '-' && c != '%' && c != '?' && c != '&' && c != '=' && c != '#') uw_error(ctx, FATAL, "Disallowed character in CSS URL"); } @@ -4688,7 +4753,7 @@ uw_Basis_string uw_Basis_property(uw_context ctx, uw_Basis_string s) { for (p = s; *p; ++p) { char c = *p; - if (!islower((int)c) && !isdigit((int)c) && c != '_' && c != '-') + if (!U8_IS_SINGLE(c) && !islower((int)c) && !isdigit((int)c) && c != '_' && c != '-') uw_error(ctx, FATAL, "Disallowed character in CSS property"); } @@ -5064,7 +5129,7 @@ void uw_Sqlcache_flush(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) { pthread_rwlock_unlock(&cache->lockIn); } -int strcmp_nullsafe(const char *str1, const char *str2) { +int strcmp_nullsafe(const char *str1, const char *str2) { if (str1) return strcmp(str1, str2); else @@ -5073,7 +5138,7 @@ int strcmp_nullsafe(const char *str1, const char *str2) { static int is_valid_hash(uw_Basis_string hash) { for (; *hash; ++hash) - if (!isxdigit(*hash)) + if (!U8_IS_SINGLE(*hash) && !isxdigit(*hash)) return 0; return 1; diff --git a/src/compiler.sml b/src/compiler.sml index f724bf56..9ee88c9b 100644 --- a/src/compiler.sml +++ b/src/compiler.sml @@ -1585,9 +1585,9 @@ fun compileC {cname, oname, ename, libs, profile, debug, linker, link = link'} = val proto = Settings.currentProtocol () val lib = if Settings.getBootLinking () then - !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a" + !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a -licui18n -licuuc -licudata" else if Settings.getStaticLinking () then - " -static " ^ !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a" + " -static " ^ !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a -licui18n -licuuc -licudata" else "-L" ^ !Settings.configLib ^ " " ^ #linkDynamic proto ^ " -lurweb" diff --git a/tests/Makefile b/tests/Makefile index ecf5557b..03e37e4b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -28,3 +28,5 @@ simple:: ./driver.sh fact ./driver.sh filter ./driver.sh jsbspace + ./driver.sh utf8 + diff --git a/tests/utf8.py b/tests/utf8.py new file mode 100644 index 00000000..ff9b737a --- /dev/null +++ b/tests/utf8.py @@ -0,0 +1,449 @@ +import unittest +import base + +class Suite(base.Base): + def test_1(self): + """Test case: substring (1)""" + self.start('Utf8/substrings') + + pre = self.xpath('pre[1]') + self.assertEqual('abc', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('bc', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('c', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('ábó', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('bó', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('ó', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('çãó', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('ãó', pre.text) + + pre = self.xpath('pre[9]') + self.assertEqual('ó', pre.text) + + pre = self.xpath('pre[10]') + self.assertEqual('', pre.text) + + pre = self.xpath('pre[11]') + self.assertEqual('', pre.text) + + + def test_2(self): + """Test case: strlen (2)""" + self.start('Utf8/strlens') + + pre = self.xpath('pre[1]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('0', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[9]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[10]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[11]') + self.assertEqual('6', pre.text) + + pre = self.xpath('pre[12]') + self.assertEqual('2', pre.text) + + pre = self.xpath('pre[13]') + self.assertEqual('14', pre.text) + + + def test_3(self): + """Test case: strlenGe (3)""" + self.start('Utf8/strlenGens') + + pre = self.xpath('pre[1]') + self.assertEqual('False', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('True', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('False', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('True', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('True', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('False', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('True', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('True', pre.text) + + def test_4(self): + """Test case: strcat (4)""" + self.start('Utf8/strcats') + + pre = self.xpath('pre[1]') + self.assertEqual('', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('0', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('aabb', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('4', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('bb', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('2', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('aa', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('2', pre.text) + + pre = self.xpath('pre[9]') + self.assertEqual('ààáá', pre.text) + + pre = self.xpath('pre[10]') + self.assertEqual('4', pre.text) + + pre = self.xpath('pre[11]') + self.assertEqual('áá', pre.text) + + pre = self.xpath('pre[12]') + self.assertEqual('2', pre.text) + + pre = self.xpath('pre[13]') + self.assertEqual('àà', pre.text) + + pre = self.xpath('pre[14]') + self.assertEqual('2', pre.text) + + def test_5(self): + """Test case: strsub (5)""" + self.start('Utf8/strsubs') + + pre = self.xpath('pre[1]') + self.assertEqual('a', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('b', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('à', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('ç', pre.text) + + def test_6(self): + """Test case: strsuffix (6)""" + self.start('Utf8/strsuffixs') + + pre = self.xpath('pre[1]') + self.assertEqual('abàç', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('bàç', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('àç', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('ç', pre.text) + + def test_7(self): + """Test case: strchr (7)""" + self.start('Utf8/strchrs') + + pre = self.xpath('pre[1]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('Some "bàç"', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('Some "àç"', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('Some "ç"', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('Some ""', pre.text) + + def test_8(self): + """Test case: strindex (8)""" + self.start('Utf8/strindexs') + + pre = self.xpath('pre[1]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('Some 0', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('Some 1', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('Some 2', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('Some 3', pre.text) + + def test_9(self): + """Test case: strindex (9)""" + self.start('Utf8/strsindexs') + + pre = self.xpath('pre[1]') + # behavior of strstr C function + self.assertEqual('Some 0', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('Some 0', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('Some 1', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('Some 2', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('None', pre.text) + + pre = self.xpath('pre[9]') + self.assertEqual('Some 3', pre.text) + + def test_10(self): + """Test case: strcspn (10)""" + self.start('Utf8/strcspns') + + pre = self.xpath('pre[1]') + self.assertEqual('4', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('0', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('0', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('2', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('3', pre.text) + + def test_11(self): + """Test case: str1 (11)""" + self.start('Utf8/str1s') + + pre = self.xpath('pre[1]') + self.assertEqual('a', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('à', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('á', pre.text) + + def test_12(self): + """Test case: isalnum (12)""" + self.start('Utf8/isalnums') + + for idx in range(1, 9): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isalnum: assert ' + str(idx)) + + def test_13(self): + """Test case: isalpha (13)""" + self.start('Utf8/isalphas') + + for idx in range(1, 9): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isalpha: assert ' + str(idx)) + + def test_14(self): + """Test case: isblank (14)""" + self.start('Utf8/isblanks') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isblank: assert ' + str(idx)) + + def test_15(self): + """Test case: iscntrl (15)""" + self.start('Utf8/iscntrls') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed iscntrl: assert ' + str(idx)) + + def test_16(self): + """Test case: isdigit (16)""" + self.start('Utf8/isdigits') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isdigit: assert ' + str(idx)) + + + def test_17(self): + """Test case: isgraph (17)""" + self.start('Utf8/isgraphs') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isgraph: assert ' + str(idx)) + + def test_18(self): + """Test case: islower (18)""" + self.start('Utf8/islowers') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed islower: assert ' + str(idx)) + + def test_19(self): + """Test case: isprint (19)""" + self.start('Utf8/isprints') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isprint: assert ' + str(idx)) + + def test_20(self): + """Test case: ispunct (20)""" + self.start('Utf8/ispuncts') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed ispunct: assert ' + str(idx)) + + def test_21(self): + """Test case: isspace (21)""" + self.start('Utf8/isspaces') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isspace: assert ' + str(idx)) + + def test_22(self): + """Test case: isupper (22)""" + self.start('Utf8/isuppers') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isupper: assert ' + str(idx)) + + def test_23(self): + """Test case: isxdigit (23)""" + self.start('Utf8/isxdigits') + + for idx in range(1, 11): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed isxdigit: assert ' + str(idx)) + + def test_24(self): + """Test case: toupper (24)""" + self.start('Utf8/touppers') + + for idx in range(1, 6): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed toupper: assert ' + str(idx)) + + def test_25(self): + """Test case: ord (25)""" + self.start('Utf8/ord_and_chrs') + + for idx in range(1, 8): + pre = self.xpath('pre[' + str(idx) + ']') + self.assertEqual('True', pre.text, 'Failed ord: assert ' + str(idx)) + + def test_26 (self): + """Test case: test_db (26) """ + self.start('Utf8/test_db') + + pre = self.xpath('pre[1]') + self.assertEqual('abc', pre.text) + + pre = self.xpath('pre[2]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[3]') + self.assertEqual('çãó', pre.text) + + pre = self.xpath('pre[4]') + self.assertEqual('3', pre.text) + + pre = self.xpath('pre[5]') + self.assertEqual('が', pre.text) + + pre = self.xpath('pre[6]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[7]') + self.assertEqual('漢', pre.text) + + pre = self.xpath('pre[8]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[9]') + self.assertEqual('カ', pre.text) + + pre = self.xpath('pre[10]') + self.assertEqual('1', pre.text) + + pre = self.xpath('pre[11]') + self.assertEqual('وظيفية', pre.text) + + pre = self.xpath('pre[12]') + self.assertEqual('6', pre.text) diff --git a/tests/utf8.ur b/tests/utf8.ur new file mode 100644 index 00000000..0dedc726 --- /dev/null +++ b/tests/utf8.ur @@ -0,0 +1,431 @@ +fun substrings () : transaction page = return + +
{[substring "abc" 0 3]}
+
{[substring "abc" 1 2]}
+
{[substring "abc" 2 1]}
+
{[substring "ábó" 0 3]}
+
{[substring "ábó" 1 2]}
+
{[substring "ábó" 2 1]}
+
{[substring "çãó" 0 3]}
+
{[substring "çãó" 1 2]}
+
{[substring "çãó" 2 1]}
+
{[substring "çãó" 2 0]}
+
{[substring "" 0 0]}
+ +
+ +fun strlens () : transaction page = return + +
{[strlen "abc"]}
+
{[strlen "çbc"]}
+
{[strlen "çãc"]}
+
{[strlen "çãó"]}
+
{[strlen "ç"]}
+
{[strlen "c"]}
+
{[strlen ""]}
+
{[strlen "が"]}
+
{[strlen "漢"]}
+
{[strlen "カ"]}
+
{[strlen "وظيفية"]}
+
{[strlen "函數"]}
+
{[strlen "Функциональное"]}
+ +
+ +fun strlenGens () : transaction page = return + +
{[strlenGe "" 1]}
+
{[strlenGe "" 0]}
+
{[strlenGe "aba" 4]}
+
{[strlenGe "aba" 3]}
+
{[strlenGe "aba" 2]}
+
{[strlenGe "áçà" 4]}
+
{[strlenGe "áçà" 3]}
+
{[strlenGe "áçà" 2]}
+ + +
+ +fun strcats () : transaction page = + let + fun catAndLen a b = + +
{[strcat a b]}
+
{[strlen (strcat a b)]}
+
+ in + return + + {catAndLen "" ""} + {catAndLen "aa" "bb"} + {catAndLen "" "bb"} + {catAndLen "aa" ""} + {catAndLen "àà" "áá"} + {catAndLen "" "áá"} + {catAndLen "àà" ""} + + +end + +fun strsubs () : transaction page = + return + +
{[strsub "abàç" 0]}
+
{[strsub "abàç" 1]}
+
{[strsub "abàç" 2]}
+
{[strsub "abàç" 3]}
+ +
+ +fun strsuffixs () : transaction page = + return + +
{[strsuffix "abàç" 0]}
+
{[strsuffix "abàç" 1]}
+
{[strsuffix "abàç" 2]}
+
{[strsuffix "abàç" 3]}
+ +
+ +fun strchrs () : transaction page = + let + fun optToStr ms = + case ms of + None => "None" + | Some s => "Some \"" ^ s ^ "\"" + + in + return + +
{[optToStr (strchr "abàç" #"c")]}
+
{[optToStr (strchr "abàç" #"a")]}
+
{[optToStr (strchr "abàç" #"b")]}
+
{[optToStr (strchr "abàç" (strsub "à" 0))]}
+
{[optToStr (strchr "abàç" (strsub "ç" 0))]}
+ +
+ end + +fun strindexs () : transaction page = + let + fun optToStr ms = + case ms of + None => "None" + | Some s => "Some " ^ (show s) + + in + return + +
{[optToStr (strindex "abàç" #"c")]}
+
{[optToStr (strindex "abàç" #"a")]}
+
{[optToStr (strindex "abàç" #"b")]}
+
{[optToStr (strindex "abàç" (strsub "à" 0))]}
+
{[optToStr (strindex "abàç" (strsub "ç" 0))]}
+ +
+ end + +fun strsindexs () : transaction page = + let + fun optToStr ms = + case ms of + None => "None" + | Some s => "Some " ^ (show s) + + in + return + +
{[optToStr (strsindex "abàç" "")]}
+
{[optToStr (strsindex "abàç" "abàç")]}
+
{[optToStr (strsindex "abàç" "abàc")]}
+
{[optToStr (strsindex "abàç" "bàç")]}
+
{[optToStr (strsindex "abàç" "bàc")]}
+
{[optToStr (strsindex "abàç" "àç")]}
+
{[optToStr (strsindex "abàç" "àc")]}
+
{[optToStr (strsindex "abàç" "ac")]}
+
{[optToStr (strsindex "abàç" "ç")]}
+ +
+ end + +fun strcspns () : transaction page = + return + +
{[strcspn "abàç" ""]}
+
{[strcspn "abàç" "abàç"]}
+
{[strcspn "abàç" "a"]}
+
{[strcspn "abàç" "bàç"]}
+
{[strcspn "abàç" "àç"]}
+
{[strcspn "abàç" "ç"]}
+ +
+ +fun str1s () : transaction page = return + +
{[str1 #"a"]}
+
{[str1 (strsub "à" 0)]}
+
{[str1 (strsub "aá" 1)]}
+ +
+ +fun isalnums () : transaction page = return + +
{[isalnum #"a"]}
+
{[isalnum (strsub "à" 0)]}
+
{[isalnum #"A"]}
+
{[isalnum (strsub "À" 0)]}
+
{[isalnum #"1"]}
+
{[not (isalnum #"!")]}
+
{[not (isalnum #"#")]}
+
{[not (isalnum #" ")]}
+ +
+ +fun isalphas () : transaction page = return + +
{[isalpha #"a"]}
+
{[isalpha (strsub "à" 0)]}
+
{[isalpha #"A"]}
+
{[isalpha (strsub "À" 0)]}
+
{[not (isalpha #"1")]}
+
{[not (isalpha #"!")]}
+
{[not (isalpha #"#")]}
+
{[not (isalpha #" ")]}
+ +
+ +fun isblanks () : transaction page = + return + +
{[not (isblank #"a")]}
+
{[not (isblank (strsub "à" 0))]}
+
{[not (isblank #"A")]}
+
{[not (isblank (strsub "À" 0))]}
+
{[not (isblank #"1")]}
+
{[not (isblank #"!")]}
+
{[not (isblank #"#")]}
+
{[isblank #" "]}
+
{[isblank #"\t"]}
+
{[not (isblank #"\n")]}
+ +
+ +fun iscntrls () : transaction page = + return + +
{[not (iscntrl #"a")]}
+
{[not (iscntrl (strsub "à" 0))]}
+
{[not (iscntrl #"A")]}
+
{[not (iscntrl (strsub "À" 0))]}
+
{[not (iscntrl #"1")]}
+
{[not (iscntrl #"!")]}
+
{[not (iscntrl #"#")]}
+
{[not (iscntrl #" ")]}
+
{[iscntrl #"\t"]}
+
{[iscntrl #"\n"]}
+ +
+ +fun isdigits () : transaction page = + return + +
{[not (isdigit #"a")]}
+
{[not (isdigit (strsub "à" 0))]}
+
{[not (isdigit #"A")]}
+
{[not (isdigit (strsub "À" 0))]}
+
{[isdigit #"1"]}
+
{[not (isdigit #"!")]}
+
{[not (isdigit #"#")]}
+
{[not (isdigit #" ")]}
+
{[not (isdigit #"\t")]}
+
{[not (isdigit #"\n")]}
+ +
+ +fun isgraphs () : transaction page = + return + +
{[isgraph #"a"]}
+
{[isgraph (strsub "à" 0)]}
+
{[isgraph #"A"]}
+
{[isgraph (strsub "À" 0)]}
+
{[isgraph #"1"]}
+
{[isgraph #"!"]}
+
{[isgraph #"#"]}
+
{[not (isgraph #" ")]}
+
{[not (isgraph #"\t")]}
+
{[not (isdigit #"\n")]}
+ +
+ +fun islowers () : transaction page = + return + +
{[islower #"a"]}
+
{[islower (strsub "à" 0)]}
+
{[not (islower #"A")]}
+
{[not (islower (strsub "À" 0))]}
+
{[not (islower #"1")]}
+
{[not (islower #"!")]}
+
{[not (islower #"#")]}
+
{[not (islower #" ")]}
+
{[not (islower #"\t")]}
+
{[not (islower #"\n")]}
+ +
+ +fun isprints () : transaction page = + return + +
{[isprint #"a"]}
+
{[isprint (strsub "à" 0)]}
+
{[isprint #"A"]}
+
{[isprint (strsub "À" 0)]}
+
{[isprint #"1"]}
+
{[isprint #"!"]}
+
{[isprint #"#"]}
+
{[isprint #" "]}
+
{[not (isprint #"\t")]}
+
{[not (isprint #"\n")]}
+ +
+ +fun ispuncts () : transaction page = + return + +
{[not (ispunct #"a")]}
+
{[not (ispunct (strsub "à" 0))]}
+
{[not (ispunct #"A")]}
+
{[not (ispunct (strsub "À" 0))]}
+
{[not (ispunct #"1")]}
+
{[ispunct #"!"]}
+
{[ispunct #"#"]}
+
{[not (ispunct #" ")]}
+
{[not (isprint #"\t")]}
+
{[not (isprint #"\n")]}
+ +
+ +fun isspaces () : transaction page = + return + +
{[not (isspace #"a")]}
+
{[not (isspace (strsub "à" 0))]}
+
{[not (isspace #"A")]}
+
{[not (isspace (strsub "À" 0))]}
+
{[not (isspace #"1")]}
+
{[not (isspace #"!")]}
+
{[not (isspace #"#")]}
+
{[isspace #" "]}
+
{[isspace #"\t"]}
+
{[isspace #"\n"]}
+ +
+ +fun isuppers () : transaction page = + return + +
{[not (isupper #"a")]}
+
{[not (isupper (strsub "à" 0))]}
+
{[isupper #"A"]}
+
{[isupper (strsub "À" 0)]}
+
{[not (isupper #"1")]}
+
{[not (isupper #"!")]}
+
{[not (isupper #"#")]}
+
{[not (isupper #" ")]}
+
{[not (isupper #"\t")]}
+
{[not (isupper #"\n")]}
+ +
+ +fun isxdigits () : transaction page = + return + +
{[isxdigit #"a"]}
+
{[not (isxdigit (strsub "à" 0))]}
+
{[isxdigit #"A"]}
+
{[not (isxdigit (strsub "À" 0))]}
+
{[isxdigit #"1"]}
+
{[not (isxdigit #"!")]}
+
{[not (isxdigit #"#")]}
+
{[not (isxdigit #" ")]}
+
{[not (isxdigit #"\t")]}
+
{[not (isxdigit #"\n")]}
+ +
+ +fun tolowers () : transaction page = + return + +
{[tolower #"A" = #"a"]}
+
{[tolower #"a" = #"a"]}
+
{[tolower (strsub "á" 0) = (strsub "á" 0)]}
+
{[tolower (strsub "Á" 0) = (strsub "á" 0)]}
+
{[tolower #"1" = #"1"]}
+ +
+ +fun touppers () : transaction page = + return + +
{[toupper #"A" = #"A"]}
+
{[toupper #"a" = #"A"]}
+
{[toupper (strsub "á" 0) = (strsub "Á" 0)]}
+
{[toupper (strsub "Á" 0) = (strsub "Á" 0)]}
+
{[toupper #"1" = #"1"]}
+ +
+ +fun ord_and_chrs () : transaction page = + return + +
{[chr (ord #"A") = #"A"]}
+
{[chr (ord #"a") = #"a"]}
+
{[chr (ord (strsub "á" 0)) = (strsub "á" 0)]}
+
{[chr (ord (strsub "Á" 0)) = (strsub "Á" 0)]}
+
{[chr (ord #"1") = #"1"]}
+
{[chr (ord #"\n") = #"\n"]}
+
{[chr (ord (strsub "が" 0)) = (strsub "が" 0)]}
+
{[chr (ord (strsub "漢" 0)) = (strsub "漢" 0)]}
+
{[chr (ord (strsub "カ" 0)) = (strsub "カ" 0)]}
+ +
+ +table t : { Id : int, Text : string } + + +fun test_db () : transaction page = + dml (INSERT INTO t (Id, Text) VALUES({[1]}, {["abc"]})); + t1 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 1); + + dml (INSERT INTO t (Id, Text) VALUES({[2]}, {["çãó"]})); + t2 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 2); + + dml (INSERT INTO t (Id, Text) VALUES({[3]}, {["が"]})); + t3 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 3); + + dml (INSERT INTO t (Id, Text) VALUES({[4]}, {["漢"]})); + t4 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 4); + + dml (INSERT INTO t (Id, Text) VALUES({[5]}, {["カ"]})); + t5 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 5); + + dml (INSERT INTO t (Id, Text) VALUES({[6]}, {["وظيفية"]})); + t6 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 6); + + return + +
{[t1.T.Text]}
+
{[strlen t1.T.Text]}
+
{[t2.T.Text]}
+
{[strlen t2.T.Text]}
+
{[t3.T.Text]}
+
{[strlen t3.T.Text]}
+
{[t4.T.Text]}
+
{[strlen t4.T.Text]}
+
{[t5.T.Text]}
+
{[strlen t5.T.Text]}
+
{[t6.T.Text]}
+
{[strlen t6.T.Text]}
+ +
diff --git a/tests/utf8.urp b/tests/utf8.urp new file mode 100644 index 00000000..9b3067af --- /dev/null +++ b/tests/utf8.urp @@ -0,0 +1,5 @@ +database dbname=utf8 +sql utf8.sql +safeGet Utf8/test_db + +utf8 \ No newline at end of file -- cgit v1.2.3 From f6d40570a8859260571f0b904ba329a1c4d1046c Mon Sep 17 00:00:00 2001 From: fab Date: Mon, 19 Nov 2018 20:33:20 +0000 Subject: several fixes on unit tests and implementation --- lib/js/urweb.js | 6 +- src/c/urweb.c | 22 ++- tests/utf8.py | 344 +------------------------------- tests/utf8.ur | 605 ++++++++++++++++++++++++++++++-------------------------- tests/utf8.urp | 1 + 5 files changed, 350 insertions(+), 628 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index f81f05e3..de1a2ad0 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -27,8 +27,8 @@ function le(x, y) { return x <= y; } // Characters -function isLower(c) { return c >= 'a' && c <= 'z'; } -function isUpper(c) { return c >= 'A' && c <= 'Z'; } +function isLower(c) { return c.toLowerCase() == c && c != c.toUpperCase(); } +function isUpper(c) { return c.toUpperCase() == c && c != c.toLowerCase(); } function isAlpha(c) { return isLower(c) || isUpper(c); } function isDigit(c) { return c >= '0' && c <= '9'; } function isAlnum(c) { return isAlpha(c) || isDigit(c); } @@ -36,7 +36,7 @@ function isBlank(c) { return c == ' ' || c == '\t'; } function isSpace(c) { return isBlank(c) || c == '\r' || c == '\n'; } function isXdigit(c) { return isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } function ord(c) { return c.charCodeAt(0); } -function isPrint(c) { return ord(c) > 31 && ord(c) < 127; } +function isPrint(c) { return ord(c) > 31 && ord(c) != 127; } function toLower(c) { return c.toLowerCase(); } function toUpper(c) { return c.toUpperCase(); } diff --git a/src/c/urweb.c b/src/c/urweb.c index 69c3da94..be65afcc 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1606,8 +1606,9 @@ uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) { return r; } +uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char ch); + uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { - unsigned char c = c1; char *r, *s2; uw_check_heap(ctx, 7); @@ -1615,7 +1616,7 @@ uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { r = s2 = ctx->heap.front; *s2++ = '"'; - switch (c) { + switch (c1) { case '"': strcpy(s2, "\\\""); s2 += 2; @@ -1637,10 +1638,16 @@ uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { s2 += 4; break; default: - if (isprint((int)c) || c >= 128) - *s2++ = c; + + if (uw_Basis_isprint(ctx, c1) == uw_Basis_True) + { + int offset = 0; + U8_APPEND_UNSAFE(s2, offset, c1); + s2 += offset; + } else { - sprintf(s2, "\\%03o", (unsigned char)c); + assert(0777 >= c1); + sprintf(s2, "\\%03o", (unsigned char)c1); s2 += 4; } } @@ -2482,16 +2489,17 @@ uw_Basis_bool uw_Basis_strlenGe(uw_context ctx, uw_Basis_string s, uw_Basis_int } int aux_strchr(uw_Basis_string s, uw_Basis_char ch, int* o_offset) { - int u8idx = 0, offset = 0; + int u8idx = 0, offset = 0, offsetpr = 0; uw_Basis_char c; while (s[offset] != 0) { U8_NEXT(s, offset, -1, c); if (c == ch) { - *o_offset = offset; + *o_offset = offsetpr; return u8idx; } + offsetpr = offset; ++u8idx; } diff --git a/tests/utf8.py b/tests/utf8.py index ff9b737a..440bc82a 100644 --- a/tests/utf8.py +++ b/tests/utf8.py @@ -5,445 +5,103 @@ class Suite(base.Base): def test_1(self): """Test case: substring (1)""" self.start('Utf8/substrings') - - pre = self.xpath('pre[1]') - self.assertEqual('abc', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('bc', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('c', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('ábó', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('bó', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('ó', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('çãó', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('ãó', pre.text) - - pre = self.xpath('pre[9]') - self.assertEqual('ó', pre.text) - - pre = self.xpath('pre[10]') - self.assertEqual('', pre.text) - - pre = self.xpath('pre[11]') - self.assertEqual('', pre.text) - def test_2(self): """Test case: strlen (2)""" self.start('Utf8/strlens') - - pre = self.xpath('pre[1]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('0', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[9]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[10]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[11]') - self.assertEqual('6', pre.text) - - pre = self.xpath('pre[12]') - self.assertEqual('2', pre.text) - - pre = self.xpath('pre[13]') - self.assertEqual('14', pre.text) - def test_3(self): """Test case: strlenGe (3)""" self.start('Utf8/strlenGens') - - pre = self.xpath('pre[1]') - self.assertEqual('False', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('True', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('False', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('True', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('True', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('False', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('True', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('True', pre.text) def test_4(self): """Test case: strcat (4)""" self.start('Utf8/strcats') - - pre = self.xpath('pre[1]') - self.assertEqual('', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('0', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('aabb', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('4', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('bb', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('2', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('aa', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('2', pre.text) - - pre = self.xpath('pre[9]') - self.assertEqual('ààáá', pre.text) - - pre = self.xpath('pre[10]') - self.assertEqual('4', pre.text) - - pre = self.xpath('pre[11]') - self.assertEqual('áá', pre.text) - - pre = self.xpath('pre[12]') - self.assertEqual('2', pre.text) - - pre = self.xpath('pre[13]') - self.assertEqual('àà', pre.text) - - pre = self.xpath('pre[14]') - self.assertEqual('2', pre.text) def test_5(self): """Test case: strsub (5)""" self.start('Utf8/strsubs') - pre = self.xpath('pre[1]') - self.assertEqual('a', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('b', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('à', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('ç', pre.text) - def test_6(self): """Test case: strsuffix (6)""" self.start('Utf8/strsuffixs') - pre = self.xpath('pre[1]') - self.assertEqual('abàç', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('bàç', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('àç', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('ç', pre.text) - def test_7(self): """Test case: strchr (7)""" self.start('Utf8/strchrs') - - pre = self.xpath('pre[1]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('Some "bàç"', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('Some "àç"', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('Some "ç"', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('Some ""', pre.text) def test_8(self): """Test case: strindex (8)""" self.start('Utf8/strindexs') - - pre = self.xpath('pre[1]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('Some 0', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('Some 1', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('Some 2', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('Some 3', pre.text) def test_9(self): """Test case: strindex (9)""" self.start('Utf8/strsindexs') - pre = self.xpath('pre[1]') - # behavior of strstr C function - self.assertEqual('Some 0', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('Some 0', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('Some 1', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('Some 2', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('None', pre.text) - - pre = self.xpath('pre[9]') - self.assertEqual('Some 3', pre.text) - def test_10(self): """Test case: strcspn (10)""" self.start('Utf8/strcspns') - pre = self.xpath('pre[1]') - self.assertEqual('4', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('0', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('0', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('2', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('3', pre.text) - def test_11(self): """Test case: str1 (11)""" self.start('Utf8/str1s') - pre = self.xpath('pre[1]') - self.assertEqual('a', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('à', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('á', pre.text) - def test_12(self): """Test case: isalnum (12)""" self.start('Utf8/isalnums') - - for idx in range(1, 9): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isalnum: assert ' + str(idx)) def test_13(self): """Test case: isalpha (13)""" self.start('Utf8/isalphas') - - for idx in range(1, 9): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isalpha: assert ' + str(idx)) def test_14(self): """Test case: isblank (14)""" self.start('Utf8/isblanks') - - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isblank: assert ' + str(idx)) def test_15(self): """Test case: iscntrl (15)""" self.start('Utf8/iscntrls') - - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed iscntrl: assert ' + str(idx)) - + def test_16(self): """Test case: isdigit (16)""" self.start('Utf8/isdigits') - - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isdigit: assert ' + str(idx)) - def test_17(self): """Test case: isgraph (17)""" self.start('Utf8/isgraphs') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isgraph: assert ' + str(idx)) - def test_18(self): """Test case: islower (18)""" self.start('Utf8/islowers') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed islower: assert ' + str(idx)) - def test_19(self): """Test case: isprint (19)""" self.start('Utf8/isprints') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isprint: assert ' + str(idx)) - def test_20(self): """Test case: ispunct (20)""" self.start('Utf8/ispuncts') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed ispunct: assert ' + str(idx)) - def test_21(self): """Test case: isspace (21)""" self.start('Utf8/isspaces') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isspace: assert ' + str(idx)) - def test_22(self): """Test case: isupper (22)""" self.start('Utf8/isuppers') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isupper: assert ' + str(idx)) - def test_23(self): """Test case: isxdigit (23)""" self.start('Utf8/isxdigits') - for idx in range(1, 11): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed isxdigit: assert ' + str(idx)) - def test_24(self): """Test case: toupper (24)""" self.start('Utf8/touppers') - for idx in range(1, 6): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed toupper: assert ' + str(idx)) - def test_25(self): """Test case: ord (25)""" self.start('Utf8/ord_and_chrs') - for idx in range(1, 8): - pre = self.xpath('pre[' + str(idx) + ']') - self.assertEqual('True', pre.text, 'Failed ord: assert ' + str(idx)) - def test_26 (self): """Test case: test_db (26) """ self.start('Utf8/test_db') - - pre = self.xpath('pre[1]') - self.assertEqual('abc', pre.text) - - pre = self.xpath('pre[2]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[3]') - self.assertEqual('çãó', pre.text) - - pre = self.xpath('pre[4]') - self.assertEqual('3', pre.text) - - pre = self.xpath('pre[5]') - self.assertEqual('が', pre.text) - - pre = self.xpath('pre[6]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[7]') - self.assertEqual('漢', pre.text) - - pre = self.xpath('pre[8]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[9]') - self.assertEqual('カ', pre.text) - - pre = self.xpath('pre[10]') - self.assertEqual('1', pre.text) - - pre = self.xpath('pre[11]') - self.assertEqual('وظيفية', pre.text) - - pre = self.xpath('pre[12]') - self.assertEqual('6', pre.text) diff --git a/tests/utf8.ur b/tests/utf8.ur index 0dedc726..1038a59f 100644 --- a/tests/utf8.ur +++ b/tests/utf8.ur @@ -1,68 +1,104 @@ -fun substrings () : transaction page = return - -
{[substring "abc" 0 3]}
-
{[substring "abc" 1 2]}
-
{[substring "abc" 2 1]}
-
{[substring "ábó" 0 3]}
-
{[substring "ábó" 1 2]}
-
{[substring "ábó" 2 1]}
-
{[substring "çãó" 0 3]}
-
{[substring "çãó" 1 2]}
-
{[substring "çãó" 2 1]}
-
{[substring "çãó" 2 0]}
-
{[substring "" 0 0]}
- + +fun test_fn_both_sides [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody = + +

Server side test: {[testname]}

+
{[assert (f () = expected) "False" testname "True" ]}
+

Client side test: {[testname]}

{[r]}
+ end}> +
+fun test_fn_sside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody = + +

Server side test: {[testname]}

+
{[assert (f () = expected) "False" testname "True" ]}
+
+ +fun substrings () : transaction page = + + return + + + {test_fn_both_sides (fn _ => substring "abc" 0 3) "abc" "substrings 1"} + {test_fn_both_sides (fn _ => substring "abc" 1 2) "bc" "substrings 2"} + {test_fn_both_sides (fn _ => substring "abc" 2 1) "c" "substrings 3"} + {test_fn_both_sides (fn _ => substring "ábó" 0 3) "ábó" "substrings 4"} + {test_fn_both_sides (fn _ => substring "ábó" 1 2) "bó" "substrings 5"} + {test_fn_both_sides (fn _ => substring "ábó" 2 1) "ó" "substrings 6"} + {test_fn_both_sides (fn _ => substring "ábó" 0 2) "áb" "substrings 7"} + {test_fn_both_sides (fn _ => substring "ábó" 0 1) "á" "substrings 8"} + + {test_fn_both_sides (fn _ => substring "" 0 0) "" "substrings 9"} + + + + fun strlens () : transaction page = return - -
{[strlen "abc"]}
-
{[strlen "çbc"]}
-
{[strlen "çãc"]}
-
{[strlen "çãó"]}
-
{[strlen "ç"]}
-
{[strlen "c"]}
-
{[strlen ""]}
-
{[strlen "が"]}
-
{[strlen "漢"]}
-
{[strlen "カ"]}
-
{[strlen "وظيفية"]}
-
{[strlen "函數"]}
-
{[strlen "Функциональное"]}
+ + {test_fn_both_sides (fn _ => strlen "abc") 3 "strlen 1"} + {test_fn_both_sides (fn _ => strlen "çbc") 3 "strlen 2"} + {test_fn_both_sides (fn _ => strlen "çãc") 3 "strlen 3"} + {test_fn_both_sides (fn _ => strlen "çãó") 3 "strlen 4"} + {test_fn_both_sides (fn _ => strlen "ç") 1 "strlen 5"} + {test_fn_both_sides (fn _ => strlen "c") 1 "strlen 6"} + {test_fn_both_sides (fn _ => strlen "") 0 "strlen 7"} + {test_fn_both_sides (fn _ => strlen "が") 1 "strlen 8"} + {test_fn_both_sides (fn _ => strlen "漢") 1 "strlen 9"} + {test_fn_both_sides (fn _ => strlen "カ") 1 "strlen 10"} + {test_fn_both_sides (fn _ => strlen "وظيفية") 6 "strlen 11"} + {test_fn_both_sides (fn _ => strlen "函數") 2 "strlen 12"} + {test_fn_both_sides (fn _ => strlen "Функциональное") 14 "strlen 13"} +
fun strlenGens () : transaction page = return -
{[strlenGe "" 1]}
-
{[strlenGe "" 0]}
-
{[strlenGe "aba" 4]}
-
{[strlenGe "aba" 3]}
-
{[strlenGe "aba" 2]}
-
{[strlenGe "áçà" 4]}
-
{[strlenGe "áçà" 3]}
-
{[strlenGe "áçà" 2]}
+ {test_fn_both_sides (fn _ => strlenGe "" 1) False "strlenGe 1"} + {test_fn_both_sides (fn _ => strlenGe "" 0) True "strlenGe 2"} + {test_fn_both_sides (fn _ => strlenGe "aba" 4) False "strlenGe 3"} + {test_fn_both_sides (fn _ => strlenGe "aba" 3) True "strlenGe 4"} + {test_fn_both_sides (fn _ => strlenGe "aba" 2) True "strlenGe 5"} + + {test_fn_both_sides (fn _ => strlenGe "àçá" 4) False "strlenGe 6"} + {test_fn_both_sides (fn _ => strlenGe "àçá" 3) True "strlenGe 7"} + {test_fn_both_sides (fn _ => strlenGe "àçá" 2) True "strlenGe 8"}
+type clen = { S : string, L : int } + +val clen_eq : eq clen = mkEq (fn a b => + a.S = b.S && a.L = b.L) + +val clen_show : show clen = mkShow (fn a => + "{S = " ^ a.S ^ ", L = " ^ (show a.L) ^ "}") + fun strcats () : transaction page = let - fun catAndLen a b = - -
{[strcat a b]}
-
{[strlen (strcat a b)]}
-
+ fun test_cat_and_len n a b expS expL = + test_fn_both_sides (fn _ => let val c = strcat a b in {S = c, L = strlen c} end) {S=expS, L=expL} ("strcat " ^ (show n)) in return - {catAndLen "" ""} - {catAndLen "aa" "bb"} - {catAndLen "" "bb"} - {catAndLen "aa" ""} - {catAndLen "àà" "áá"} - {catAndLen "" "áá"} - {catAndLen "àà" ""} + {test_cat_and_len 1 "" "" "" 0} + + {test_cat_and_len 2 "aa" "bb" "aabb" 4} + {test_cat_and_len 3 "" "bb" "bb" 2} + {test_cat_and_len 4 "aa" "" "aa" 2} + + {test_cat_and_len 5 "àà" "áá" "ààáá" 4} + {test_cat_and_len 6 "" "áá" "áá" 2} + {test_cat_and_len 7 "àà" "" "àà" 2} + + {test_cat_and_len 8 "函數" "ãã" "函數ãã" 4} + end @@ -70,324 +106,303 @@ end fun strsubs () : transaction page = return -
{[strsub "abàç" 0]}
-
{[strsub "abàç" 1]}
-
{[strsub "abàç" 2]}
-
{[strsub "abàç" 3]}
+ {test_fn_both_sides (fn _ => strsub "abàç" 0) #"a" "strsub 1"} + {test_fn_both_sides (fn _ => strsub "abàç" 1) #"b" "strsub 2"} + {test_fn_both_sides (fn _ => strsub "àb" 0) (strsub "à" 0) "strsub 3"} + {test_fn_both_sides (fn _ => strsub "abàç" 2) (strsub "à" 0) "strsub 4"} + {test_fn_both_sides (fn _ => strsub "abàç" 3) (strsub "ç" 0) "strsub 5"}
fun strsuffixs () : transaction page = return -
{[strsuffix "abàç" 0]}
-
{[strsuffix "abàç" 1]}
-
{[strsuffix "abàç" 2]}
-
{[strsuffix "abàç" 3]}
+ {test_fn_both_sides (fn _ => strsuffix "abàç" 0) "abàç" "strsuffix 1"} + {test_fn_both_sides (fn _ => strsuffix "abàç" 1) "bàç" "strsuffix 2"} + {test_fn_both_sides (fn _ => strsuffix "abàç" 2) "àç" "strsuffix 3"} + {test_fn_both_sides (fn _ => strsuffix "abàç" 3) "ç" "strsuffix 4"}
fun strchrs () : transaction page = - let - fun optToStr ms = - case ms of - None => "None" - | Some s => "Some \"" ^ s ^ "\"" - - in - return - -
{[optToStr (strchr "abàç" #"c")]}
-
{[optToStr (strchr "abàç" #"a")]}
-
{[optToStr (strchr "abàç" #"b")]}
-
{[optToStr (strchr "abàç" (strsub "à" 0))]}
-
{[optToStr (strchr "abàç" (strsub "ç" 0))]}
- -
- end + return + + {test_fn_both_sides (fn _ => strchr "abàç" #"c") None "strchr 1"} + {test_fn_both_sides (fn _ => strchr "abàç" #"a") (Some "abàç") "strchr 2"} + {test_fn_both_sides (fn _ => strchr "abàç" #"b") (Some "bàç") "strchr 3"} + {test_fn_both_sides (fn _ => strchr "abàç" (strsub "à" 0)) (Some "àç") "strchr 4"} + {test_fn_both_sides (fn _ => strchr "abàç" (strsub "ç" 0)) (Some "ç") "strchr 5"} + + fun strindexs () : transaction page = - let - fun optToStr ms = - case ms of - None => "None" - | Some s => "Some " ^ (show s) - - in - return - -
{[optToStr (strindex "abàç" #"c")]}
-
{[optToStr (strindex "abàç" #"a")]}
-
{[optToStr (strindex "abàç" #"b")]}
-
{[optToStr (strindex "abàç" (strsub "à" 0))]}
-
{[optToStr (strindex "abàç" (strsub "ç" 0))]}
- -
- end + return + + {test_fn_both_sides (fn _ => strindex "abàç" #"c") None "strindex 1"} + {test_fn_both_sides (fn _ => strindex "abàç" #"a") (Some 0) "strindex 2"} + {test_fn_both_sides (fn _ => strindex "abàç" #"b") (Some 1) "strindex 3"} + {test_fn_both_sides (fn _ => strindex "abàç" (strsub "à" 0)) (Some 2) "strindex 4"} + {test_fn_both_sides (fn _ => strindex "abàç" (strsub "ç" 0)) (Some 3) "strindex 5"} + + + fun strsindexs () : transaction page = - let - fun optToStr ms = - case ms of - None => "None" - | Some s => "Some " ^ (show s) - - in - return - -
{[optToStr (strsindex "abàç" "")]}
-
{[optToStr (strsindex "abàç" "abàç")]}
-
{[optToStr (strsindex "abàç" "abàc")]}
-
{[optToStr (strsindex "abàç" "bàç")]}
-
{[optToStr (strsindex "abàç" "bàc")]}
-
{[optToStr (strsindex "abàç" "àç")]}
-
{[optToStr (strsindex "abàç" "àc")]}
-
{[optToStr (strsindex "abàç" "ac")]}
-
{[optToStr (strsindex "abàç" "ç")]}
- -
- end + return + + {test_fn_both_sides (fn _ => strsindex "abàç" "") (Some 0) "strsindex 1"} + {test_fn_both_sides (fn _ => strsindex "abàç" "abàç") (Some 0) "strsindex 2"} + {test_fn_both_sides (fn _ => strsindex "abàç" "abàc") None "strsindex 3"} + {test_fn_both_sides (fn _ => strsindex "abàç" "bàç") (Some 1) "strsindex 4"} + {test_fn_both_sides (fn _ => strsindex "abàç" "bàc") None "strsindex 5"} + {test_fn_both_sides (fn _ => strsindex "abàç" "àç") (Some 2) "strsindex 6"} + {test_fn_both_sides (fn _ => strsindex "abàç" "àc") None "strsindex 7"} + {test_fn_both_sides (fn _ => strsindex "abàç" "ç") (Some 3) "strsindex 8"} + {test_fn_both_sides (fn _ => strsindex "abàç" "c") None "strsindex 9"} + + fun strcspns () : transaction page = return -
{[strcspn "abàç" ""]}
-
{[strcspn "abàç" "abàç"]}
-
{[strcspn "abàç" "a"]}
-
{[strcspn "abàç" "bàç"]}
-
{[strcspn "abàç" "àç"]}
-
{[strcspn "abàç" "ç"]}
+ {test_fn_both_sides (fn _ => strcspn "abàç" "") 4 "strcspn 1"} + {test_fn_both_sides (fn _ => strcspn "abàç" "abàç") 0 "strcspn 2"} + {test_fn_both_sides (fn _ => strcspn "abàç" "a") 0 "strcspn 3"} + {test_fn_both_sides (fn _ => strcspn "abàç" "bàç") 1 "strcspn 4"} + {test_fn_both_sides (fn _ => strcspn "abàç" "àç") 2 "strcspn 5"} + {test_fn_both_sides (fn _ => strcspn "abàç" "ç") 3 "strcspn 6"}
fun str1s () : transaction page = return -
{[str1 #"a"]}
-
{[str1 (strsub "à" 0)]}
-
{[str1 (strsub "aá" 1)]}
+ {test_fn_both_sides (fn _ => str1 #"a") "a" "str1 1"} + {test_fn_both_sides (fn _ => str1 (strsub "à" 0)) "à" "str1 2"} + {test_fn_both_sides (fn _ => str1 (strsub "aá" 1)) "á" "str1 3"}
fun isalnums () : transaction page = return -
{[isalnum #"a"]}
-
{[isalnum (strsub "à" 0)]}
-
{[isalnum #"A"]}
-
{[isalnum (strsub "À" 0)]}
-
{[isalnum #"1"]}
-
{[not (isalnum #"!")]}
-
{[not (isalnum #"#")]}
-
{[not (isalnum #" ")]}
+ {test_fn_both_sides (fn _ => isalnum #"a") True "isalnum 1"} + {test_fn_both_sides (fn _ => isalnum #"a") True "isalnum 2"} + {test_fn_both_sides (fn _ => isalnum (strsub "à" 0)) True "isalnum 3"} + {test_fn_both_sides (fn _ => isalnum #"A") True "isalnum 4"} + {test_fn_both_sides (fn _ => isalnum (strsub "À" 0)) True "isalnum 5"} + {test_fn_both_sides (fn _ => isalnum #"1") True "isalnum 6"} + {test_fn_both_sides (fn _ => not (isalnum #"!")) True "isalnum 7"} + {test_fn_both_sides (fn _ => not (isalnum #"#")) True "isalnum 8"} + {test_fn_both_sides (fn _ => not (isalnum #" ")) True "isalnum 9"}
fun isalphas () : transaction page = return -
{[isalpha #"a"]}
-
{[isalpha (strsub "à" 0)]}
-
{[isalpha #"A"]}
-
{[isalpha (strsub "À" 0)]}
-
{[not (isalpha #"1")]}
-
{[not (isalpha #"!")]}
-
{[not (isalpha #"#")]}
-
{[not (isalpha #" ")]}
+ {test_fn_both_sides (fn _ => isalpha #"a") True "isalpha 1"} + {test_fn_both_sides (fn _ => isalpha (strsub "à" 0)) True "isalpha 2"} + {test_fn_both_sides (fn _ => isalpha #"A") True "isalpha 3"} + {test_fn_both_sides (fn _ => isalpha (strsub "À" 0)) True "isalpha 4"} + {test_fn_both_sides (fn _ => not (isalpha #"1")) True "isalpha 5"} + {test_fn_both_sides (fn _ => not (isalpha #"!")) True "isalpha 6"} + {test_fn_both_sides (fn _ => not (isalpha #"#")) True "isalpha 7"} + {test_fn_both_sides (fn _ => not (isalpha #" ")) True "isalpha 8"}
fun isblanks () : transaction page = return -
{[not (isblank #"a")]}
-
{[not (isblank (strsub "à" 0))]}
-
{[not (isblank #"A")]}
-
{[not (isblank (strsub "À" 0))]}
-
{[not (isblank #"1")]}
-
{[not (isblank #"!")]}
-
{[not (isblank #"#")]}
-
{[isblank #" "]}
-
{[isblank #"\t"]}
-
{[not (isblank #"\n")]}
+ {test_fn_both_sides (fn _ => not (isblank #"a")) True "isblank 1"} + {test_fn_both_sides (fn _ => not (isblank (strsub "à" 0))) True "isblank 2"} + {test_fn_both_sides (fn _ => not (isblank #"A")) True "isblank 3"} + {test_fn_both_sides (fn _ => not (isblank (strsub "À" 0))) True "isblank 4"} + {test_fn_both_sides (fn _ => not (isblank #"1")) True "isblank 5"} + {test_fn_both_sides (fn _ => not (isblank #"!")) True "isblank 6"} + {test_fn_both_sides (fn _ => not (isblank #"#")) True "isblank 7"} + {test_fn_both_sides (fn _ => isblank #" ") True "isblank 8"} + {test_fn_both_sides (fn _ => isblank #"\t") True "isblank 9"} + {test_fn_both_sides (fn _ => not (isblank #"\n")) True "isblank 10"}
fun iscntrls () : transaction page = return -
{[not (iscntrl #"a")]}
-
{[not (iscntrl (strsub "à" 0))]}
-
{[not (iscntrl #"A")]}
-
{[not (iscntrl (strsub "À" 0))]}
-
{[not (iscntrl #"1")]}
-
{[not (iscntrl #"!")]}
-
{[not (iscntrl #"#")]}
-
{[not (iscntrl #" ")]}
-
{[iscntrl #"\t"]}
-
{[iscntrl #"\n"]}
+ {test_fn_sside (fn _ => not (iscntrl #"a")) True "iscntrl 1"} + {test_fn_sside (fn _ => not (iscntrl (strsub "à" 0))) True "iscntrl 2"} + {test_fn_sside (fn _ => not (iscntrl #"A")) True "iscntrl 3"} + {test_fn_sside (fn _ => not (iscntrl (strsub "À" 0))) True "iscntrl 4"} + {test_fn_sside (fn _ => not (iscntrl #"1")) True "iscntrl 5"} + {test_fn_sside (fn _ => not (iscntrl #"!")) True "iscntrl 6"} + {test_fn_sside (fn _ => not (iscntrl #"#")) True "iscntrl 7"} + {test_fn_sside (fn _ => not (iscntrl #" ")) True "iscntrl 8"} + {test_fn_sside (fn _ => iscntrl #"\t") True "iscntrl 9"} + {test_fn_sside (fn _ => iscntrl #"\n") True "iscntrl 10"}
fun isdigits () : transaction page = return -
{[not (isdigit #"a")]}
-
{[not (isdigit (strsub "à" 0))]}
-
{[not (isdigit #"A")]}
-
{[not (isdigit (strsub "À" 0))]}
-
{[isdigit #"1"]}
-
{[not (isdigit #"!")]}
-
{[not (isdigit #"#")]}
-
{[not (isdigit #" ")]}
-
{[not (isdigit #"\t")]}
-
{[not (isdigit #"\n")]}
+ {test_fn_both_sides (fn _ => not (isdigit #"a")) True "isdigit 1"} + {test_fn_both_sides (fn _ => not (isdigit (strsub "à" 0))) True "isdigit 2"} + {test_fn_both_sides (fn _ => not (isdigit #"A")) True "isdigit 3"} + {test_fn_both_sides (fn _ => not (isdigit (strsub "À" 0))) True "isdigit 4"} + {test_fn_both_sides (fn _ => isdigit #"1") True "isdigit 5"} + {test_fn_both_sides (fn _ => not (isdigit #"!")) True "isdigit 6"} + {test_fn_both_sides (fn _ => not (isdigit #"#")) True "isdigit 7"} + {test_fn_both_sides (fn _ => not (isdigit #" ")) True "isdigit 8"} + {test_fn_both_sides (fn _ => not (isdigit #"\t")) True "isdigit 9"} + {test_fn_both_sides (fn _ => not (isdigit #"\n")) True "isdigit 10"} -
+ fun isgraphs () : transaction page = return -
{[isgraph #"a"]}
-
{[isgraph (strsub "à" 0)]}
-
{[isgraph #"A"]}
-
{[isgraph (strsub "À" 0)]}
-
{[isgraph #"1"]}
-
{[isgraph #"!"]}
-
{[isgraph #"#"]}
-
{[not (isgraph #" ")]}
-
{[not (isgraph #"\t")]}
-
{[not (isdigit #"\n")]}
+ {test_fn_sside (fn _ => isgraph #"a") True "isgraph 1"} + {test_fn_sside (fn _ => isgraph (strsub "à" 0)) True "isgraph 2"} + {test_fn_sside (fn _ => isgraph #"A") True "isgraph 3"} + {test_fn_sside (fn _ => isgraph (strsub "À" 0)) True "isgraph 4"} + {test_fn_sside (fn _ => isgraph #"1") True "isgraph 5"} + {test_fn_sside (fn _ => isgraph #"!") True "isgraph 6"} + {test_fn_sside (fn _ => isgraph #"#") True "isgraph 7"} + {test_fn_sside (fn _ => not (isgraph #" ")) True "isgraph 8"} + {test_fn_sside (fn _ => not (isgraph #"\t")) True "isgraph 9"} + {test_fn_sside (fn _ => not (isdigit #"\n")) True "isgraph 10"} -
+ fun islowers () : transaction page = return -
{[islower #"a"]}
-
{[islower (strsub "à" 0)]}
-
{[not (islower #"A")]}
-
{[not (islower (strsub "À" 0))]}
-
{[not (islower #"1")]}
-
{[not (islower #"!")]}
-
{[not (islower #"#")]}
-
{[not (islower #" ")]}
-
{[not (islower #"\t")]}
-
{[not (islower #"\n")]}
+ {test_fn_both_sides (fn _ => islower #"a") True "islower 1"} + {test_fn_both_sides (fn _ => islower (strsub "à" 0)) True "islower 2"} + {test_fn_both_sides (fn _ => not (islower #"A")) True "islower 3"} + {test_fn_both_sides (fn _ => not (islower (strsub "À" 0))) True "islower 4"} + {test_fn_both_sides (fn _ => not (islower #"1")) True "islower 5"} + {test_fn_both_sides (fn _ => not (islower #"!")) True "islower 6"} + {test_fn_both_sides (fn _ => not (islower #"#")) True "islower 7"} + {test_fn_both_sides (fn _ => not (islower #" ")) True "islower 8"} + {test_fn_both_sides (fn _ => not (islower #"\t")) True "islower 9"} + {test_fn_both_sides (fn _ => not (islower #"\n")) True "islower 10"}
fun isprints () : transaction page = return -
{[isprint #"a"]}
-
{[isprint (strsub "à" 0)]}
-
{[isprint #"A"]}
-
{[isprint (strsub "À" 0)]}
-
{[isprint #"1"]}
-
{[isprint #"!"]}
-
{[isprint #"#"]}
-
{[isprint #" "]}
-
{[not (isprint #"\t")]}
-
{[not (isprint #"\n")]}
+ {test_fn_both_sides (fn _ => isprint #"a") True "isprint 1"} + {test_fn_both_sides (fn _ => isprint (strsub "à" 0)) True "isprint 2"} + {test_fn_both_sides (fn _ => isprint #"A") True "isprint 3"} + {test_fn_both_sides (fn _ => isprint (strsub "À" 0)) True "isprint 4"} + {test_fn_both_sides (fn _ => isprint #"1") True "isprint 5"} + {test_fn_both_sides (fn _ => isprint #"!") True "isprint 6"} + {test_fn_both_sides (fn _ => isprint #"#") True "isprint 7"} + {test_fn_both_sides (fn _ => isprint #" ") True "isprint 8"} + {test_fn_both_sides (fn _ => not (isprint #"\t")) True "isprint 9"} + {test_fn_both_sides (fn _ => not (isprint #"\n")) True "isprint 10"}
fun ispuncts () : transaction page = return -
{[not (ispunct #"a")]}
-
{[not (ispunct (strsub "à" 0))]}
-
{[not (ispunct #"A")]}
-
{[not (ispunct (strsub "À" 0))]}
-
{[not (ispunct #"1")]}
-
{[ispunct #"!"]}
-
{[ispunct #"#"]}
-
{[not (ispunct #" ")]}
-
{[not (isprint #"\t")]}
-
{[not (isprint #"\n")]}
+ {test_fn_sside (fn _ => not (ispunct #"a")) True "ispunct 1"} + {test_fn_sside (fn _ => not (ispunct (strsub "à" 0))) True "ispunct 2"} + {test_fn_sside (fn _ => not (ispunct #"A")) True "ispunct 3"} + {test_fn_sside (fn _ => not (ispunct (strsub "À" 0))) True "ispunct 4"} + {test_fn_sside (fn _ => not (ispunct #"1")) True "ispunct 5"} + {test_fn_sside (fn _ => ispunct #"!") True "ispunct 6"} + {test_fn_sside (fn _ => ispunct #"#") True "ispunct 7"} + {test_fn_sside (fn _ => not (ispunct #" ")) True "ispunct 8"} + {test_fn_sside (fn _ => not (isprint #"\t")) True "ispunct 9"} + {test_fn_sside (fn _ => not (isprint #"\n")) True "ispunct 10"}
fun isspaces () : transaction page = return -
{[not (isspace #"a")]}
-
{[not (isspace (strsub "à" 0))]}
-
{[not (isspace #"A")]}
-
{[not (isspace (strsub "À" 0))]}
-
{[not (isspace #"1")]}
-
{[not (isspace #"!")]}
-
{[not (isspace #"#")]}
-
{[isspace #" "]}
-
{[isspace #"\t"]}
-
{[isspace #"\n"]}
+ {test_fn_both_sides (fn _ => not (isspace #"a")) True "isspace 1"} + {test_fn_both_sides (fn _ => not (isspace (strsub "à" 0))) True "isspace 2"} + {test_fn_both_sides (fn _ => not (isspace #"A")) True "isspace 3"} + {test_fn_both_sides (fn _ => not (isspace (strsub "À" 0))) True "isspace 4"} + {test_fn_both_sides (fn _ => not (isspace #"1")) True "isspace 5"} + {test_fn_both_sides (fn _ => not (isspace #"!")) True "isspace 6"} + {test_fn_both_sides (fn _ => not (isspace #"#")) True "isspace 7"} + {test_fn_both_sides (fn _ => isspace #" ") True "isspace 8"} + {test_fn_both_sides (fn _ => isspace #"\t") True "isspace 9"} + {test_fn_both_sides (fn _ => isspace #"\n") True "isspace 10"}
fun isuppers () : transaction page = return -
{[not (isupper #"a")]}
-
{[not (isupper (strsub "à" 0))]}
-
{[isupper #"A"]}
-
{[isupper (strsub "À" 0)]}
-
{[not (isupper #"1")]}
-
{[not (isupper #"!")]}
-
{[not (isupper #"#")]}
-
{[not (isupper #" ")]}
-
{[not (isupper #"\t")]}
-
{[not (isupper #"\n")]}
+ {test_fn_both_sides (fn _ => not (isupper #"a")) True "isupper 1"} + {test_fn_both_sides (fn _ => not (isupper (strsub "à" 0))) True "isupper 2"} + {test_fn_both_sides (fn _ => isupper #"A") True "isupper 3"} + {test_fn_both_sides (fn _ => isupper (strsub "À" 0)) True "isupper 4"} + {test_fn_both_sides (fn _ => not (isupper #"1")) True "isupper 5"} + {test_fn_both_sides (fn _ => not (isupper #"!")) True "isupper 6"} + {test_fn_both_sides (fn _ => not (isupper #"#")) True "isupper 7"} + {test_fn_both_sides (fn _ => not (isupper #" ")) True "isupper 8"} + {test_fn_both_sides (fn _ => not (isupper #"\t")) True "isupper 9"} + {test_fn_both_sides (fn _ => not (isupper #"\n")) True "isupper 10"}
fun isxdigits () : transaction page = return -
{[isxdigit #"a"]}
-
{[not (isxdigit (strsub "à" 0))]}
-
{[isxdigit #"A"]}
-
{[not (isxdigit (strsub "À" 0))]}
-
{[isxdigit #"1"]}
-
{[not (isxdigit #"!")]}
-
{[not (isxdigit #"#")]}
-
{[not (isxdigit #" ")]}
-
{[not (isxdigit #"\t")]}
-
{[not (isxdigit #"\n")]}
+ {test_fn_both_sides (fn _ => isxdigit #"a") True "isxdigit 1"} + {test_fn_both_sides (fn _ => not (isxdigit (strsub "à" 0))) True "isxdigit 2"} + {test_fn_both_sides (fn _ => isxdigit #"A") True "isxdigit 3"} + {test_fn_both_sides (fn _ => not (isxdigit (strsub "À" 0))) True "isxdigit 4"} + {test_fn_both_sides (fn _ => isxdigit #"1") True "isxdigit 5"} + {test_fn_both_sides (fn _ => not (isxdigit #"!")) True "isxdigit 6"} + {test_fn_both_sides (fn _ => not (isxdigit #"#")) True "isxdigit 7"} + {test_fn_both_sides (fn _ => not (isxdigit #" ")) True "isxdigit 8"} + {test_fn_both_sides (fn _ => not (isxdigit #"\t")) True "isxdigit 9"} + {test_fn_both_sides (fn _ => not (isxdigit #"\n")) True "isxdigit 10"}
fun tolowers () : transaction page = return -
{[tolower #"A" = #"a"]}
-
{[tolower #"a" = #"a"]}
-
{[tolower (strsub "á" 0) = (strsub "á" 0)]}
-
{[tolower (strsub "Á" 0) = (strsub "á" 0)]}
-
{[tolower #"1" = #"1"]}
+ {test_fn_both_sides (fn _ => tolower #"A") #"a" "tolower 1"} + {test_fn_both_sides (fn _ => tolower #"a") #"a" "tolower 2"} + {test_fn_both_sides (fn _ => tolower (strsub "á" 0)) (strsub "á" 0) "tolower 3"} + {test_fn_both_sides (fn _ => tolower (strsub "Á" 0)) (strsub "á" 0) "tolower 4"} + {test_fn_both_sides (fn _ => tolower #"1") #"1" "tolower 5"}
fun touppers () : transaction page = return -
{[toupper #"A" = #"A"]}
-
{[toupper #"a" = #"A"]}
-
{[toupper (strsub "á" 0) = (strsub "Á" 0)]}
-
{[toupper (strsub "Á" 0) = (strsub "Á" 0)]}
-
{[toupper #"1" = #"1"]}
+ {test_fn_both_sides (fn _ => toupper #"A") #"A" "toupper 1"} + {test_fn_both_sides (fn _ => toupper #"a") #"A" "toupper 2"} + {test_fn_both_sides (fn _ => toupper (strsub "á" 0)) (strsub "Á" 0) "toupper 3"} + {test_fn_both_sides (fn _ => toupper (strsub "Á" 0)) (strsub "Á" 0) "toupper 4"} + {test_fn_both_sides (fn _ => toupper #"1") #"1" "toupper 5"}
fun ord_and_chrs () : transaction page = return -
{[chr (ord #"A") = #"A"]}
-
{[chr (ord #"a") = #"a"]}
-
{[chr (ord (strsub "á" 0)) = (strsub "á" 0)]}
-
{[chr (ord (strsub "Á" 0)) = (strsub "Á" 0)]}
-
{[chr (ord #"1") = #"1"]}
-
{[chr (ord #"\n") = #"\n"]}
-
{[chr (ord (strsub "が" 0)) = (strsub "が" 0)]}
-
{[chr (ord (strsub "漢" 0)) = (strsub "漢" 0)]}
-
{[chr (ord (strsub "カ" 0)) = (strsub "カ" 0)]}
+ {test_fn_both_sides (fn _ => chr (ord #"A")) #"A" "ord => chr 1"} + {test_fn_both_sides (fn _ => chr (ord #"a")) #"a" "ord => chr 2"} + {test_fn_both_sides (fn _ => chr (ord (strsub "á" 0))) (strsub "á" 0) "ord => chr 3"} + {test_fn_both_sides (fn _ => chr (ord (strsub "Á" 0))) (strsub "Á" 0) "ord => chr 4"} + {test_fn_both_sides (fn _ => chr (ord #"1")) #"1" "ord => chr 5"} + {test_fn_both_sides (fn _ => chr (ord #"\n")) #"\n" "ord => chr 6"} + {test_fn_both_sides (fn _ => chr (ord (strsub "が" 0))) (strsub "が" 0) "ord => chr 7"} + {test_fn_both_sides (fn _ => chr (ord (strsub "漢" 0))) (strsub "漢" 0) "ord => chr 8"} + {test_fn_both_sides (fn _ => chr (ord (strsub "カ" 0))) (strsub "カ" 0) "ord => chr 9"}
@@ -395,37 +410,77 @@ table t : { Id : int, Text : string } fun test_db () : transaction page = - dml (INSERT INTO t (Id, Text) VALUES({[1]}, {["abc"]})); + let + val s1 = "abc" + val s2 = "çãó" + val s3 = "が" + val s4 = "漢" + val s5 = "カ" + val s6 = "وظيفية" + + fun test_str_and_len n c expS expL = + test_fn_both_sides (fn _ => {S = c, L = strlen c}) {S=expS, L=expL} ("test_db " ^ (show n)) + + in + dml (INSERT INTO t (Id, Text) VALUES({[1]}, {[s1]})); t1 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 1); - dml (INSERT INTO t (Id, Text) VALUES({[2]}, {["çãó"]})); + dml (INSERT INTO t (Id, Text) VALUES({[2]}, {[s2]})); t2 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 2); - dml (INSERT INTO t (Id, Text) VALUES({[3]}, {["が"]})); + dml (INSERT INTO t (Id, Text) VALUES({[3]}, {[s3]})); t3 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 3); - dml (INSERT INTO t (Id, Text) VALUES({[4]}, {["漢"]})); + dml (INSERT INTO t (Id, Text) VALUES({[4]}, {[s4]})); t4 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 4); - dml (INSERT INTO t (Id, Text) VALUES({[5]}, {["カ"]})); + dml (INSERT INTO t (Id, Text) VALUES({[5]}, {[s5]})); t5 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 5); - dml (INSERT INTO t (Id, Text) VALUES({[6]}, {["وظيفية"]})); + dml (INSERT INTO t (Id, Text) VALUES({[6]}, {[s6]})); t6 <- oneRow (SELECT t.Text FROM t WHERE t.Id = 6); return -
{[t1.T.Text]}
-
{[strlen t1.T.Text]}
-
{[t2.T.Text]}
-
{[strlen t2.T.Text]}
-
{[t3.T.Text]}
-
{[strlen t3.T.Text]}
-
{[t4.T.Text]}
-
{[strlen t4.T.Text]}
-
{[t5.T.Text]}
-
{[strlen t5.T.Text]}
-
{[t6.T.Text]}
-
{[strlen t6.T.Text]}
+ {test_str_and_len 1 t1.T.Text s1 (strlen s1)} + {test_str_and_len 2 t2.T.Text s2 (strlen s2)} + {test_str_and_len 3 t3.T.Text s3 (strlen s3)} + {test_str_and_len 4 t4.T.Text s4 (strlen s4)} + {test_str_and_len 5 t5.T.Text s5 (strlen s5)} + {test_str_and_len 6 t6.T.Text s6 (strlen s6)} + +
+ end + +fun index () : transaction page = + return + + substrings + strlens + strlenGens + strcats + strsubs + strsuffixs + strchrs + strindexs + strsindexs + strcspns + str1s + isalnums + isalphas + isblanks + iscntrls + isdigits + isgraphs + islowers + isprints + ispuncts + isspaces + isuppers + isxdigits + tolowers + touppers + ord_and_chrs + test_db diff --git a/tests/utf8.urp b/tests/utf8.urp index 9b3067af..25288aa8 100644 --- a/tests/utf8.urp +++ b/tests/utf8.urp @@ -2,4 +2,5 @@ database dbname=utf8 sql utf8.sql safeGet Utf8/test_db +$/option utf8 \ No newline at end of file -- cgit v1.2.3 From 7eb75de05fe0b52798a3950a28683fe23736beac Mon Sep 17 00:00:00 2001 From: Chris Double Date: Sun, 25 Nov 2018 14:30:55 +1300 Subject: Replace timelocal usage with mktime timelocal is a non-standard GNU extension and equivalent to the POSIX standard mktime. musl-libc doesn't have timelocal, preventing fully static builds of urweb with musl. --- src/c/urweb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 2e3e18bc..e203ee37 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4238,7 +4238,7 @@ uw_Basis_time uw_Basis_fromDatetime(uw_context ctx, uw_Basis_int year, uw_Basis_ struct tm tm = { .tm_year = year - 1900, .tm_mon = month, .tm_mday = day, .tm_hour = hour, .tm_min = minute, .tm_sec = second, .tm_isdst = -1 }; - uw_Basis_time r = { timelocal(&tm) }; + uw_Basis_time r = { mktime(&tm) }; return r; } -- cgit v1.2.3 From 5cc729b48aad084757a049b7e5cdbadae5e9e400 Mon Sep 17 00:00:00 2001 From: fab Date: Fri, 30 Nov 2018 23:29:14 +0000 Subject: reject invalid codepoints. Basis.iscodepoint. fix german char in js --- include/urweb/urweb_cpp.h | 5 +- lib/js/urweb.js | 7 +- lib/ur/basis.urs | 2 + src/c/urweb.c | 265 +++++++++++++++++++++++++++------------------- 4 files changed, 168 insertions(+), 111 deletions(-) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 5f1144b8..25f97fb3 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -103,7 +103,7 @@ char *uw_Basis_htmlifyFloat(struct uw_context *, uw_Basis_float); char *uw_Basis_htmlifyString(struct uw_context *, uw_Basis_string); char *uw_Basis_htmlifyBool(struct uw_context *, uw_Basis_bool); char *uw_Basis_htmlifyTime(struct uw_context *, uw_Basis_time); -char *uw_Basis_htmlifySpecialChar(struct uw_context *, unsigned char); +char *uw_Basis_htmlifySpecialChar(struct uw_context *, uw_Basis_char); char *uw_Basis_htmlifySource(struct uw_context *, uw_Basis_source); uw_unit uw_Basis_htmlifyInt_w(struct uw_context *, uw_Basis_int); @@ -111,7 +111,7 @@ uw_unit uw_Basis_htmlifyFloat_w(struct uw_context *, uw_Basis_float); uw_unit uw_Basis_htmlifyString_w(struct uw_context *, uw_Basis_string); uw_unit uw_Basis_htmlifyBool_w(struct uw_context *, uw_Basis_bool); uw_unit uw_Basis_htmlifyTime_w(struct uw_context *, uw_Basis_time); -uw_unit uw_Basis_htmlifySpecialChar_w(struct uw_context *, unsigned char); +uw_unit uw_Basis_htmlifySpecialChar_w(struct uw_context *, uw_Basis_char); uw_unit uw_Basis_htmlifySource_w(struct uw_context *, uw_Basis_source); char *uw_Basis_attrifyInt(struct uw_context *, uw_Basis_int); @@ -327,6 +327,7 @@ uw_Basis_bool uw_Basis_isxdigit(struct uw_context *, uw_Basis_char); uw_Basis_char uw_Basis_tolower(struct uw_context *, uw_Basis_char); uw_Basis_char uw_Basis_toupper(struct uw_context *, uw_Basis_char); +uw_Basis_bool uw_Basis_iscodepoint(struct uw_context *, uw_Basis_int); uw_Basis_int uw_Basis_ord(struct uw_context *, uw_Basis_char); uw_Basis_char uw_Basis_chr(struct uw_context *, uw_Basis_int); diff --git a/lib/js/urweb.js b/lib/js/urweb.js index de1a2ad0..c7725e28 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -38,7 +38,12 @@ function isXdigit(c) { return isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' function ord(c) { return c.charCodeAt(0); } function isPrint(c) { return ord(c) > 31 && ord(c) != 127; } function toLower(c) { return c.toLowerCase(); } -function toUpper(c) { return c.toUpperCase(); } +function toUpper(c) { + if (ord(c) == 223) + return c; + else + return c.toUpperCase(); +} // Lists diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index 878f2793..c9d6556b 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -79,6 +79,8 @@ val toupper : char -> char val ord : char -> int val chr : int -> char +val iscodepoint : int -> bool + (** String operations *) val strlen : string -> int diff --git a/src/c/urweb.c b/src/c/urweb.c index be65afcc..195ddada 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1559,101 +1559,89 @@ const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { } } -uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) { - char *r, *s2; - - uw_check_heap(ctx, strlen(s) * 4 + 3); - - r = s2 = ctx->heap.front; - *s2++ = '"'; - - for (; *s; s++) { - unsigned char c = *s; - - switch (c) { - case '"': - strcpy(s2, "\\\""); - s2 += 2; - break; - case '\'': - strcpy(s2, "\\047"); - s2 += 4; - break; - case '\\': - strcpy(s2, "\\\\"); - s2 += 2; - break; - case '<': - strcpy(s2, "\\074"); - s2 += 4; - break; - case '&': - strcpy(s2, "\\046"); - s2 += 4; - break; - default: - if (isprint((int)c) || c >= 128) - *s2++ = c; - else { - sprintf(s2, "\\%03o", c); - s2 += 4; - } - } - } - - strcpy(s2, "\""); - ctx->heap.front = s2 + 2; - return r; -} - uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char ch); - -uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { - char *r, *s2; - - uw_check_heap(ctx, 7); - - r = s2 = ctx->heap.front; - *s2++ = '"'; - +void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { + char* buffer = *buffer_ptr; + switch (c1) { case '"': - strcpy(s2, "\\\""); - s2 += 2; + strcpy(buffer, "\\\""); + buffer += 2; break; case '\'': - strcpy(s2, "\\047"); - s2 += 4; + strcpy(buffer, "\\047"); + buffer += 4; break; case '\\': - strcpy(s2, "\\\\"); - s2 += 2; + strcpy(buffer, "\\\\"); + buffer += 2; break; case '<': - strcpy(s2, "\\074"); - s2 += 4; + strcpy(buffer, "\\074"); + buffer += 4; break; case '&': - strcpy(s2, "\\046"); - s2 += 4; + strcpy(buffer, "\\046"); + buffer += 4; break; default: if (uw_Basis_isprint(ctx, c1) == uw_Basis_True) { int offset = 0; - U8_APPEND_UNSAFE(s2, offset, c1); - s2 += offset; + U8_APPEND_UNSAFE(buffer, offset, c1); + buffer += offset; } else { - assert(0777 >= c1); - sprintf(s2, "\\%03o", (unsigned char)c1); - s2 += 4; + assert(65536 > c1); + sprintf(buffer, "\\u%04x", (unsigned char)c1); + buffer += 6; } } + + *buffer_ptr = buffer; +} + +uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) { + char *r, *s2; + uw_Basis_char c; + + uw_check_heap(ctx, strlen(s) * 6 + 3); + + r = s2 = ctx->heap.front; + *s2++ = '"'; + + int offset = 0; + while(s[offset] != 0) + { + U8_NEXT(s, offset, -1, c); + + jsifyChar(&s2, ctx, c); + } + strcpy(s2, "\""); ctx->heap.front = s2 + 2; + + return r; +} + +uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c); + +uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { + char *r, *s2; + + uw_check_heap(ctx, 8); + + r = s2 = ctx->heap.front; + + *s2++ = '"'; + + jsifyChar(&s2, ctx, c1); + + strcpy(s2, "\""); + ctx->heap.front = s2 + 2; + return r; } @@ -1697,6 +1685,7 @@ uw_Basis_string uw_Basis_jsifyString_ws(uw_context ctx, uw_Basis_string s) { strcpy(s2, "\""); ctx->script.front = s2 + 1; + return r; } @@ -2262,25 +2251,27 @@ uw_unit uw_Basis_htmlifyInt_w(uw_context ctx, uw_Basis_int n) { return uw_unit_v; } -char *uw_Basis_htmlifySpecialChar(uw_context ctx, unsigned char ch) { +char *uw_Basis_htmlifySpecialChar(uw_context ctx, uw_Basis_char ch) { unsigned int n = ch; int len; char *r; - uw_check_heap(ctx, INTS_MAX+3); + uw_check_heap(ctx, INTS_MAX+3 + 1); r = ctx->heap.front; - sprintf(r, "&#%u;%n", n, &len); + len = sprintf(r, "&#%u;", n); ctx->heap.front += len+1; + return r; } -uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, unsigned char ch) { +uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { unsigned int n = ch; int len; uw_check(ctx, INTS_MAX+3); - sprintf(ctx->page.front, "&#%u;%n", n, &len); + len = sprintf(ctx->page.front, "&#%u;", n); ctx->page.front += len; + return uw_unit_v; } @@ -2328,48 +2319,69 @@ uw_unit uw_Basis_jsifyInt_w(uw_context ctx, uw_Basis_int n) { char *uw_Basis_htmlifyString(uw_context ctx, const char *s) { char *r, *s2; + uw_Basis_char c1; + int offset = 0, len = 0; + + uw_check_heap(ctx, strlen(s) * (INTS_MAX + 3) + 1); - uw_check_heap(ctx, strlen(s) * 5 + 1); - - for (r = s2 = ctx->heap.front; *s; s++) { - unsigned char c = *s; - - switch (c) { - case '<': - strcpy(s2, "<"); - s2 += 4; - break; - case '&': - strcpy(s2, "&"); - s2 += 5; - break; - default: - *s2++ = c; + r = s2 = ctx->heap.front; + + while (s[offset] != 0) { + + U8_NEXT(s, offset, -1, c1); + + + if (U8_IS_SINGLE(c1) && uw_Basis_isprint(ctx, c1)) { + switch (c1) { + case '<': + strcpy(s2, "<"); + s2 += 4; + break; + case '&': + strcpy(s2, "&"); + s2 += 5; + break; + default: + *s2++ = c1; + } + } else { + len = sprintf(s2, "&#%u;", c1); + s2 += len; } } - + *s2++ = 0; ctx->heap.front = s2; + return r; } uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) { uw_check(ctx, strlen(s) * 6); - - for (; *s; s++) { - unsigned char c = *s; - - switch (c) { - case '<': - uw_write_unsafe(ctx, "<"); - break; - case '&': - uw_write_unsafe(ctx, "&"); - break; - default: - uw_writec_unsafe(ctx, c); + int offset = 0; + uw_Basis_char c1; + + while(s[offset] != 0){ + + U8_NEXT(s, offset, -1, c1); + + if (U8_IS_SINGLE(c1) && uw_Basis_isprint(ctx, c1)) { + + switch (c1) { + case '<': + uw_write_unsafe(ctx, "<"); + break; + case '&': + uw_write_unsafe(ctx, "&"); + break; + default: + uw_writec_unsafe(ctx, c1); + } } - } + else { + uw_Basis_htmlifySpecialChar_w(ctx, c1); + } + } return uw_unit_v; } @@ -4474,9 +4486,46 @@ uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c) { return (uw_Basis_int)c; } +uw_Basis_bool uw_Basis_iscodepoint (uw_context ctx, uw_Basis_int n) { + (void)ctx; + uw_Basis_char ch = (uw_Basis_char)n; + + if (UCHAR_MIN_VALUE <= ch && UCHAR_MAX_VALUE > ch) { + + if (U8_LENGTH(ch) == 0) { + return uw_Basis_False; + } + + if (u_charType(ch) == U_UNASSIGNED) { + return uw_Basis_False; + } + + } else { + return uw_Basis_False; + } + + return uw_Basis_True; +} + uw_Basis_char uw_Basis_chr(uw_context ctx, uw_Basis_int n) { (void)ctx; - return (uw_Basis_char)n; + uw_Basis_char ch = (uw_Basis_char)n; + + if (UCHAR_MIN_VALUE <= ch && UCHAR_MAX_VALUE > ch) { + + if (U8_LENGTH(ch) == 0) { + uw_error(ctx, FATAL, "The integer %lld cannot be converted to a char", n); + } + + if (u_charType(ch) == U_UNASSIGNED) { + uw_error(ctx, FATAL, "The integer %lld is not a valid char codepoint", n); + } + + } else { + uw_error(ctx, FATAL, "Integer %lld out of range of unicode chars", n); + } + + return ch; } uw_Basis_string uw_Basis_currentUrl(uw_context ctx) { -- cgit v1.2.3 From b50f472e65c0ffca5d485049325caa51298daa1a Mon Sep 17 00:00:00 2001 From: fab Date: Sun, 2 Dec 2018 00:46:46 +0000 Subject: 1 bug fix and sorting out my own confusion: uw_Basis_char is already a codepoint, NOT the "serialized" utf8 --- src/c/urweb.c | 37 ++++++------------------------------- tests/utf8.ur | 5 ++++- 2 files changed, 10 insertions(+), 32 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 195ddada..a4203376 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1560,6 +1560,7 @@ const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { } uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char ch); + void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { char* buffer = *buffer_ptr; @@ -1594,7 +1595,7 @@ void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { } else { assert(65536 > c1); - sprintf(buffer, "\\u%04x", (unsigned char)c1); + sprintf(buffer, "\\u%04x", c1); buffer += 6; } } @@ -4488,43 +4489,17 @@ uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c) { uw_Basis_bool uw_Basis_iscodepoint (uw_context ctx, uw_Basis_int n) { (void)ctx; - uw_Basis_char ch = (uw_Basis_char)n; - - if (UCHAR_MIN_VALUE <= ch && UCHAR_MAX_VALUE > ch) { - - if (U8_LENGTH(ch) == 0) { - return uw_Basis_False; - } - - if (u_charType(ch) == U_UNASSIGNED) { - return uw_Basis_False; - } - - } else { - return uw_Basis_False; - } - - return uw_Basis_True; + return !!(n <= 0x10FFFF); } uw_Basis_char uw_Basis_chr(uw_context ctx, uw_Basis_int n) { (void)ctx; uw_Basis_char ch = (uw_Basis_char)n; - if (UCHAR_MIN_VALUE <= ch && UCHAR_MAX_VALUE > ch) { - - if (U8_LENGTH(ch) == 0) { - uw_error(ctx, FATAL, "The integer %lld cannot be converted to a char", n); - } - - if (u_charType(ch) == U_UNASSIGNED) { - uw_error(ctx, FATAL, "The integer %lld is not a valid char codepoint", n); - } - - } else { - uw_error(ctx, FATAL, "Integer %lld out of range of unicode chars", n); + if (n > 0x10FFFF) { + uw_error(ctx, FATAL, "The integer %lld is not a valid char codepoint", n); } - + return ch; } diff --git a/tests/utf8.ur b/tests/utf8.ur index 07ac9c3d..e7c7fd40 100644 --- a/tests/utf8.ur +++ b/tests/utf8.ur @@ -100,7 +100,10 @@ fun strcats () : transaction page = {test_cat_and_len 5 "àà" "áá" "ààáá" 4} {test_cat_and_len 6 "" "áá" "áá" 2} {test_cat_and_len 7 "àà" "" "àà" 2} - {test_cat_and_len 8 "函數" "ãã" "函數ãã" 4} + {test_cat_and_len 8 "函數" "ãã" "函數ãã" 4} + {test_cat_and_len 9 "ç" "ã" "çã" 2} + {test_cat_and_len 10 (show (strsub "ç" 0)) (show (strsub "ã" 0)) "çã" 2} + {test_cat_and_len 11 (show (chr 231)) (show (chr 227)) "çã" 2} end -- cgit v1.2.3 From bc1547efbbad30da255b7c29973c94c8d37edabc Mon Sep 17 00:00:00 2001 From: fab Date: Sun, 2 Dec 2018 20:58:02 +0000 Subject: fix: U8_IS_SINGLE should only be called on raw char*, NOT on uw_Basis_char --- src/c/urweb.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index a4203376..d622df87 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -2321,18 +2321,17 @@ uw_unit uw_Basis_jsifyInt_w(uw_context ctx, uw_Basis_int n) { char *uw_Basis_htmlifyString(uw_context ctx, const char *s) { char *r, *s2; uw_Basis_char c1; - int offset = 0, len = 0; + int oldoffset = 0, offset = 0, offset2 = 0, len = 0; uw_check_heap(ctx, strlen(s) * (INTS_MAX + 3) + 1); r = s2 = ctx->heap.front; while (s[offset] != 0) { - + oldoffset = offset; U8_NEXT(s, offset, -1, c1); - - - if (U8_IS_SINGLE(c1) && uw_Basis_isprint(ctx, c1)) { + + if ((offset - oldoffset == 1) && uw_Basis_isprint(ctx, c1)) { switch (c1) { case '<': strcpy(s2, "<"); @@ -2343,7 +2342,9 @@ char *uw_Basis_htmlifyString(uw_context ctx, const char *s) { s2 += 5; break; default: - *s2++ = c1; + offset2 = 0; + U8_APPEND_UNSAFE(s2, offset2, c1); + s2 += offset2; } } else { len = sprintf(s2, "&#%u;", c1); @@ -2353,20 +2354,19 @@ char *uw_Basis_htmlifyString(uw_context ctx, const char *s) { *s2++ = 0; ctx->heap.front = s2; - return r; } uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) { uw_check(ctx, strlen(s) * 6); - int offset = 0; + int offset = 0, oldoffset = 0; uw_Basis_char c1; while(s[offset] != 0){ - + oldoffset = offset; U8_NEXT(s, offset, -1, c1); - if (U8_IS_SINGLE(c1) && uw_Basis_isprint(ctx, c1)) { + if ((offset - oldoffset == 1) && uw_Basis_isprint(ctx, c1)) { switch (c1) { case '<': -- cgit v1.2.3 From df191c8374991f65c5f5a552cfa5f4fb08fe29e8 Mon Sep 17 00:00:00 2001 From: fab Date: Thu, 6 Dec 2018 21:24:04 +0000 Subject: chars with more than 2 bytes are awkwardly handled by the "normal" string of javascript. the best way to get consistent results seems to be to convert to array by Array.from(...) and back to strings with .join("") --- lib/js/urweb.js | 14 +++++++------- src/c/urweb.c | 14 +++++++++----- tests/utf8.ur | 20 ++++++++++++++++++++ 3 files changed, 36 insertions(+), 12 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index c7725e28..e28446e3 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -1462,9 +1462,9 @@ function s2b(s) { return s == "True" ? true : s == "False" ? false : null; } function s2be(s) { return s == "True" ? true : s == "False" ? false : er("Illegal Boolean " ^ s); } function id(x) { return x; } -function sub(s, i) { return s.charAt(i); } -function suf(s, i) { return s.substring(i); } -function slen(s) { return s.length; } +function sub(s, i) { return Array.from(s)[i].codePointAt(0); } +function suf(s, i) { return Array.from(s).slice(i).join(""); } +function slen(s) { return Array.from(s).length; } function sidx(s, ch) { var r = s.indexOf(ch); if (r == -1) @@ -1494,10 +1494,10 @@ function schr(s, ch) { return s.substring(r); } function ssub(s, start, len) { - return s.substring(start, start+len); + return Array.from(s).slice(start, start+len).join(""); } function strlenGe(s, len) { - return s.length >= len; + return slen(s) >= len; } function trimZeroes(s) { @@ -1596,11 +1596,11 @@ function strcmp(str1, str2) { } function chr(n) { - return String.fromCharCode(n); + return String.fromCodePoint(n); } function htmlifySpecialChar(ch) { - return "&#" + ch.charCodeAt(0) + ";"; + return "&#" + ch.codePointAt(0) + ";"; } diff --git a/src/c/urweb.c b/src/c/urweb.c index d622df87..1394e068 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1594,9 +1594,13 @@ void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { buffer += offset; } else { - assert(65536 > c1); - sprintf(buffer, "\\u%04x", c1); - buffer += 6; + if(65536 > c1) { + sprintf(buffer, "\\u%04x", c1); + buffer += 6; + } else { + sprintf(buffer, "\\u{%06x}", c1); + buffer += 10; + } } } @@ -1608,7 +1612,7 @@ uw_Basis_string uw_Basis_jsifyString(uw_context ctx, uw_Basis_string s) { char *r, *s2; uw_Basis_char c; - uw_check_heap(ctx, strlen(s) * 6 + 3); + uw_check_heap(ctx, strlen(s) * 10 + 3); r = s2 = ctx->heap.front; *s2++ = '"'; @@ -1632,7 +1636,7 @@ uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c); uw_Basis_string uw_Basis_jsifyChar(uw_context ctx, uw_Basis_char c1) { char *r, *s2; - uw_check_heap(ctx, 8); + uw_check_heap(ctx, 10); r = s2 = ctx->heap.front; diff --git a/tests/utf8.ur b/tests/utf8.ur index e7c7fd40..cf781fa9 100644 --- a/tests/utf8.ur +++ b/tests/utf8.ur @@ -31,6 +31,25 @@ fun test_fn_cside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected +fun highencode () : transaction page = + return + + {test_fn_cside (fn _ => strlen "𝌆𝌇𝌈𝌉") (strlen "𝌆𝌇𝌈𝌉") "high encode - strlen 1"} + {test_fn_cside (fn _ => strlen "𝌇𝌈𝌉") (strlen "𝌇𝌈𝌉") "high encode - strlen 2"} + {test_fn_cside (fn _ => strlen "𝌈𝌉") (strlen "𝌈𝌉") "high encode - strlen 3"} + {test_fn_cside (fn _ => strlen "𝌉") (strlen "𝌉") "high encode - strlen 4"} + + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 1 3) (substring "𝌆𝌇𝌈𝌉" 1 3) "high encode - substring 1"} + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 2 2) (substring "𝌆𝌇𝌈𝌉" 2 2) "high encode - substring 2"} + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 3 1) (substring "𝌆𝌇𝌈𝌉" 3 1) "high encode - substring 3"} + + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 1 3)) (strlen (substring "𝌆𝌇𝌈𝌉" 1 3)) "high encode - strlen of substring 1"} + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 2 2)) (strlen (substring "𝌆𝌇𝌈𝌉" 2 2)) "high encode - strlen of substring 2"} + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 3 1)) (strlen (substring "𝌆𝌇𝌈𝌉" 3 1)) "high encode - strlen of substring 3"} + + + + fun substrings () : transaction page = return @@ -510,6 +529,7 @@ fun index () : transaction page = touppers ord_and_chrs test ord + highencode test_db -- cgit v1.2.3 From 1dd8c0c06f27343f86fd16b2c52b872871d0ab10 Mon Sep 17 00:00:00 2001 From: fab Date: Sun, 9 Dec 2018 22:23:41 +0000 Subject: fix isxdigit: is probably helpful to keep it only to ascii chars. migrate islower, isupper, isalpha, isdigit, isblank, isspace, isxdigit, isprint --- lib/js/urweb.js | 2778 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- src/c/urweb.c | 2 +- 2 files changed, 2708 insertions(+), 72 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index 05ee2a17..fe47959f 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -27,130 +27,2766 @@ function le(x, y) { return x <= y; } // Characters -function isLower(c) { return toLower(c) == c && c != toUpper(c); } -function isUpper(c) { return toUpper(c) == c && c != toLower(c); } -function isAlpha(c) { return isLower(c) || isUpper(c); } +function ord(c) { return c.codePointAt(0); } + +function isLower(c) { + var cp = ord(c); + + if (cp >= 97 && cp <= 122) return true; + if (cp == 170) return true; + if (cp == 181) return true; + if (cp == 186) return true; + if (cp >= 223 && cp <= 246) return true; + if (cp >= 248 && cp <= 255) return true; + if (cp == 257) return true; + if (cp == 259) return true; + if (cp == 261) return true; + if (cp == 263) return true; + if (cp == 265) return true; + if (cp == 267) return true; + if (cp == 269) return true; + if (cp == 271) return true; + if (cp == 273) return true; + if (cp == 275) return true; + if (cp == 277) return true; + if (cp == 279) return true; + if (cp == 281) return true; + if (cp == 283) return true; + if (cp == 285) return true; + if (cp == 287) return true; + if (cp == 289) return true; + if (cp == 291) return true; + if (cp == 293) return true; + if (cp == 295) return true; + if (cp == 297) return true; + if (cp == 299) return true; + if (cp == 301) return true; + if (cp == 303) return true; + if (cp == 305) return true; + if (cp == 307) return true; + if (cp == 309) return true; + if (cp >= 311 && cp <= 312) return true; + if (cp == 314) return true; + if (cp == 316) return true; + if (cp == 318) return true; + if (cp == 320) return true; + if (cp == 322) return true; + if (cp == 324) return true; + if (cp == 326) return true; + if (cp >= 328 && cp <= 329) return true; + if (cp == 331) return true; + if (cp == 333) return true; + if (cp == 335) return true; + if (cp == 337) return true; + if (cp == 339) return true; + if (cp == 341) return true; + if (cp == 343) return true; + if (cp == 345) return true; + if (cp == 347) return true; + if (cp == 349) return true; + if (cp == 351) return true; + if (cp == 353) return true; + if (cp == 355) return true; + if (cp == 357) return true; + if (cp == 359) return true; + if (cp == 361) return true; + if (cp == 363) return true; + if (cp == 365) return true; + if (cp == 367) return true; + if (cp == 369) return true; + if (cp == 371) return true; + if (cp == 373) return true; + if (cp == 375) return true; + if (cp == 378) return true; + if (cp == 380) return true; + if (cp >= 382 && cp <= 384) return true; + if (cp == 387) return true; + if (cp == 389) return true; + if (cp == 392) return true; + if (cp >= 396 && cp <= 397) return true; + if (cp == 402) return true; + if (cp == 405) return true; + if (cp >= 409 && cp <= 411) return true; + if (cp == 414) return true; + if (cp == 417) return true; + if (cp == 419) return true; + if (cp == 421) return true; + if (cp == 424) return true; + if (cp >= 426 && cp <= 427) return true; + if (cp == 429) return true; + if (cp == 432) return true; + if (cp == 436) return true; + if (cp == 438) return true; + if (cp >= 441 && cp <= 442) return true; + if (cp >= 445 && cp <= 447) return true; + if (cp == 454) return true; + if (cp == 457) return true; + if (cp == 460) return true; + if (cp == 462) return true; + if (cp == 464) return true; + if (cp == 466) return true; + if (cp == 468) return true; + if (cp == 470) return true; + if (cp == 472) return true; + if (cp == 474) return true; + if (cp >= 476 && cp <= 477) return true; + if (cp == 479) return true; + if (cp == 481) return true; + if (cp == 483) return true; + if (cp == 485) return true; + if (cp == 487) return true; + if (cp == 489) return true; + if (cp == 491) return true; + if (cp == 493) return true; + if (cp >= 495 && cp <= 496) return true; + if (cp == 499) return true; + if (cp == 501) return true; + if (cp == 505) return true; + if (cp == 507) return true; + if (cp == 509) return true; + if (cp == 511) return true; + if (cp == 513) return true; + if (cp == 515) return true; + if (cp == 517) return true; + if (cp == 519) return true; + if (cp == 521) return true; + if (cp == 523) return true; + if (cp == 525) return true; + if (cp == 527) return true; + if (cp == 529) return true; + if (cp == 531) return true; + if (cp == 533) return true; + if (cp == 535) return true; + if (cp == 537) return true; + if (cp == 539) return true; + if (cp == 541) return true; + if (cp == 543) return true; + if (cp == 545) return true; + if (cp == 547) return true; + if (cp == 549) return true; + if (cp == 551) return true; + if (cp == 553) return true; + if (cp == 555) return true; + if (cp == 557) return true; + if (cp == 559) return true; + if (cp == 561) return true; + if (cp >= 563 && cp <= 569) return true; + if (cp == 572) return true; + if (cp >= 575 && cp <= 576) return true; + if (cp == 578) return true; + if (cp == 583) return true; + if (cp == 585) return true; + if (cp == 587) return true; + if (cp == 589) return true; + if (cp >= 591 && cp <= 659) return true; + if (cp >= 661 && cp <= 696) return true; + if (cp >= 704 && cp <= 705) return true; + if (cp >= 736 && cp <= 740) return true; + if (cp == 837) return true; + if (cp == 881) return true; + if (cp == 883) return true; + if (cp == 887) return true; + if (cp >= 890 && cp <= 893) return true; + if (cp == 912) return true; + if (cp >= 940 && cp <= 974) return true; + if (cp >= 976 && cp <= 977) return true; + if (cp >= 981 && cp <= 983) return true; + if (cp == 985) return true; + if (cp == 987) return true; + if (cp == 989) return true; + if (cp == 991) return true; + if (cp == 993) return true; + if (cp == 995) return true; + if (cp == 997) return true; + if (cp == 999) return true; + if (cp == 1001) return true; + if (cp == 1003) return true; + if (cp == 1005) return true; + if (cp >= 1007 && cp <= 1011) return true; + if (cp == 1013) return true; + if (cp == 1016) return true; + if (cp >= 1019 && cp <= 1020) return true; + if (cp >= 1072 && cp <= 1119) return true; + if (cp == 1121) return true; + if (cp == 1123) return true; + if (cp == 1125) return true; + if (cp == 1127) return true; + if (cp == 1129) return true; + if (cp == 1131) return true; + if (cp == 1133) return true; + if (cp == 1135) return true; + if (cp == 1137) return true; + if (cp == 1139) return true; + if (cp == 1141) return true; + if (cp == 1143) return true; + if (cp == 1145) return true; + if (cp == 1147) return true; + if (cp == 1149) return true; + if (cp == 1151) return true; + if (cp == 1153) return true; + if (cp == 1163) return true; + if (cp == 1165) return true; + if (cp == 1167) return true; + if (cp == 1169) return true; + if (cp == 1171) return true; + if (cp == 1173) return true; + if (cp == 1175) return true; + if (cp == 1177) return true; + if (cp == 1179) return true; + if (cp == 1181) return true; + if (cp == 1183) return true; + if (cp == 1185) return true; + if (cp == 1187) return true; + if (cp == 1189) return true; + if (cp == 1191) return true; + if (cp == 1193) return true; + if (cp == 1195) return true; + if (cp == 1197) return true; + if (cp == 1199) return true; + if (cp == 1201) return true; + if (cp == 1203) return true; + if (cp == 1205) return true; + if (cp == 1207) return true; + if (cp == 1209) return true; + if (cp == 1211) return true; + if (cp == 1213) return true; + if (cp == 1215) return true; + if (cp == 1218) return true; + if (cp == 1220) return true; + if (cp == 1222) return true; + if (cp == 1224) return true; + if (cp == 1226) return true; + if (cp == 1228) return true; + if (cp >= 1230 && cp <= 1231) return true; + if (cp == 1233) return true; + if (cp == 1235) return true; + if (cp == 1237) return true; + if (cp == 1239) return true; + if (cp == 1241) return true; + if (cp == 1243) return true; + if (cp == 1245) return true; + if (cp == 1247) return true; + if (cp == 1249) return true; + if (cp == 1251) return true; + if (cp == 1253) return true; + if (cp == 1255) return true; + if (cp == 1257) return true; + if (cp == 1259) return true; + if (cp == 1261) return true; + if (cp == 1263) return true; + if (cp == 1265) return true; + if (cp == 1267) return true; + if (cp == 1269) return true; + if (cp == 1271) return true; + if (cp == 1273) return true; + if (cp == 1275) return true; + if (cp == 1277) return true; + if (cp == 1279) return true; + if (cp == 1281) return true; + if (cp == 1283) return true; + if (cp == 1285) return true; + if (cp == 1287) return true; + if (cp == 1289) return true; + if (cp == 1291) return true; + if (cp == 1293) return true; + if (cp == 1295) return true; + if (cp == 1297) return true; + if (cp == 1299) return true; + if (cp == 1301) return true; + if (cp == 1303) return true; + if (cp == 1305) return true; + if (cp == 1307) return true; + if (cp == 1309) return true; + if (cp == 1311) return true; + if (cp == 1313) return true; + if (cp == 1315) return true; + if (cp == 1317) return true; + if (cp == 1319) return true; + if (cp == 1321) return true; + if (cp == 1323) return true; + if (cp == 1325) return true; + if (cp == 1327) return true; + if (cp >= 1377 && cp <= 1415) return true; + if (cp >= 5112 && cp <= 5117) return true; + if (cp >= 7296 && cp <= 7304) return true; + if (cp >= 7424 && cp <= 7615) return true; + if (cp == 7681) return true; + if (cp == 7683) return true; + if (cp == 7685) return true; + if (cp == 7687) return true; + if (cp == 7689) return true; + if (cp == 7691) return true; + if (cp == 7693) return true; + if (cp == 7695) return true; + if (cp == 7697) return true; + if (cp == 7699) return true; + if (cp == 7701) return true; + if (cp == 7703) return true; + if (cp == 7705) return true; + if (cp == 7707) return true; + if (cp == 7709) return true; + if (cp == 7711) return true; + if (cp == 7713) return true; + if (cp == 7715) return true; + if (cp == 7717) return true; + if (cp == 7719) return true; + if (cp == 7721) return true; + if (cp == 7723) return true; + if (cp == 7725) return true; + if (cp == 7727) return true; + if (cp == 7729) return true; + if (cp == 7731) return true; + if (cp == 7733) return true; + if (cp == 7735) return true; + if (cp == 7737) return true; + if (cp == 7739) return true; + if (cp == 7741) return true; + if (cp == 7743) return true; + if (cp == 7745) return true; + if (cp == 7747) return true; + if (cp == 7749) return true; + if (cp == 7751) return true; + if (cp == 7753) return true; + if (cp == 7755) return true; + if (cp == 7757) return true; + if (cp == 7759) return true; + if (cp == 7761) return true; + if (cp == 7763) return true; + if (cp == 7765) return true; + if (cp == 7767) return true; + if (cp == 7769) return true; + if (cp == 7771) return true; + if (cp == 7773) return true; + if (cp == 7775) return true; + if (cp == 7777) return true; + if (cp == 7779) return true; + if (cp == 7781) return true; + if (cp == 7783) return true; + if (cp == 7785) return true; + if (cp == 7787) return true; + if (cp == 7789) return true; + if (cp == 7791) return true; + if (cp == 7793) return true; + if (cp == 7795) return true; + if (cp == 7797) return true; + if (cp == 7799) return true; + if (cp == 7801) return true; + if (cp == 7803) return true; + if (cp == 7805) return true; + if (cp == 7807) return true; + if (cp == 7809) return true; + if (cp == 7811) return true; + if (cp == 7813) return true; + if (cp == 7815) return true; + if (cp == 7817) return true; + if (cp == 7819) return true; + if (cp == 7821) return true; + if (cp == 7823) return true; + if (cp == 7825) return true; + if (cp == 7827) return true; + if (cp >= 7829 && cp <= 7837) return true; + if (cp == 7839) return true; + if (cp == 7841) return true; + if (cp == 7843) return true; + if (cp == 7845) return true; + if (cp == 7847) return true; + if (cp == 7849) return true; + if (cp == 7851) return true; + if (cp == 7853) return true; + if (cp == 7855) return true; + if (cp == 7857) return true; + if (cp == 7859) return true; + if (cp == 7861) return true; + if (cp == 7863) return true; + if (cp == 7865) return true; + if (cp == 7867) return true; + if (cp == 7869) return true; + if (cp == 7871) return true; + if (cp == 7873) return true; + if (cp == 7875) return true; + if (cp == 7877) return true; + if (cp == 7879) return true; + if (cp == 7881) return true; + if (cp == 7883) return true; + if (cp == 7885) return true; + if (cp == 7887) return true; + if (cp == 7889) return true; + if (cp == 7891) return true; + if (cp == 7893) return true; + if (cp == 7895) return true; + if (cp == 7897) return true; + if (cp == 7899) return true; + if (cp == 7901) return true; + if (cp == 7903) return true; + if (cp == 7905) return true; + if (cp == 7907) return true; + if (cp == 7909) return true; + if (cp == 7911) return true; + if (cp == 7913) return true; + if (cp == 7915) return true; + if (cp == 7917) return true; + if (cp == 7919) return true; + if (cp == 7921) return true; + if (cp == 7923) return true; + if (cp == 7925) return true; + if (cp == 7927) return true; + if (cp == 7929) return true; + if (cp == 7931) return true; + if (cp == 7933) return true; + if (cp >= 7935 && cp <= 7943) return true; + if (cp >= 7952 && cp <= 7957) return true; + if (cp >= 7968 && cp <= 7975) return true; + if (cp >= 7984 && cp <= 7991) return true; + if (cp >= 8000 && cp <= 8005) return true; + if (cp >= 8016 && cp <= 8023) return true; + if (cp >= 8032 && cp <= 8039) return true; + if (cp >= 8048 && cp <= 8061) return true; + if (cp >= 8064 && cp <= 8071) return true; + if (cp >= 8080 && cp <= 8087) return true; + if (cp >= 8096 && cp <= 8103) return true; + if (cp >= 8112 && cp <= 8116) return true; + if (cp >= 8118 && cp <= 8119) return true; + if (cp == 8126) return true; + if (cp >= 8130 && cp <= 8132) return true; + if (cp >= 8134 && cp <= 8135) return true; + if (cp >= 8144 && cp <= 8147) return true; + if (cp >= 8150 && cp <= 8151) return true; + if (cp >= 8160 && cp <= 8167) return true; + if (cp >= 8178 && cp <= 8180) return true; + if (cp >= 8182 && cp <= 8183) return true; + if (cp == 8305) return true; + if (cp == 8319) return true; + if (cp >= 8336 && cp <= 8348) return true; + if (cp == 8458) return true; + if (cp >= 8462 && cp <= 8463) return true; + if (cp == 8467) return true; + if (cp == 8495) return true; + if (cp == 8500) return true; + if (cp == 8505) return true; + if (cp >= 8508 && cp <= 8509) return true; + if (cp >= 8518 && cp <= 8521) return true; + if (cp == 8526) return true; + if (cp >= 8560 && cp <= 8575) return true; + if (cp == 8580) return true; + if (cp >= 9424 && cp <= 9449) return true; + if (cp >= 11312 && cp <= 11358) return true; + if (cp == 11361) return true; + if (cp >= 11365 && cp <= 11366) return true; + if (cp == 11368) return true; + if (cp == 11370) return true; + if (cp == 11372) return true; + if (cp == 11377) return true; + if (cp >= 11379 && cp <= 11380) return true; + if (cp >= 11382 && cp <= 11389) return true; + if (cp == 11393) return true; + if (cp == 11395) return true; + if (cp == 11397) return true; + if (cp == 11399) return true; + if (cp == 11401) return true; + if (cp == 11403) return true; + if (cp == 11405) return true; + if (cp == 11407) return true; + if (cp == 11409) return true; + if (cp == 11411) return true; + if (cp == 11413) return true; + if (cp == 11415) return true; + if (cp == 11417) return true; + if (cp == 11419) return true; + if (cp == 11421) return true; + if (cp == 11423) return true; + if (cp == 11425) return true; + if (cp == 11427) return true; + if (cp == 11429) return true; + if (cp == 11431) return true; + if (cp == 11433) return true; + if (cp == 11435) return true; + if (cp == 11437) return true; + if (cp == 11439) return true; + if (cp == 11441) return true; + if (cp == 11443) return true; + if (cp == 11445) return true; + if (cp == 11447) return true; + if (cp == 11449) return true; + if (cp == 11451) return true; + if (cp == 11453) return true; + if (cp == 11455) return true; + if (cp == 11457) return true; + if (cp == 11459) return true; + if (cp == 11461) return true; + if (cp == 11463) return true; + if (cp == 11465) return true; + if (cp == 11467) return true; + if (cp == 11469) return true; + if (cp == 11471) return true; + if (cp == 11473) return true; + if (cp == 11475) return true; + if (cp == 11477) return true; + if (cp == 11479) return true; + if (cp == 11481) return true; + if (cp == 11483) return true; + if (cp == 11485) return true; + if (cp == 11487) return true; + if (cp == 11489) return true; + if (cp >= 11491 && cp <= 11492) return true; + if (cp == 11500) return true; + if (cp == 11502) return true; + if (cp == 11507) return true; + if (cp >= 11520 && cp <= 11557) return true; + if (cp == 11559) return true; + if (cp == 11565) return true; + if (cp == 42561) return true; + if (cp == 42563) return true; + if (cp == 42565) return true; + if (cp == 42567) return true; + if (cp == 42569) return true; + if (cp == 42571) return true; + if (cp == 42573) return true; + if (cp == 42575) return true; + if (cp == 42577) return true; + if (cp == 42579) return true; + if (cp == 42581) return true; + if (cp == 42583) return true; + if (cp == 42585) return true; + if (cp == 42587) return true; + if (cp == 42589) return true; + if (cp == 42591) return true; + if (cp == 42593) return true; + if (cp == 42595) return true; + if (cp == 42597) return true; + if (cp == 42599) return true; + if (cp == 42601) return true; + if (cp == 42603) return true; + if (cp == 42605) return true; + if (cp == 42625) return true; + if (cp == 42627) return true; + if (cp == 42629) return true; + if (cp == 42631) return true; + if (cp == 42633) return true; + if (cp == 42635) return true; + if (cp == 42637) return true; + if (cp == 42639) return true; + if (cp == 42641) return true; + if (cp == 42643) return true; + if (cp == 42645) return true; + if (cp == 42647) return true; + if (cp == 42649) return true; + if (cp >= 42651 && cp <= 42653) return true; + if (cp == 42787) return true; + if (cp == 42789) return true; + if (cp == 42791) return true; + if (cp == 42793) return true; + if (cp == 42795) return true; + if (cp == 42797) return true; + if (cp >= 42799 && cp <= 42801) return true; + if (cp == 42803) return true; + if (cp == 42805) return true; + if (cp == 42807) return true; + if (cp == 42809) return true; + if (cp == 42811) return true; + if (cp == 42813) return true; + if (cp == 42815) return true; + if (cp == 42817) return true; + if (cp == 42819) return true; + if (cp == 42821) return true; + if (cp == 42823) return true; + if (cp == 42825) return true; + if (cp == 42827) return true; + if (cp == 42829) return true; + if (cp == 42831) return true; + if (cp == 42833) return true; + if (cp == 42835) return true; + if (cp == 42837) return true; + if (cp == 42839) return true; + if (cp == 42841) return true; + if (cp == 42843) return true; + if (cp == 42845) return true; + if (cp == 42847) return true; + if (cp == 42849) return true; + if (cp == 42851) return true; + if (cp == 42853) return true; + if (cp == 42855) return true; + if (cp == 42857) return true; + if (cp == 42859) return true; + if (cp == 42861) return true; + if (cp >= 42863 && cp <= 42872) return true; + if (cp == 42874) return true; + if (cp == 42876) return true; + if (cp == 42879) return true; + if (cp == 42881) return true; + if (cp == 42883) return true; + if (cp == 42885) return true; + if (cp == 42887) return true; + if (cp == 42892) return true; + if (cp == 42894) return true; + if (cp == 42897) return true; + if (cp >= 42899 && cp <= 42901) return true; + if (cp == 42903) return true; + if (cp == 42905) return true; + if (cp == 42907) return true; + if (cp == 42909) return true; + if (cp == 42911) return true; + if (cp == 42913) return true; + if (cp == 42915) return true; + if (cp == 42917) return true; + if (cp == 42919) return true; + if (cp == 42921) return true; + if (cp == 42933) return true; + if (cp == 42935) return true; + if (cp >= 43000 && cp <= 43002) return true; + if (cp >= 43824 && cp <= 43866) return true; + if (cp >= 43868 && cp <= 43877) return true; + if (cp >= 43888 && cp <= 43967) return true; + if (cp >= 64256 && cp <= 64262) return true; + if (cp >= 64275 && cp <= 64279) return true; + if (cp >= 65345 && cp <= 65370) return true; + if (cp >= 66600 && cp <= 66639) return true; + if (cp >= 66776 && cp <= 66811) return true; + if (cp >= 68800 && cp <= 68850) return true; + if (cp >= 71872 && cp <= 71903) return true; + if (cp >= 119834 && cp <= 119859) return true; + if (cp >= 119886 && cp <= 119892) return true; + if (cp >= 119894 && cp <= 119911) return true; + if (cp >= 119938 && cp <= 119963) return true; + if (cp >= 119990 && cp <= 119993) return true; + if (cp == 119995) return true; + if (cp >= 119997 && cp <= 120003) return true; + if (cp >= 120005 && cp <= 120015) return true; + if (cp >= 120042 && cp <= 120067) return true; + if (cp >= 120094 && cp <= 120119) return true; + if (cp >= 120146 && cp <= 120171) return true; + if (cp >= 120198 && cp <= 120223) return true; + if (cp >= 120250 && cp <= 120275) return true; + if (cp >= 120302 && cp <= 120327) return true; + if (cp >= 120354 && cp <= 120379) return true; + if (cp >= 120406 && cp <= 120431) return true; + if (cp >= 120458 && cp <= 120485) return true; + if (cp >= 120514 && cp <= 120538) return true; + if (cp >= 120540 && cp <= 120545) return true; + if (cp >= 120572 && cp <= 120596) return true; + if (cp >= 120598 && cp <= 120603) return true; + if (cp >= 120630 && cp <= 120654) return true; + if (cp >= 120656 && cp <= 120661) return true; + if (cp >= 120688 && cp <= 120712) return true; + if (cp >= 120714 && cp <= 120719) return true; + if (cp >= 120746 && cp <= 120770) return true; + if (cp >= 120772 && cp <= 120777) return true; + if (cp == 120779) return true; + if (cp >= 125218 && cp <= 125251) return true; + + return false; +} + +function isUpper(c) { + var cp = ord(c); + + if (cp >= 65 && cp <= 90) return true; + if (cp >= 192 && cp <= 214) return true; + if (cp >= 216 && cp <= 222) return true; + if (cp == 256) return true; + if (cp == 258) return true; + if (cp == 260) return true; + if (cp == 262) return true; + if (cp == 264) return true; + if (cp == 266) return true; + if (cp == 268) return true; + if (cp == 270) return true; + if (cp == 272) return true; + if (cp == 274) return true; + if (cp == 276) return true; + if (cp == 278) return true; + if (cp == 280) return true; + if (cp == 282) return true; + if (cp == 284) return true; + if (cp == 286) return true; + if (cp == 288) return true; + if (cp == 290) return true; + if (cp == 292) return true; + if (cp == 294) return true; + if (cp == 296) return true; + if (cp == 298) return true; + if (cp == 300) return true; + if (cp == 302) return true; + if (cp == 304) return true; + if (cp == 306) return true; + if (cp == 308) return true; + if (cp == 310) return true; + if (cp == 313) return true; + if (cp == 315) return true; + if (cp == 317) return true; + if (cp == 319) return true; + if (cp == 321) return true; + if (cp == 323) return true; + if (cp == 325) return true; + if (cp == 327) return true; + if (cp == 330) return true; + if (cp == 332) return true; + if (cp == 334) return true; + if (cp == 336) return true; + if (cp == 338) return true; + if (cp == 340) return true; + if (cp == 342) return true; + if (cp == 344) return true; + if (cp == 346) return true; + if (cp == 348) return true; + if (cp == 350) return true; + if (cp == 352) return true; + if (cp == 354) return true; + if (cp == 356) return true; + if (cp == 358) return true; + if (cp == 360) return true; + if (cp == 362) return true; + if (cp == 364) return true; + if (cp == 366) return true; + if (cp == 368) return true; + if (cp == 370) return true; + if (cp == 372) return true; + if (cp == 374) return true; + if (cp >= 376 && cp <= 377) return true; + if (cp == 379) return true; + if (cp == 381) return true; + if (cp >= 385 && cp <= 386) return true; + if (cp == 388) return true; + if (cp >= 390 && cp <= 391) return true; + if (cp >= 393 && cp <= 395) return true; + if (cp >= 398 && cp <= 401) return true; + if (cp >= 403 && cp <= 404) return true; + if (cp >= 406 && cp <= 408) return true; + if (cp >= 412 && cp <= 413) return true; + if (cp >= 415 && cp <= 416) return true; + if (cp == 418) return true; + if (cp == 420) return true; + if (cp >= 422 && cp <= 423) return true; + if (cp == 425) return true; + if (cp == 428) return true; + if (cp >= 430 && cp <= 431) return true; + if (cp >= 433 && cp <= 435) return true; + if (cp == 437) return true; + if (cp >= 439 && cp <= 440) return true; + if (cp == 444) return true; + if (cp == 452) return true; + if (cp == 455) return true; + if (cp == 458) return true; + if (cp == 461) return true; + if (cp == 463) return true; + if (cp == 465) return true; + if (cp == 467) return true; + if (cp == 469) return true; + if (cp == 471) return true; + if (cp == 473) return true; + if (cp == 475) return true; + if (cp == 478) return true; + if (cp == 480) return true; + if (cp == 482) return true; + if (cp == 484) return true; + if (cp == 486) return true; + if (cp == 488) return true; + if (cp == 490) return true; + if (cp == 492) return true; + if (cp == 494) return true; + if (cp == 497) return true; + if (cp == 500) return true; + if (cp >= 502 && cp <= 504) return true; + if (cp == 506) return true; + if (cp == 508) return true; + if (cp == 510) return true; + if (cp == 512) return true; + if (cp == 514) return true; + if (cp == 516) return true; + if (cp == 518) return true; + if (cp == 520) return true; + if (cp == 522) return true; + if (cp == 524) return true; + if (cp == 526) return true; + if (cp == 528) return true; + if (cp == 530) return true; + if (cp == 532) return true; + if (cp == 534) return true; + if (cp == 536) return true; + if (cp == 538) return true; + if (cp == 540) return true; + if (cp == 542) return true; + if (cp == 544) return true; + if (cp == 546) return true; + if (cp == 548) return true; + if (cp == 550) return true; + if (cp == 552) return true; + if (cp == 554) return true; + if (cp == 556) return true; + if (cp == 558) return true; + if (cp == 560) return true; + if (cp == 562) return true; + if (cp >= 570 && cp <= 571) return true; + if (cp >= 573 && cp <= 574) return true; + if (cp == 577) return true; + if (cp >= 579 && cp <= 582) return true; + if (cp == 584) return true; + if (cp == 586) return true; + if (cp == 588) return true; + if (cp == 590) return true; + if (cp == 880) return true; + if (cp == 882) return true; + if (cp == 886) return true; + if (cp == 895) return true; + if (cp == 902) return true; + if (cp >= 904 && cp <= 906) return true; + if (cp == 908) return true; + if (cp >= 910 && cp <= 911) return true; + if (cp >= 913 && cp <= 929) return true; + if (cp >= 931 && cp <= 939) return true; + if (cp == 975) return true; + if (cp >= 978 && cp <= 980) return true; + if (cp == 984) return true; + if (cp == 986) return true; + if (cp == 988) return true; + if (cp == 990) return true; + if (cp == 992) return true; + if (cp == 994) return true; + if (cp == 996) return true; + if (cp == 998) return true; + if (cp == 1000) return true; + if (cp == 1002) return true; + if (cp == 1004) return true; + if (cp == 1006) return true; + if (cp == 1012) return true; + if (cp == 1015) return true; + if (cp >= 1017 && cp <= 1018) return true; + if (cp >= 1021 && cp <= 1071) return true; + if (cp == 1120) return true; + if (cp == 1122) return true; + if (cp == 1124) return true; + if (cp == 1126) return true; + if (cp == 1128) return true; + if (cp == 1130) return true; + if (cp == 1132) return true; + if (cp == 1134) return true; + if (cp == 1136) return true; + if (cp == 1138) return true; + if (cp == 1140) return true; + if (cp == 1142) return true; + if (cp == 1144) return true; + if (cp == 1146) return true; + if (cp == 1148) return true; + if (cp == 1150) return true; + if (cp == 1152) return true; + if (cp == 1162) return true; + if (cp == 1164) return true; + if (cp == 1166) return true; + if (cp == 1168) return true; + if (cp == 1170) return true; + if (cp == 1172) return true; + if (cp == 1174) return true; + if (cp == 1176) return true; + if (cp == 1178) return true; + if (cp == 1180) return true; + if (cp == 1182) return true; + if (cp == 1184) return true; + if (cp == 1186) return true; + if (cp == 1188) return true; + if (cp == 1190) return true; + if (cp == 1192) return true; + if (cp == 1194) return true; + if (cp == 1196) return true; + if (cp == 1198) return true; + if (cp == 1200) return true; + if (cp == 1202) return true; + if (cp == 1204) return true; + if (cp == 1206) return true; + if (cp == 1208) return true; + if (cp == 1210) return true; + if (cp == 1212) return true; + if (cp == 1214) return true; + if (cp >= 1216 && cp <= 1217) return true; + if (cp == 1219) return true; + if (cp == 1221) return true; + if (cp == 1223) return true; + if (cp == 1225) return true; + if (cp == 1227) return true; + if (cp == 1229) return true; + if (cp == 1232) return true; + if (cp == 1234) return true; + if (cp == 1236) return true; + if (cp == 1238) return true; + if (cp == 1240) return true; + if (cp == 1242) return true; + if (cp == 1244) return true; + if (cp == 1246) return true; + if (cp == 1248) return true; + if (cp == 1250) return true; + if (cp == 1252) return true; + if (cp == 1254) return true; + if (cp == 1256) return true; + if (cp == 1258) return true; + if (cp == 1260) return true; + if (cp == 1262) return true; + if (cp == 1264) return true; + if (cp == 1266) return true; + if (cp == 1268) return true; + if (cp == 1270) return true; + if (cp == 1272) return true; + if (cp == 1274) return true; + if (cp == 1276) return true; + if (cp == 1278) return true; + if (cp == 1280) return true; + if (cp == 1282) return true; + if (cp == 1284) return true; + if (cp == 1286) return true; + if (cp == 1288) return true; + if (cp == 1290) return true; + if (cp == 1292) return true; + if (cp == 1294) return true; + if (cp == 1296) return true; + if (cp == 1298) return true; + if (cp == 1300) return true; + if (cp == 1302) return true; + if (cp == 1304) return true; + if (cp == 1306) return true; + if (cp == 1308) return true; + if (cp == 1310) return true; + if (cp == 1312) return true; + if (cp == 1314) return true; + if (cp == 1316) return true; + if (cp == 1318) return true; + if (cp == 1320) return true; + if (cp == 1322) return true; + if (cp == 1324) return true; + if (cp == 1326) return true; + if (cp >= 1329 && cp <= 1366) return true; + if (cp >= 4256 && cp <= 4293) return true; + if (cp == 4295) return true; + if (cp == 4301) return true; + if (cp >= 5024 && cp <= 5109) return true; + if (cp == 7680) return true; + if (cp == 7682) return true; + if (cp == 7684) return true; + if (cp == 7686) return true; + if (cp == 7688) return true; + if (cp == 7690) return true; + if (cp == 7692) return true; + if (cp == 7694) return true; + if (cp == 7696) return true; + if (cp == 7698) return true; + if (cp == 7700) return true; + if (cp == 7702) return true; + if (cp == 7704) return true; + if (cp == 7706) return true; + if (cp == 7708) return true; + if (cp == 7710) return true; + if (cp == 7712) return true; + if (cp == 7714) return true; + if (cp == 7716) return true; + if (cp == 7718) return true; + if (cp == 7720) return true; + if (cp == 7722) return true; + if (cp == 7724) return true; + if (cp == 7726) return true; + if (cp == 7728) return true; + if (cp == 7730) return true; + if (cp == 7732) return true; + if (cp == 7734) return true; + if (cp == 7736) return true; + if (cp == 7738) return true; + if (cp == 7740) return true; + if (cp == 7742) return true; + if (cp == 7744) return true; + if (cp == 7746) return true; + if (cp == 7748) return true; + if (cp == 7750) return true; + if (cp == 7752) return true; + if (cp == 7754) return true; + if (cp == 7756) return true; + if (cp == 7758) return true; + if (cp == 7760) return true; + if (cp == 7762) return true; + if (cp == 7764) return true; + if (cp == 7766) return true; + if (cp == 7768) return true; + if (cp == 7770) return true; + if (cp == 7772) return true; + if (cp == 7774) return true; + if (cp == 7776) return true; + if (cp == 7778) return true; + if (cp == 7780) return true; + if (cp == 7782) return true; + if (cp == 7784) return true; + if (cp == 7786) return true; + if (cp == 7788) return true; + if (cp == 7790) return true; + if (cp == 7792) return true; + if (cp == 7794) return true; + if (cp == 7796) return true; + if (cp == 7798) return true; + if (cp == 7800) return true; + if (cp == 7802) return true; + if (cp == 7804) return true; + if (cp == 7806) return true; + if (cp == 7808) return true; + if (cp == 7810) return true; + if (cp == 7812) return true; + if (cp == 7814) return true; + if (cp == 7816) return true; + if (cp == 7818) return true; + if (cp == 7820) return true; + if (cp == 7822) return true; + if (cp == 7824) return true; + if (cp == 7826) return true; + if (cp == 7828) return true; + if (cp == 7838) return true; + if (cp == 7840) return true; + if (cp == 7842) return true; + if (cp == 7844) return true; + if (cp == 7846) return true; + if (cp == 7848) return true; + if (cp == 7850) return true; + if (cp == 7852) return true; + if (cp == 7854) return true; + if (cp == 7856) return true; + if (cp == 7858) return true; + if (cp == 7860) return true; + if (cp == 7862) return true; + if (cp == 7864) return true; + if (cp == 7866) return true; + if (cp == 7868) return true; + if (cp == 7870) return true; + if (cp == 7872) return true; + if (cp == 7874) return true; + if (cp == 7876) return true; + if (cp == 7878) return true; + if (cp == 7880) return true; + if (cp == 7882) return true; + if (cp == 7884) return true; + if (cp == 7886) return true; + if (cp == 7888) return true; + if (cp == 7890) return true; + if (cp == 7892) return true; + if (cp == 7894) return true; + if (cp == 7896) return true; + if (cp == 7898) return true; + if (cp == 7900) return true; + if (cp == 7902) return true; + if (cp == 7904) return true; + if (cp == 7906) return true; + if (cp == 7908) return true; + if (cp == 7910) return true; + if (cp == 7912) return true; + if (cp == 7914) return true; + if (cp == 7916) return true; + if (cp == 7918) return true; + if (cp == 7920) return true; + if (cp == 7922) return true; + if (cp == 7924) return true; + if (cp == 7926) return true; + if (cp == 7928) return true; + if (cp == 7930) return true; + if (cp == 7932) return true; + if (cp == 7934) return true; + if (cp >= 7944 && cp <= 7951) return true; + if (cp >= 7960 && cp <= 7965) return true; + if (cp >= 7976 && cp <= 7983) return true; + if (cp >= 7992 && cp <= 7999) return true; + if (cp >= 8008 && cp <= 8013) return true; + if (cp == 8025) return true; + if (cp == 8027) return true; + if (cp == 8029) return true; + if (cp == 8031) return true; + if (cp >= 8040 && cp <= 8047) return true; + if (cp >= 8120 && cp <= 8123) return true; + if (cp >= 8136 && cp <= 8139) return true; + if (cp >= 8152 && cp <= 8155) return true; + if (cp >= 8168 && cp <= 8172) return true; + if (cp >= 8184 && cp <= 8187) return true; + if (cp == 8450) return true; + if (cp == 8455) return true; + if (cp >= 8459 && cp <= 8461) return true; + if (cp >= 8464 && cp <= 8466) return true; + if (cp == 8469) return true; + if (cp >= 8473 && cp <= 8477) return true; + if (cp == 8484) return true; + if (cp == 8486) return true; + if (cp == 8488) return true; + if (cp >= 8490 && cp <= 8493) return true; + if (cp >= 8496 && cp <= 8499) return true; + if (cp >= 8510 && cp <= 8511) return true; + if (cp == 8517) return true; + if (cp >= 8544 && cp <= 8559) return true; + if (cp == 8579) return true; + if (cp >= 9398 && cp <= 9423) return true; + if (cp >= 11264 && cp <= 11310) return true; + if (cp == 11360) return true; + if (cp >= 11362 && cp <= 11364) return true; + if (cp == 11367) return true; + if (cp == 11369) return true; + if (cp == 11371) return true; + if (cp >= 11373 && cp <= 11376) return true; + if (cp == 11378) return true; + if (cp == 11381) return true; + if (cp >= 11390 && cp <= 11392) return true; + if (cp == 11394) return true; + if (cp == 11396) return true; + if (cp == 11398) return true; + if (cp == 11400) return true; + if (cp == 11402) return true; + if (cp == 11404) return true; + if (cp == 11406) return true; + if (cp == 11408) return true; + if (cp == 11410) return true; + if (cp == 11412) return true; + if (cp == 11414) return true; + if (cp == 11416) return true; + if (cp == 11418) return true; + if (cp == 11420) return true; + if (cp == 11422) return true; + if (cp == 11424) return true; + if (cp == 11426) return true; + if (cp == 11428) return true; + if (cp == 11430) return true; + if (cp == 11432) return true; + if (cp == 11434) return true; + if (cp == 11436) return true; + if (cp == 11438) return true; + if (cp == 11440) return true; + if (cp == 11442) return true; + if (cp == 11444) return true; + if (cp == 11446) return true; + if (cp == 11448) return true; + if (cp == 11450) return true; + if (cp == 11452) return true; + if (cp == 11454) return true; + if (cp == 11456) return true; + if (cp == 11458) return true; + if (cp == 11460) return true; + if (cp == 11462) return true; + if (cp == 11464) return true; + if (cp == 11466) return true; + if (cp == 11468) return true; + if (cp == 11470) return true; + if (cp == 11472) return true; + if (cp == 11474) return true; + if (cp == 11476) return true; + if (cp == 11478) return true; + if (cp == 11480) return true; + if (cp == 11482) return true; + if (cp == 11484) return true; + if (cp == 11486) return true; + if (cp == 11488) return true; + if (cp == 11490) return true; + if (cp == 11499) return true; + if (cp == 11501) return true; + if (cp == 11506) return true; + if (cp == 42560) return true; + if (cp == 42562) return true; + if (cp == 42564) return true; + if (cp == 42566) return true; + if (cp == 42568) return true; + if (cp == 42570) return true; + if (cp == 42572) return true; + if (cp == 42574) return true; + if (cp == 42576) return true; + if (cp == 42578) return true; + if (cp == 42580) return true; + if (cp == 42582) return true; + if (cp == 42584) return true; + if (cp == 42586) return true; + if (cp == 42588) return true; + if (cp == 42590) return true; + if (cp == 42592) return true; + if (cp == 42594) return true; + if (cp == 42596) return true; + if (cp == 42598) return true; + if (cp == 42600) return true; + if (cp == 42602) return true; + if (cp == 42604) return true; + if (cp == 42624) return true; + if (cp == 42626) return true; + if (cp == 42628) return true; + if (cp == 42630) return true; + if (cp == 42632) return true; + if (cp == 42634) return true; + if (cp == 42636) return true; + if (cp == 42638) return true; + if (cp == 42640) return true; + if (cp == 42642) return true; + if (cp == 42644) return true; + if (cp == 42646) return true; + if (cp == 42648) return true; + if (cp == 42650) return true; + if (cp == 42786) return true; + if (cp == 42788) return true; + if (cp == 42790) return true; + if (cp == 42792) return true; + if (cp == 42794) return true; + if (cp == 42796) return true; + if (cp == 42798) return true; + if (cp == 42802) return true; + if (cp == 42804) return true; + if (cp == 42806) return true; + if (cp == 42808) return true; + if (cp == 42810) return true; + if (cp == 42812) return true; + if (cp == 42814) return true; + if (cp == 42816) return true; + if (cp == 42818) return true; + if (cp == 42820) return true; + if (cp == 42822) return true; + if (cp == 42824) return true; + if (cp == 42826) return true; + if (cp == 42828) return true; + if (cp == 42830) return true; + if (cp == 42832) return true; + if (cp == 42834) return true; + if (cp == 42836) return true; + if (cp == 42838) return true; + if (cp == 42840) return true; + if (cp == 42842) return true; + if (cp == 42844) return true; + if (cp == 42846) return true; + if (cp == 42848) return true; + if (cp == 42850) return true; + if (cp == 42852) return true; + if (cp == 42854) return true; + if (cp == 42856) return true; + if (cp == 42858) return true; + if (cp == 42860) return true; + if (cp == 42862) return true; + if (cp == 42873) return true; + if (cp == 42875) return true; + if (cp >= 42877 && cp <= 42878) return true; + if (cp == 42880) return true; + if (cp == 42882) return true; + if (cp == 42884) return true; + if (cp == 42886) return true; + if (cp == 42891) return true; + if (cp == 42893) return true; + if (cp == 42896) return true; + if (cp == 42898) return true; + if (cp == 42902) return true; + if (cp == 42904) return true; + if (cp == 42906) return true; + if (cp == 42908) return true; + if (cp == 42910) return true; + if (cp == 42912) return true; + if (cp == 42914) return true; + if (cp == 42916) return true; + if (cp == 42918) return true; + if (cp == 42920) return true; + if (cp >= 42922 && cp <= 42926) return true; + if (cp >= 42928 && cp <= 42932) return true; + if (cp == 42934) return true; + if (cp >= 65313 && cp <= 65338) return true; + if (cp >= 66560 && cp <= 66599) return true; + if (cp >= 66736 && cp <= 66771) return true; + if (cp >= 68736 && cp <= 68786) return true; + if (cp >= 71840 && cp <= 71871) return true; + if (cp >= 119808 && cp <= 119833) return true; + if (cp >= 119860 && cp <= 119885) return true; + if (cp >= 119912 && cp <= 119937) return true; + if (cp == 119964) return true; + if (cp >= 119966 && cp <= 119967) return true; + if (cp == 119970) return true; + if (cp >= 119973 && cp <= 119974) return true; + if (cp >= 119977 && cp <= 119980) return true; + if (cp >= 119982 && cp <= 119989) return true; + if (cp >= 120016 && cp <= 120041) return true; + if (cp >= 120068 && cp <= 120069) return true; + if (cp >= 120071 && cp <= 120074) return true; + if (cp >= 120077 && cp <= 120084) return true; + if (cp >= 120086 && cp <= 120092) return true; + if (cp >= 120120 && cp <= 120121) return true; + if (cp >= 120123 && cp <= 120126) return true; + if (cp >= 120128 && cp <= 120132) return true; + if (cp == 120134) return true; + if (cp >= 120138 && cp <= 120144) return true; + if (cp >= 120172 && cp <= 120197) return true; + if (cp >= 120224 && cp <= 120249) return true; + if (cp >= 120276 && cp <= 120301) return true; + if (cp >= 120328 && cp <= 120353) return true; + if (cp >= 120380 && cp <= 120405) return true; + if (cp >= 120432 && cp <= 120457) return true; + if (cp >= 120488 && cp <= 120512) return true; + if (cp >= 120546 && cp <= 120570) return true; + if (cp >= 120604 && cp <= 120628) return true; + if (cp >= 120662 && cp <= 120686) return true; + if (cp >= 120720 && cp <= 120744) return true; + if (cp == 120778) return true; + if (cp >= 125184 && cp <= 125217) return true; + if (cp >= 127280 && cp <= 127305) return true; + if (cp >= 127312 && cp <= 127337) return true; + if (cp >= 127344 && cp <= 127369) return true; + + return false; +} + +function isAlpha(c) { + var cp = ord(c); + + if (cp >= 65 && cp <= 90) return true; + if (cp >= 97 && cp <= 122) return true; + if (cp == 170) return true; + if (cp == 181) return true; + if (cp == 186) return true; + if (cp >= 192 && cp <= 214) return true; + if (cp >= 216 && cp <= 246) return true; + if (cp >= 248 && cp <= 705) return true; + if (cp >= 710 && cp <= 721) return true; + if (cp >= 736 && cp <= 740) return true; + if (cp == 748) return true; + if (cp == 750) return true; + if (cp == 837) return true; + if (cp >= 880 && cp <= 884) return true; + if (cp >= 886 && cp <= 887) return true; + if (cp >= 890 && cp <= 893) return true; + if (cp == 895) return true; + if (cp == 902) return true; + if (cp >= 904 && cp <= 906) return true; + if (cp == 908) return true; + if (cp >= 910 && cp <= 929) return true; + if (cp >= 931 && cp <= 1013) return true; + if (cp >= 1015 && cp <= 1153) return true; + if (cp >= 1162 && cp <= 1327) return true; + if (cp >= 1329 && cp <= 1366) return true; + if (cp == 1369) return true; + if (cp >= 1377 && cp <= 1415) return true; + if (cp >= 1456 && cp <= 1469) return true; + if (cp == 1471) return true; + if (cp >= 1473 && cp <= 1474) return true; + if (cp >= 1476 && cp <= 1477) return true; + if (cp == 1479) return true; + if (cp >= 1488 && cp <= 1514) return true; + if (cp >= 1520 && cp <= 1522) return true; + if (cp >= 1552 && cp <= 1562) return true; + if (cp >= 1568 && cp <= 1623) return true; + if (cp >= 1625 && cp <= 1631) return true; + if (cp >= 1646 && cp <= 1747) return true; + if (cp >= 1749 && cp <= 1756) return true; + if (cp >= 1761 && cp <= 1768) return true; + if (cp >= 1773 && cp <= 1775) return true; + if (cp >= 1786 && cp <= 1788) return true; + if (cp == 1791) return true; + if (cp >= 1808 && cp <= 1855) return true; + if (cp >= 1869 && cp <= 1969) return true; + if (cp >= 1994 && cp <= 2026) return true; + if (cp >= 2036 && cp <= 2037) return true; + if (cp == 2042) return true; + if (cp >= 2048 && cp <= 2071) return true; + if (cp >= 2074 && cp <= 2092) return true; + if (cp >= 2112 && cp <= 2136) return true; + if (cp >= 2144 && cp <= 2154) return true; + if (cp >= 2208 && cp <= 2228) return true; + if (cp >= 2230 && cp <= 2237) return true; + if (cp >= 2260 && cp <= 2271) return true; + if (cp >= 2275 && cp <= 2281) return true; + if (cp >= 2288 && cp <= 2363) return true; + if (cp >= 2365 && cp <= 2380) return true; + if (cp >= 2382 && cp <= 2384) return true; + if (cp >= 2389 && cp <= 2403) return true; + if (cp >= 2417 && cp <= 2435) return true; + if (cp >= 2437 && cp <= 2444) return true; + if (cp >= 2447 && cp <= 2448) return true; + if (cp >= 2451 && cp <= 2472) return true; + if (cp >= 2474 && cp <= 2480) return true; + if (cp == 2482) return true; + if (cp >= 2486 && cp <= 2489) return true; + if (cp >= 2493 && cp <= 2500) return true; + if (cp >= 2503 && cp <= 2504) return true; + if (cp >= 2507 && cp <= 2508) return true; + if (cp == 2510) return true; + if (cp == 2519) return true; + if (cp >= 2524 && cp <= 2525) return true; + if (cp >= 2527 && cp <= 2531) return true; + if (cp >= 2544 && cp <= 2545) return true; + if (cp == 2556) return true; + if (cp >= 2561 && cp <= 2563) return true; + if (cp >= 2565 && cp <= 2570) return true; + if (cp >= 2575 && cp <= 2576) return true; + if (cp >= 2579 && cp <= 2600) return true; + if (cp >= 2602 && cp <= 2608) return true; + if (cp >= 2610 && cp <= 2611) return true; + if (cp >= 2613 && cp <= 2614) return true; + if (cp >= 2616 && cp <= 2617) return true; + if (cp >= 2622 && cp <= 2626) return true; + if (cp >= 2631 && cp <= 2632) return true; + if (cp >= 2635 && cp <= 2636) return true; + if (cp == 2641) return true; + if (cp >= 2649 && cp <= 2652) return true; + if (cp == 2654) return true; + if (cp >= 2672 && cp <= 2677) return true; + if (cp >= 2689 && cp <= 2691) return true; + if (cp >= 2693 && cp <= 2701) return true; + if (cp >= 2703 && cp <= 2705) return true; + if (cp >= 2707 && cp <= 2728) return true; + if (cp >= 2730 && cp <= 2736) return true; + if (cp >= 2738 && cp <= 2739) return true; + if (cp >= 2741 && cp <= 2745) return true; + if (cp >= 2749 && cp <= 2757) return true; + if (cp >= 2759 && cp <= 2761) return true; + if (cp >= 2763 && cp <= 2764) return true; + if (cp == 2768) return true; + if (cp >= 2784 && cp <= 2787) return true; + if (cp >= 2809 && cp <= 2812) return true; + if (cp >= 2817 && cp <= 2819) return true; + if (cp >= 2821 && cp <= 2828) return true; + if (cp >= 2831 && cp <= 2832) return true; + if (cp >= 2835 && cp <= 2856) return true; + if (cp >= 2858 && cp <= 2864) return true; + if (cp >= 2866 && cp <= 2867) return true; + if (cp >= 2869 && cp <= 2873) return true; + if (cp >= 2877 && cp <= 2884) return true; + if (cp >= 2887 && cp <= 2888) return true; + if (cp >= 2891 && cp <= 2892) return true; + if (cp >= 2902 && cp <= 2903) return true; + if (cp >= 2908 && cp <= 2909) return true; + if (cp >= 2911 && cp <= 2915) return true; + if (cp == 2929) return true; + if (cp >= 2946 && cp <= 2947) return true; + if (cp >= 2949 && cp <= 2954) return true; + if (cp >= 2958 && cp <= 2960) return true; + if (cp >= 2962 && cp <= 2965) return true; + if (cp >= 2969 && cp <= 2970) return true; + if (cp == 2972) return true; + if (cp >= 2974 && cp <= 2975) return true; + if (cp >= 2979 && cp <= 2980) return true; + if (cp >= 2984 && cp <= 2986) return true; + if (cp >= 2990 && cp <= 3001) return true; + if (cp >= 3006 && cp <= 3010) return true; + if (cp >= 3014 && cp <= 3016) return true; + if (cp >= 3018 && cp <= 3020) return true; + if (cp == 3024) return true; + if (cp == 3031) return true; + if (cp >= 3072 && cp <= 3075) return true; + if (cp >= 3077 && cp <= 3084) return true; + if (cp >= 3086 && cp <= 3088) return true; + if (cp >= 3090 && cp <= 3112) return true; + if (cp >= 3114 && cp <= 3129) return true; + if (cp >= 3133 && cp <= 3140) return true; + if (cp >= 3142 && cp <= 3144) return true; + if (cp >= 3146 && cp <= 3148) return true; + if (cp >= 3157 && cp <= 3158) return true; + if (cp >= 3160 && cp <= 3162) return true; + if (cp >= 3168 && cp <= 3171) return true; + if (cp >= 3200 && cp <= 3203) return true; + if (cp >= 3205 && cp <= 3212) return true; + if (cp >= 3214 && cp <= 3216) return true; + if (cp >= 3218 && cp <= 3240) return true; + if (cp >= 3242 && cp <= 3251) return true; + if (cp >= 3253 && cp <= 3257) return true; + if (cp >= 3261 && cp <= 3268) return true; + if (cp >= 3270 && cp <= 3272) return true; + if (cp >= 3274 && cp <= 3276) return true; + if (cp >= 3285 && cp <= 3286) return true; + if (cp == 3294) return true; + if (cp >= 3296 && cp <= 3299) return true; + if (cp >= 3313 && cp <= 3314) return true; + if (cp >= 3328 && cp <= 3331) return true; + if (cp >= 3333 && cp <= 3340) return true; + if (cp >= 3342 && cp <= 3344) return true; + if (cp >= 3346 && cp <= 3386) return true; + if (cp >= 3389 && cp <= 3396) return true; + if (cp >= 3398 && cp <= 3400) return true; + if (cp >= 3402 && cp <= 3404) return true; + if (cp == 3406) return true; + if (cp >= 3412 && cp <= 3415) return true; + if (cp >= 3423 && cp <= 3427) return true; + if (cp >= 3450 && cp <= 3455) return true; + if (cp >= 3458 && cp <= 3459) return true; + if (cp >= 3461 && cp <= 3478) return true; + if (cp >= 3482 && cp <= 3505) return true; + if (cp >= 3507 && cp <= 3515) return true; + if (cp == 3517) return true; + if (cp >= 3520 && cp <= 3526) return true; + if (cp >= 3535 && cp <= 3540) return true; + if (cp == 3542) return true; + if (cp >= 3544 && cp <= 3551) return true; + if (cp >= 3570 && cp <= 3571) return true; + if (cp >= 3585 && cp <= 3642) return true; + if (cp >= 3648 && cp <= 3654) return true; + if (cp == 3661) return true; + if (cp >= 3713 && cp <= 3714) return true; + if (cp == 3716) return true; + if (cp >= 3719 && cp <= 3720) return true; + if (cp == 3722) return true; + if (cp == 3725) return true; + if (cp >= 3732 && cp <= 3735) return true; + if (cp >= 3737 && cp <= 3743) return true; + if (cp >= 3745 && cp <= 3747) return true; + if (cp == 3749) return true; + if (cp == 3751) return true; + if (cp >= 3754 && cp <= 3755) return true; + if (cp >= 3757 && cp <= 3769) return true; + if (cp >= 3771 && cp <= 3773) return true; + if (cp >= 3776 && cp <= 3780) return true; + if (cp == 3782) return true; + if (cp == 3789) return true; + if (cp >= 3804 && cp <= 3807) return true; + if (cp == 3840) return true; + if (cp >= 3904 && cp <= 3911) return true; + if (cp >= 3913 && cp <= 3948) return true; + if (cp >= 3953 && cp <= 3969) return true; + if (cp >= 3976 && cp <= 3991) return true; + if (cp >= 3993 && cp <= 4028) return true; + if (cp >= 4096 && cp <= 4150) return true; + if (cp == 4152) return true; + if (cp >= 4155 && cp <= 4159) return true; + if (cp >= 4176 && cp <= 4194) return true; + if (cp >= 4197 && cp <= 4200) return true; + if (cp >= 4206 && cp <= 4230) return true; + if (cp == 4238) return true; + if (cp >= 4252 && cp <= 4253) return true; + if (cp >= 4256 && cp <= 4293) return true; + if (cp == 4295) return true; + if (cp == 4301) return true; + if (cp >= 4304 && cp <= 4346) return true; + if (cp >= 4348 && cp <= 4680) return true; + if (cp >= 4682 && cp <= 4685) return true; + if (cp >= 4688 && cp <= 4694) return true; + if (cp == 4696) return true; + if (cp >= 4698 && cp <= 4701) return true; + if (cp >= 4704 && cp <= 4744) return true; + if (cp >= 4746 && cp <= 4749) return true; + if (cp >= 4752 && cp <= 4784) return true; + if (cp >= 4786 && cp <= 4789) return true; + if (cp >= 4792 && cp <= 4798) return true; + if (cp == 4800) return true; + if (cp >= 4802 && cp <= 4805) return true; + if (cp >= 4808 && cp <= 4822) return true; + if (cp >= 4824 && cp <= 4880) return true; + if (cp >= 4882 && cp <= 4885) return true; + if (cp >= 4888 && cp <= 4954) return true; + if (cp == 4959) return true; + if (cp >= 4992 && cp <= 5007) return true; + if (cp >= 5024 && cp <= 5109) return true; + if (cp >= 5112 && cp <= 5117) return true; + if (cp >= 5121 && cp <= 5740) return true; + if (cp >= 5743 && cp <= 5759) return true; + if (cp >= 5761 && cp <= 5786) return true; + if (cp >= 5792 && cp <= 5866) return true; + if (cp >= 5870 && cp <= 5880) return true; + if (cp >= 5888 && cp <= 5900) return true; + if (cp >= 5902 && cp <= 5907) return true; + if (cp >= 5920 && cp <= 5939) return true; + if (cp >= 5952 && cp <= 5971) return true; + if (cp >= 5984 && cp <= 5996) return true; + if (cp >= 5998 && cp <= 6000) return true; + if (cp >= 6002 && cp <= 6003) return true; + if (cp >= 6016 && cp <= 6067) return true; + if (cp >= 6070 && cp <= 6088) return true; + if (cp == 6103) return true; + if (cp == 6108) return true; + if (cp >= 6176 && cp <= 6263) return true; + if (cp >= 6272 && cp <= 6314) return true; + if (cp >= 6320 && cp <= 6389) return true; + if (cp >= 6400 && cp <= 6430) return true; + if (cp >= 6432 && cp <= 6443) return true; + if (cp >= 6448 && cp <= 6456) return true; + if (cp >= 6480 && cp <= 6509) return true; + if (cp >= 6512 && cp <= 6516) return true; + if (cp >= 6528 && cp <= 6571) return true; + if (cp >= 6576 && cp <= 6601) return true; + if (cp >= 6656 && cp <= 6683) return true; + if (cp >= 6688 && cp <= 6750) return true; + if (cp >= 6753 && cp <= 6772) return true; + if (cp == 6823) return true; + if (cp >= 6912 && cp <= 6963) return true; + if (cp >= 6965 && cp <= 6979) return true; + if (cp >= 6981 && cp <= 6987) return true; + if (cp >= 7040 && cp <= 7081) return true; + if (cp >= 7084 && cp <= 7087) return true; + if (cp >= 7098 && cp <= 7141) return true; + if (cp >= 7143 && cp <= 7153) return true; + if (cp >= 7168 && cp <= 7221) return true; + if (cp >= 7245 && cp <= 7247) return true; + if (cp >= 7258 && cp <= 7293) return true; + if (cp >= 7296 && cp <= 7304) return true; + if (cp >= 7401 && cp <= 7404) return true; + if (cp >= 7406 && cp <= 7411) return true; + if (cp >= 7413 && cp <= 7414) return true; + if (cp >= 7424 && cp <= 7615) return true; + if (cp >= 7655 && cp <= 7668) return true; + if (cp >= 7680 && cp <= 7957) return true; + if (cp >= 7960 && cp <= 7965) return true; + if (cp >= 7968 && cp <= 8005) return true; + if (cp >= 8008 && cp <= 8013) return true; + if (cp >= 8016 && cp <= 8023) return true; + if (cp == 8025) return true; + if (cp == 8027) return true; + if (cp == 8029) return true; + if (cp >= 8031 && cp <= 8061) return true; + if (cp >= 8064 && cp <= 8116) return true; + if (cp >= 8118 && cp <= 8124) return true; + if (cp == 8126) return true; + if (cp >= 8130 && cp <= 8132) return true; + if (cp >= 8134 && cp <= 8140) return true; + if (cp >= 8144 && cp <= 8147) return true; + if (cp >= 8150 && cp <= 8155) return true; + if (cp >= 8160 && cp <= 8172) return true; + if (cp >= 8178 && cp <= 8180) return true; + if (cp >= 8182 && cp <= 8188) return true; + if (cp == 8305) return true; + if (cp == 8319) return true; + if (cp >= 8336 && cp <= 8348) return true; + if (cp == 8450) return true; + if (cp == 8455) return true; + if (cp >= 8458 && cp <= 8467) return true; + if (cp == 8469) return true; + if (cp >= 8473 && cp <= 8477) return true; + if (cp == 8484) return true; + if (cp == 8486) return true; + if (cp == 8488) return true; + if (cp >= 8490 && cp <= 8493) return true; + if (cp >= 8495 && cp <= 8505) return true; + if (cp >= 8508 && cp <= 8511) return true; + if (cp >= 8517 && cp <= 8521) return true; + if (cp == 8526) return true; + if (cp >= 8544 && cp <= 8584) return true; + if (cp >= 9398 && cp <= 9449) return true; + if (cp >= 11264 && cp <= 11310) return true; + if (cp >= 11312 && cp <= 11358) return true; + if (cp >= 11360 && cp <= 11492) return true; + if (cp >= 11499 && cp <= 11502) return true; + if (cp >= 11506 && cp <= 11507) return true; + if (cp >= 11520 && cp <= 11557) return true; + if (cp == 11559) return true; + if (cp == 11565) return true; + if (cp >= 11568 && cp <= 11623) return true; + if (cp == 11631) return true; + if (cp >= 11648 && cp <= 11670) return true; + if (cp >= 11680 && cp <= 11686) return true; + if (cp >= 11688 && cp <= 11694) return true; + if (cp >= 11696 && cp <= 11702) return true; + if (cp >= 11704 && cp <= 11710) return true; + if (cp >= 11712 && cp <= 11718) return true; + if (cp >= 11720 && cp <= 11726) return true; + if (cp >= 11728 && cp <= 11734) return true; + if (cp >= 11736 && cp <= 11742) return true; + if (cp >= 11744 && cp <= 11775) return true; + if (cp == 11823) return true; + if (cp >= 12293 && cp <= 12295) return true; + if (cp >= 12321 && cp <= 12329) return true; + if (cp >= 12337 && cp <= 12341) return true; + if (cp >= 12344 && cp <= 12348) return true; + if (cp >= 12353 && cp <= 12438) return true; + if (cp >= 12445 && cp <= 12447) return true; + if (cp >= 12449 && cp <= 12538) return true; + if (cp >= 12540 && cp <= 12543) return true; + if (cp >= 12549 && cp <= 12590) return true; + if (cp >= 12593 && cp <= 12686) return true; + if (cp >= 12704 && cp <= 12730) return true; + if (cp >= 12784 && cp <= 12799) return true; + if (cp >= 13312 && cp <= 19893) return true; + if (cp >= 19968 && cp <= 40938) return true; + if (cp >= 40960 && cp <= 42124) return true; + if (cp >= 42192 && cp <= 42237) return true; + if (cp >= 42240 && cp <= 42508) return true; + if (cp >= 42512 && cp <= 42527) return true; + if (cp >= 42538 && cp <= 42539) return true; + if (cp >= 42560 && cp <= 42606) return true; + if (cp >= 42612 && cp <= 42619) return true; + if (cp >= 42623 && cp <= 42735) return true; + if (cp >= 42775 && cp <= 42783) return true; + if (cp >= 42786 && cp <= 42888) return true; + if (cp >= 42891 && cp <= 42926) return true; + if (cp >= 42928 && cp <= 42935) return true; + if (cp >= 42999 && cp <= 43009) return true; + if (cp >= 43011 && cp <= 43013) return true; + if (cp >= 43015 && cp <= 43018) return true; + if (cp >= 43020 && cp <= 43047) return true; + if (cp >= 43072 && cp <= 43123) return true; + if (cp >= 43136 && cp <= 43203) return true; + if (cp == 43205) return true; + if (cp >= 43250 && cp <= 43255) return true; + if (cp == 43259) return true; + if (cp == 43261) return true; + if (cp >= 43274 && cp <= 43306) return true; + if (cp >= 43312 && cp <= 43346) return true; + if (cp >= 43360 && cp <= 43388) return true; + if (cp >= 43392 && cp <= 43442) return true; + if (cp >= 43444 && cp <= 43455) return true; + if (cp == 43471) return true; + if (cp >= 43488 && cp <= 43492) return true; + if (cp >= 43494 && cp <= 43503) return true; + if (cp >= 43514 && cp <= 43518) return true; + if (cp >= 43520 && cp <= 43574) return true; + if (cp >= 43584 && cp <= 43597) return true; + if (cp >= 43616 && cp <= 43638) return true; + if (cp == 43642) return true; + if (cp >= 43646 && cp <= 43710) return true; + if (cp == 43712) return true; + if (cp == 43714) return true; + if (cp >= 43739 && cp <= 43741) return true; + if (cp >= 43744 && cp <= 43759) return true; + if (cp >= 43762 && cp <= 43765) return true; + if (cp >= 43777 && cp <= 43782) return true; + if (cp >= 43785 && cp <= 43790) return true; + if (cp >= 43793 && cp <= 43798) return true; + if (cp >= 43808 && cp <= 43814) return true; + if (cp >= 43816 && cp <= 43822) return true; + if (cp >= 43824 && cp <= 43866) return true; + if (cp >= 43868 && cp <= 43877) return true; + if (cp >= 43888 && cp <= 44010) return true; + if (cp >= 44032 && cp <= 55203) return true; + if (cp >= 55216 && cp <= 55238) return true; + if (cp >= 55243 && cp <= 55291) return true; + if (cp >= 63744 && cp <= 64109) return true; + if (cp >= 64112 && cp <= 64217) return true; + if (cp >= 64256 && cp <= 64262) return true; + if (cp >= 64275 && cp <= 64279) return true; + if (cp >= 64285 && cp <= 64296) return true; + if (cp >= 64298 && cp <= 64310) return true; + if (cp >= 64312 && cp <= 64316) return true; + if (cp == 64318) return true; + if (cp >= 64320 && cp <= 64321) return true; + if (cp >= 64323 && cp <= 64324) return true; + if (cp >= 64326 && cp <= 64433) return true; + if (cp >= 64467 && cp <= 64829) return true; + if (cp >= 64848 && cp <= 64911) return true; + if (cp >= 64914 && cp <= 64967) return true; + if (cp >= 65008 && cp <= 65019) return true; + if (cp >= 65136 && cp <= 65140) return true; + if (cp >= 65142 && cp <= 65276) return true; + if (cp >= 65313 && cp <= 65338) return true; + if (cp >= 65345 && cp <= 65370) return true; + if (cp >= 65382 && cp <= 65470) return true; + if (cp >= 65474 && cp <= 65479) return true; + if (cp >= 65482 && cp <= 65487) return true; + if (cp >= 65490 && cp <= 65495) return true; + if (cp >= 65498 && cp <= 65500) return true; + if (cp >= 65536 && cp <= 65547) return true; + if (cp >= 65549 && cp <= 65574) return true; + if (cp >= 65576 && cp <= 65594) return true; + if (cp >= 65596 && cp <= 65597) return true; + if (cp >= 65599 && cp <= 65613) return true; + if (cp >= 65616 && cp <= 65629) return true; + if (cp >= 65664 && cp <= 65786) return true; + if (cp >= 65856 && cp <= 65908) return true; + if (cp >= 66176 && cp <= 66204) return true; + if (cp >= 66208 && cp <= 66256) return true; + if (cp >= 66304 && cp <= 66335) return true; + if (cp >= 66349 && cp <= 66378) return true; + if (cp >= 66384 && cp <= 66426) return true; + if (cp >= 66432 && cp <= 66461) return true; + if (cp >= 66464 && cp <= 66499) return true; + if (cp >= 66504 && cp <= 66511) return true; + if (cp >= 66513 && cp <= 66517) return true; + if (cp >= 66560 && cp <= 66717) return true; + if (cp >= 66736 && cp <= 66771) return true; + if (cp >= 66776 && cp <= 66811) return true; + if (cp >= 66816 && cp <= 66855) return true; + if (cp >= 66864 && cp <= 66915) return true; + if (cp >= 67072 && cp <= 67382) return true; + if (cp >= 67392 && cp <= 67413) return true; + if (cp >= 67424 && cp <= 67431) return true; + if (cp >= 67584 && cp <= 67589) return true; + if (cp == 67592) return true; + if (cp >= 67594 && cp <= 67637) return true; + if (cp >= 67639 && cp <= 67640) return true; + if (cp == 67644) return true; + if (cp >= 67647 && cp <= 67669) return true; + if (cp >= 67680 && cp <= 67702) return true; + if (cp >= 67712 && cp <= 67742) return true; + if (cp >= 67808 && cp <= 67826) return true; + if (cp >= 67828 && cp <= 67829) return true; + if (cp >= 67840 && cp <= 67861) return true; + if (cp >= 67872 && cp <= 67897) return true; + if (cp >= 67968 && cp <= 68023) return true; + if (cp >= 68030 && cp <= 68031) return true; + if (cp >= 68096 && cp <= 68099) return true; + if (cp >= 68101 && cp <= 68102) return true; + if (cp >= 68108 && cp <= 68115) return true; + if (cp >= 68117 && cp <= 68119) return true; + if (cp >= 68121 && cp <= 68147) return true; + if (cp >= 68192 && cp <= 68220) return true; + if (cp >= 68224 && cp <= 68252) return true; + if (cp >= 68288 && cp <= 68295) return true; + if (cp >= 68297 && cp <= 68324) return true; + if (cp >= 68352 && cp <= 68405) return true; + if (cp >= 68416 && cp <= 68437) return true; + if (cp >= 68448 && cp <= 68466) return true; + if (cp >= 68480 && cp <= 68497) return true; + if (cp >= 68608 && cp <= 68680) return true; + if (cp >= 68736 && cp <= 68786) return true; + if (cp >= 68800 && cp <= 68850) return true; + if (cp >= 69632 && cp <= 69701) return true; + if (cp >= 69762 && cp <= 69816) return true; + if (cp >= 69840 && cp <= 69864) return true; + if (cp >= 69888 && cp <= 69938) return true; + if (cp >= 69968 && cp <= 70002) return true; + if (cp == 70006) return true; + if (cp >= 70016 && cp <= 70079) return true; + if (cp >= 70081 && cp <= 70084) return true; + if (cp == 70106) return true; + if (cp == 70108) return true; + if (cp >= 70144 && cp <= 70161) return true; + if (cp >= 70163 && cp <= 70196) return true; + if (cp == 70199) return true; + if (cp == 70206) return true; + if (cp >= 70272 && cp <= 70278) return true; + if (cp == 70280) return true; + if (cp >= 70282 && cp <= 70285) return true; + if (cp >= 70287 && cp <= 70301) return true; + if (cp >= 70303 && cp <= 70312) return true; + if (cp >= 70320 && cp <= 70376) return true; + if (cp >= 70400 && cp <= 70403) return true; + if (cp >= 70405 && cp <= 70412) return true; + if (cp >= 70415 && cp <= 70416) return true; + if (cp >= 70419 && cp <= 70440) return true; + if (cp >= 70442 && cp <= 70448) return true; + if (cp >= 70450 && cp <= 70451) return true; + if (cp >= 70453 && cp <= 70457) return true; + if (cp >= 70461 && cp <= 70468) return true; + if (cp >= 70471 && cp <= 70472) return true; + if (cp >= 70475 && cp <= 70476) return true; + if (cp == 70480) return true; + if (cp == 70487) return true; + if (cp >= 70493 && cp <= 70499) return true; + if (cp >= 70656 && cp <= 70721) return true; + if (cp >= 70723 && cp <= 70725) return true; + if (cp >= 70727 && cp <= 70730) return true; + if (cp >= 70784 && cp <= 70849) return true; + if (cp >= 70852 && cp <= 70853) return true; + if (cp == 70855) return true; + if (cp >= 71040 && cp <= 71093) return true; + if (cp >= 71096 && cp <= 71102) return true; + if (cp >= 71128 && cp <= 71133) return true; + if (cp >= 71168 && cp <= 71230) return true; + if (cp == 71232) return true; + if (cp == 71236) return true; + if (cp >= 71296 && cp <= 71349) return true; + if (cp >= 71424 && cp <= 71449) return true; + if (cp >= 71453 && cp <= 71466) return true; + if (cp >= 71840 && cp <= 71903) return true; + if (cp == 71935) return true; + if (cp >= 72192 && cp <= 72242) return true; + if (cp >= 72245 && cp <= 72254) return true; + if (cp >= 72272 && cp <= 72323) return true; + if (cp >= 72326 && cp <= 72343) return true; + if (cp >= 72384 && cp <= 72440) return true; + if (cp >= 72704 && cp <= 72712) return true; + if (cp >= 72714 && cp <= 72758) return true; + if (cp >= 72760 && cp <= 72766) return true; + if (cp == 72768) return true; + if (cp >= 72818 && cp <= 72847) return true; + if (cp >= 72850 && cp <= 72871) return true; + if (cp >= 72873 && cp <= 72886) return true; + if (cp >= 72960 && cp <= 72966) return true; + if (cp >= 72968 && cp <= 72969) return true; + if (cp >= 72971 && cp <= 73014) return true; + if (cp == 73018) return true; + if (cp >= 73020 && cp <= 73021) return true; + if (cp >= 73023 && cp <= 73025) return true; + if (cp == 73027) return true; + if (cp >= 73030 && cp <= 73031) return true; + if (cp >= 73728 && cp <= 74649) return true; + if (cp >= 74752 && cp <= 74862) return true; + if (cp >= 74880 && cp <= 75075) return true; + if (cp >= 77824 && cp <= 78894) return true; + if (cp >= 82944 && cp <= 83526) return true; + if (cp >= 92160 && cp <= 92728) return true; + if (cp >= 92736 && cp <= 92766) return true; + if (cp >= 92880 && cp <= 92909) return true; + if (cp >= 92928 && cp <= 92982) return true; + if (cp >= 92992 && cp <= 92995) return true; + if (cp >= 93027 && cp <= 93047) return true; + if (cp >= 93053 && cp <= 93071) return true; + if (cp >= 93952 && cp <= 94020) return true; + if (cp >= 94032 && cp <= 94078) return true; + if (cp >= 94099 && cp <= 94111) return true; + if (cp >= 94176 && cp <= 94177) return true; + if (cp >= 94208 && cp <= 100332) return true; + if (cp >= 100352 && cp <= 101106) return true; + if (cp >= 110592 && cp <= 110878) return true; + if (cp >= 110960 && cp <= 111355) return true; + if (cp >= 113664 && cp <= 113770) return true; + if (cp >= 113776 && cp <= 113788) return true; + if (cp >= 113792 && cp <= 113800) return true; + if (cp >= 113808 && cp <= 113817) return true; + if (cp == 113822) return true; + if (cp >= 119808 && cp <= 119892) return true; + if (cp >= 119894 && cp <= 119964) return true; + if (cp >= 119966 && cp <= 119967) return true; + if (cp == 119970) return true; + if (cp >= 119973 && cp <= 119974) return true; + if (cp >= 119977 && cp <= 119980) return true; + if (cp >= 119982 && cp <= 119993) return true; + if (cp == 119995) return true; + if (cp >= 119997 && cp <= 120003) return true; + if (cp >= 120005 && cp <= 120069) return true; + if (cp >= 120071 && cp <= 120074) return true; + if (cp >= 120077 && cp <= 120084) return true; + if (cp >= 120086 && cp <= 120092) return true; + if (cp >= 120094 && cp <= 120121) return true; + if (cp >= 120123 && cp <= 120126) return true; + if (cp >= 120128 && cp <= 120132) return true; + if (cp == 120134) return true; + if (cp >= 120138 && cp <= 120144) return true; + if (cp >= 120146 && cp <= 120485) return true; + if (cp >= 120488 && cp <= 120512) return true; + if (cp >= 120514 && cp <= 120538) return true; + if (cp >= 120540 && cp <= 120570) return true; + if (cp >= 120572 && cp <= 120596) return true; + if (cp >= 120598 && cp <= 120628) return true; + if (cp >= 120630 && cp <= 120654) return true; + if (cp >= 120656 && cp <= 120686) return true; + if (cp >= 120688 && cp <= 120712) return true; + if (cp >= 120714 && cp <= 120744) return true; + if (cp >= 120746 && cp <= 120770) return true; + if (cp >= 120772 && cp <= 120779) return true; + if (cp >= 122880 && cp <= 122886) return true; + if (cp >= 122888 && cp <= 122904) return true; + if (cp >= 122907 && cp <= 122913) return true; + if (cp >= 122915 && cp <= 122916) return true; + if (cp >= 122918 && cp <= 122922) return true; + if (cp >= 124928 && cp <= 125124) return true; + if (cp >= 125184 && cp <= 125251) return true; + if (cp == 125255) return true; + if (cp >= 126464 && cp <= 126467) return true; + if (cp >= 126469 && cp <= 126495) return true; + if (cp >= 126497 && cp <= 126498) return true; + if (cp == 126500) return true; + if (cp == 126503) return true; + if (cp >= 126505 && cp <= 126514) return true; + if (cp >= 126516 && cp <= 126519) return true; + if (cp == 126521) return true; + if (cp == 126523) return true; + if (cp == 126530) return true; + if (cp == 126535) return true; + if (cp == 126537) return true; + if (cp == 126539) return true; + if (cp >= 126541 && cp <= 126543) return true; + if (cp >= 126545 && cp <= 126546) return true; + if (cp == 126548) return true; + if (cp == 126551) return true; + if (cp == 126553) return true; + if (cp == 126555) return true; + if (cp == 126557) return true; + if (cp == 126559) return true; + if (cp >= 126561 && cp <= 126562) return true; + if (cp == 126564) return true; + if (cp >= 126567 && cp <= 126570) return true; + if (cp >= 126572 && cp <= 126578) return true; + if (cp >= 126580 && cp <= 126583) return true; + if (cp >= 126585 && cp <= 126588) return true; + if (cp == 126590) return true; + if (cp >= 126592 && cp <= 126601) return true; + if (cp >= 126603 && cp <= 126619) return true; + if (cp >= 126625 && cp <= 126627) return true; + if (cp >= 126629 && cp <= 126633) return true; + if (cp >= 126635 && cp <= 126651) return true; + if (cp >= 127280 && cp <= 127305) return true; + if (cp >= 127312 && cp <= 127337) return true; + if (cp >= 127344 && cp <= 127369) return true; + if (cp >= 131072 && cp <= 173782) return true; + if (cp >= 173824 && cp <= 177972) return true; + if (cp >= 177984 && cp <= 178205) return true; + if (cp >= 178208 && cp <= 183969) return true; + if (cp >= 183984 && cp <= 191456) return true; + if (cp >= 194560 && cp <= 195101) return true; + + return false; +} + function isDigit(c) { var cp = ord(c); - if (cp >= 48 && c <= 57) + if (cp >= 48 && cp <= 57) return true; - else if (cp >= 1632 && cp <= 1641) + if (cp >= 1632 && cp <= 1641) return true; - else if (cp >= 1776 && cp <= 1785) + if (cp >= 1776 && cp <= 1785) return true; - else if (cp >= 1984 && cp <= 1993) + if (cp >= 1984 && cp <= 1993) return true; - else if (cp >= 2406 && cp <= 2415) + if (cp >= 2406 && cp <= 2415) return true; - else if (cp >= 2534 && cp <= 2543) + if (cp >= 2534 && cp <= 2543) return true; - else if (cp >= 2662 && cp <= 2671) + if (cp >= 2662 && cp <= 2671) return true; - else if (cp >= 2790 && cp <= 2799) + if (cp >= 2790 && cp <= 2799) return true; - else if (cp >= 2918 && cp <= 2927) + if (cp >= 2918 && cp <= 2927) return true; - else if (cp >= 3046 && cp <= 3055) + if (cp >= 3046 && cp <= 3055) return true; - else if (cp >= 3174 && cp <= 3183) + if (cp >= 3174 && cp <= 3183) return true; - else if (cp >= 3302 && cp <= 3311) + if (cp >= 3302 && cp <= 3311) return true; - else if (cp >= 3430 && cp <= 3439) + if (cp >= 3430 && cp <= 3439) return true; - else if (cp >= 3558 && cp <= 3567) + if (cp >= 3558 && cp <= 3567) return true; - else if (cp >= 3664 && cp <= 3673) + if (cp >= 3664 && cp <= 3673) return true; - else if (cp >= 3792 && cp <= 3801) + if (cp >= 3792 && cp <= 3801) return true; - else if (cp >= 3872 && cp <= 3881) + if (cp >= 3872 && cp <= 3881) return true; - else if (cp >= 4160 && cp <= 4169) + if (cp >= 4160 && cp <= 4169) return true; - else if (cp >= 4240 && cp <= 4249) + if (cp >= 4240 && cp <= 4249) return true; - else if (cp >= 6112 && cp <= 6121) + if (cp >= 6112 && cp <= 6121) return true; - else if (cp >= 6160 && cp <= 6169) + if (cp >= 6160 && cp <= 6169) return true; - else if (cp >= 6470 && cp <= 6479) + if (cp >= 6470 && cp <= 6479) return true; - else if (cp >= 6608 && cp <= 6617) + if (cp >= 6608 && cp <= 6617) return true; - else if (cp >= 6784 && cp <= 6793) + if (cp >= 6784 && cp <= 6793) return true; - else if (cp >= 6800 && cp <= 6809) + if (cp >= 6800 && cp <= 6809) return true; - else if (cp >= 6992 && cp <= 7001) + if (cp >= 6992 && cp <= 7001) return true; - else if (cp >= 7088 && cp <= 7097) + if (cp >= 7088 && cp <= 7097) return true; - else if (cp >= 7232 && cp <= 7241) + if (cp >= 7232 && cp <= 7241) return true; - else if (cp >= 7248 && cp <= 7257) + if (cp >= 7248 && cp <= 7257) return true; - else if (cp >= 42528 && cp <= 42537) + if (cp >= 42528 && cp <= 42537) return true; - else if (cp >= 43216 && cp <= 43225) + if (cp >= 43216 && cp <= 43225) return true; - else if (cp >= 43264 && cp <= 43273) + if (cp >= 43264 && cp <= 43273) return true; - else if (cp >= 43472 && cp <= 43481) + if (cp >= 43472 && cp <= 43481) return true; - else if (cp >= 43504 && cp <= 43513) + if (cp >= 43504 && cp <= 43513) return true; - else if (cp >= 43600 && cp <= 43609) + if (cp >= 43600 && cp <= 43609) return true; - else if (cp >= 44016 && cp <= 44025) + if (cp >= 44016 && cp <= 44025) return true; - else if (cp >= 65296 && cp <= 65305) + if (cp >= 65296 && cp <= 65305) return true; - else if (cp >= 66720 && cp <= 66729) + if (cp >= 66720 && cp <= 66729) return true; - else if (cp >= 69734 && cp <= 69743) + if (cp >= 69734 && cp <= 69743) return true; - else if (cp >= 69872 && cp <= 69881) + if (cp >= 69872 && cp <= 69881) return true; - else if (cp >= 69942 && cp <= 69951) + if (cp >= 69942 && cp <= 69951) return true; - else if (cp >= 70096 && cp <= 70105) + if (cp >= 70096 && cp <= 70105) return true; - else if (cp >= 70384 && cp <= 70393) + if (cp >= 70384 && cp <= 70393) return true; - else if (cp >= 70736 && cp <= 70745) + if (cp >= 70736 && cp <= 70745) return true; - else if (cp >= 70864 && cp <= 70873) + if (cp >= 70864 && cp <= 70873) return true; - else if (cp >= 71248 && cp <= 71257) + if (cp >= 71248 && cp <= 71257) return true; - else if (cp >= 71360 && cp <= 71369) + if (cp >= 71360 && cp <= 71369) return true; - else if (cp >= 71472 && cp <= 71481) + if (cp >= 71472 && cp <= 71481) return true; - else if (cp >= 71904 && cp <= 71913) + if (cp >= 71904 && cp <= 71913) return true; - else if (cp >= 72784 && cp <= 72793) + if (cp >= 72784 && cp <= 72793) return true; - else if (cp >= 73040 && cp <= 73049) + if (cp >= 73040 && cp <= 73049) return true; - else if (cp >= 92768 && cp <= 92777) + if (cp >= 92768 && cp <= 92777) return true; - else if (cp >= 93008 && cp <= 93017) + if (cp >= 93008 && cp <= 93017) return true; - else if (cp >= 120782 && cp <= 120831) + if (cp >= 120782 && cp <= 120831) return true; - else if (cp >= 125264 && cp <= 125273) + if (cp >= 125264 && cp <= 125273) return true; return false; } + function isAlnum(c) { return isAlpha(c) || isDigit(c); } -function isBlank(c) { return c == ' ' || c == '\t'; } -function isSpace(c) { return isBlank(c) || c == '\r' || c == '\n'; } -function isXdigit(c) { return isDigit(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } -function ord(c) { return c.codePointAt(0); } -function isPrint(c) { return ord(c) > 31 && ord(c) != 127; } +function isBlank(c) { + var cp = ord(c); + if (cp == 9) + return true; + if (cp == 32) + return true; + if (cp == 160) + return true; + if (cp == 5760) + return true; + if (cp >= 8192 && cp <= 8202) + return true; + if (cp == 8239) + return true; + if (cp == 8287) + return true; + if (cp == 12288) + return true; + + return false; +} +function isSpace(c) { + var cp = ord(c); + if (cp == 10) + return true; + if (cp == 13) + return true; + if (cp == 133) + return true; + if (cp == 8232) + return true; + if (cp == 8233) + return true; + + return isBlank(c); +} +function isXdigit(c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); } + +function isPrint(c) { + var cp = ord(c); + if (cp >= 32 && cp <= 126) return true; + if (cp >= 160 && cp <= 887) return true; + if (cp >= 890 && cp <= 895) return true; + if (cp >= 900 && cp <= 906) return true; + if (cp == 908) return true; + if (cp >= 910 && cp <= 929) return true; + if (cp >= 931 && cp <= 1327) return true; + if (cp >= 1329 && cp <= 1366) return true; + if (cp >= 1369 && cp <= 1375) return true; + if (cp >= 1377 && cp <= 1415) return true; + if (cp >= 1417 && cp <= 1418) return true; + if (cp >= 1421 && cp <= 1423) return true; + if (cp >= 1425 && cp <= 1479) return true; + if (cp >= 1488 && cp <= 1514) return true; + if (cp >= 1520 && cp <= 1524) return true; + if (cp >= 1536 && cp <= 1564) return true; + if (cp >= 1566 && cp <= 1805) return true; + if (cp >= 1807 && cp <= 1866) return true; + if (cp >= 1869 && cp <= 1969) return true; + if (cp >= 1984 && cp <= 2042) return true; + if (cp >= 2048 && cp <= 2093) return true; + if (cp >= 2096 && cp <= 2110) return true; + if (cp >= 2112 && cp <= 2139) return true; + if (cp == 2142) return true; + if (cp >= 2144 && cp <= 2154) return true; + if (cp >= 2208 && cp <= 2228) return true; + if (cp >= 2230 && cp <= 2237) return true; + if (cp >= 2260 && cp <= 2435) return true; + if (cp >= 2437 && cp <= 2444) return true; + if (cp >= 2447 && cp <= 2448) return true; + if (cp >= 2451 && cp <= 2472) return true; + if (cp >= 2474 && cp <= 2480) return true; + if (cp == 2482) return true; + if (cp >= 2486 && cp <= 2489) return true; + if (cp >= 2492 && cp <= 2500) return true; + if (cp >= 2503 && cp <= 2504) return true; + if (cp >= 2507 && cp <= 2510) return true; + if (cp == 2519) return true; + if (cp >= 2524 && cp <= 2525) return true; + if (cp >= 2527 && cp <= 2531) return true; + if (cp >= 2534 && cp <= 2557) return true; + if (cp >= 2561 && cp <= 2563) return true; + if (cp >= 2565 && cp <= 2570) return true; + if (cp >= 2575 && cp <= 2576) return true; + if (cp >= 2579 && cp <= 2600) return true; + if (cp >= 2602 && cp <= 2608) return true; + if (cp >= 2610 && cp <= 2611) return true; + if (cp >= 2613 && cp <= 2614) return true; + if (cp >= 2616 && cp <= 2617) return true; + if (cp == 2620) return true; + if (cp >= 2622 && cp <= 2626) return true; + if (cp >= 2631 && cp <= 2632) return true; + if (cp >= 2635 && cp <= 2637) return true; + if (cp == 2641) return true; + if (cp >= 2649 && cp <= 2652) return true; + if (cp == 2654) return true; + if (cp >= 2662 && cp <= 2677) return true; + if (cp >= 2689 && cp <= 2691) return true; + if (cp >= 2693 && cp <= 2701) return true; + if (cp >= 2703 && cp <= 2705) return true; + if (cp >= 2707 && cp <= 2728) return true; + if (cp >= 2730 && cp <= 2736) return true; + if (cp >= 2738 && cp <= 2739) return true; + if (cp >= 2741 && cp <= 2745) return true; + if (cp >= 2748 && cp <= 2757) return true; + if (cp >= 2759 && cp <= 2761) return true; + if (cp >= 2763 && cp <= 2765) return true; + if (cp == 2768) return true; + if (cp >= 2784 && cp <= 2787) return true; + if (cp >= 2790 && cp <= 2801) return true; + if (cp >= 2809 && cp <= 2815) return true; + if (cp >= 2817 && cp <= 2819) return true; + if (cp >= 2821 && cp <= 2828) return true; + if (cp >= 2831 && cp <= 2832) return true; + if (cp >= 2835 && cp <= 2856) return true; + if (cp >= 2858 && cp <= 2864) return true; + if (cp >= 2866 && cp <= 2867) return true; + if (cp >= 2869 && cp <= 2873) return true; + if (cp >= 2876 && cp <= 2884) return true; + if (cp >= 2887 && cp <= 2888) return true; + if (cp >= 2891 && cp <= 2893) return true; + if (cp >= 2902 && cp <= 2903) return true; + if (cp >= 2908 && cp <= 2909) return true; + if (cp >= 2911 && cp <= 2915) return true; + if (cp >= 2918 && cp <= 2935) return true; + if (cp >= 2946 && cp <= 2947) return true; + if (cp >= 2949 && cp <= 2954) return true; + if (cp >= 2958 && cp <= 2960) return true; + if (cp >= 2962 && cp <= 2965) return true; + if (cp >= 2969 && cp <= 2970) return true; + if (cp == 2972) return true; + if (cp >= 2974 && cp <= 2975) return true; + if (cp >= 2979 && cp <= 2980) return true; + if (cp >= 2984 && cp <= 2986) return true; + if (cp >= 2990 && cp <= 3001) return true; + if (cp >= 3006 && cp <= 3010) return true; + if (cp >= 3014 && cp <= 3016) return true; + if (cp >= 3018 && cp <= 3021) return true; + if (cp == 3024) return true; + if (cp == 3031) return true; + if (cp >= 3046 && cp <= 3066) return true; + if (cp >= 3072 && cp <= 3075) return true; + if (cp >= 3077 && cp <= 3084) return true; + if (cp >= 3086 && cp <= 3088) return true; + if (cp >= 3090 && cp <= 3112) return true; + if (cp >= 3114 && cp <= 3129) return true; + if (cp >= 3133 && cp <= 3140) return true; + if (cp >= 3142 && cp <= 3144) return true; + if (cp >= 3146 && cp <= 3149) return true; + if (cp >= 3157 && cp <= 3158) return true; + if (cp >= 3160 && cp <= 3162) return true; + if (cp >= 3168 && cp <= 3171) return true; + if (cp >= 3174 && cp <= 3183) return true; + if (cp >= 3192 && cp <= 3203) return true; + if (cp >= 3205 && cp <= 3212) return true; + if (cp >= 3214 && cp <= 3216) return true; + if (cp >= 3218 && cp <= 3240) return true; + if (cp >= 3242 && cp <= 3251) return true; + if (cp >= 3253 && cp <= 3257) return true; + if (cp >= 3260 && cp <= 3268) return true; + if (cp >= 3270 && cp <= 3272) return true; + if (cp >= 3274 && cp <= 3277) return true; + if (cp >= 3285 && cp <= 3286) return true; + if (cp == 3294) return true; + if (cp >= 3296 && cp <= 3299) return true; + if (cp >= 3302 && cp <= 3311) return true; + if (cp >= 3313 && cp <= 3314) return true; + if (cp >= 3328 && cp <= 3331) return true; + if (cp >= 3333 && cp <= 3340) return true; + if (cp >= 3342 && cp <= 3344) return true; + if (cp >= 3346 && cp <= 3396) return true; + if (cp >= 3398 && cp <= 3400) return true; + if (cp >= 3402 && cp <= 3407) return true; + if (cp >= 3412 && cp <= 3427) return true; + if (cp >= 3430 && cp <= 3455) return true; + if (cp >= 3458 && cp <= 3459) return true; + if (cp >= 3461 && cp <= 3478) return true; + if (cp >= 3482 && cp <= 3505) return true; + if (cp >= 3507 && cp <= 3515) return true; + if (cp == 3517) return true; + if (cp >= 3520 && cp <= 3526) return true; + if (cp == 3530) return true; + if (cp >= 3535 && cp <= 3540) return true; + if (cp == 3542) return true; + if (cp >= 3544 && cp <= 3551) return true; + if (cp >= 3558 && cp <= 3567) return true; + if (cp >= 3570 && cp <= 3572) return true; + if (cp >= 3585 && cp <= 3642) return true; + if (cp >= 3647 && cp <= 3675) return true; + if (cp >= 3713 && cp <= 3714) return true; + if (cp == 3716) return true; + if (cp >= 3719 && cp <= 3720) return true; + if (cp == 3722) return true; + if (cp == 3725) return true; + if (cp >= 3732 && cp <= 3735) return true; + if (cp >= 3737 && cp <= 3743) return true; + if (cp >= 3745 && cp <= 3747) return true; + if (cp == 3749) return true; + if (cp == 3751) return true; + if (cp >= 3754 && cp <= 3755) return true; + if (cp >= 3757 && cp <= 3769) return true; + if (cp >= 3771 && cp <= 3773) return true; + if (cp >= 3776 && cp <= 3780) return true; + if (cp == 3782) return true; + if (cp >= 3784 && cp <= 3789) return true; + if (cp >= 3792 && cp <= 3801) return true; + if (cp >= 3804 && cp <= 3807) return true; + if (cp >= 3840 && cp <= 3911) return true; + if (cp >= 3913 && cp <= 3948) return true; + if (cp >= 3953 && cp <= 3991) return true; + if (cp >= 3993 && cp <= 4028) return true; + if (cp >= 4030 && cp <= 4044) return true; + if (cp >= 4046 && cp <= 4058) return true; + if (cp >= 4096 && cp <= 4293) return true; + if (cp == 4295) return true; + if (cp == 4301) return true; + if (cp >= 4304 && cp <= 4680) return true; + if (cp >= 4682 && cp <= 4685) return true; + if (cp >= 4688 && cp <= 4694) return true; + if (cp == 4696) return true; + if (cp >= 4698 && cp <= 4701) return true; + if (cp >= 4704 && cp <= 4744) return true; + if (cp >= 4746 && cp <= 4749) return true; + if (cp >= 4752 && cp <= 4784) return true; + if (cp >= 4786 && cp <= 4789) return true; + if (cp >= 4792 && cp <= 4798) return true; + if (cp == 4800) return true; + if (cp >= 4802 && cp <= 4805) return true; + if (cp >= 4808 && cp <= 4822) return true; + if (cp >= 4824 && cp <= 4880) return true; + if (cp >= 4882 && cp <= 4885) return true; + if (cp >= 4888 && cp <= 4954) return true; + if (cp >= 4957 && cp <= 4988) return true; + if (cp >= 4992 && cp <= 5017) return true; + if (cp >= 5024 && cp <= 5109) return true; + if (cp >= 5112 && cp <= 5117) return true; + if (cp >= 5120 && cp <= 5788) return true; + if (cp >= 5792 && cp <= 5880) return true; + if (cp >= 5888 && cp <= 5900) return true; + if (cp >= 5902 && cp <= 5908) return true; + if (cp >= 5920 && cp <= 5942) return true; + if (cp >= 5952 && cp <= 5971) return true; + if (cp >= 5984 && cp <= 5996) return true; + if (cp >= 5998 && cp <= 6000) return true; + if (cp >= 6002 && cp <= 6003) return true; + if (cp >= 6016 && cp <= 6109) return true; + if (cp >= 6112 && cp <= 6121) return true; + if (cp >= 6128 && cp <= 6137) return true; + if (cp >= 6144 && cp <= 6158) return true; + if (cp >= 6160 && cp <= 6169) return true; + if (cp >= 6176 && cp <= 6263) return true; + if (cp >= 6272 && cp <= 6314) return true; + if (cp >= 6320 && cp <= 6389) return true; + if (cp >= 6400 && cp <= 6430) return true; + if (cp >= 6432 && cp <= 6443) return true; + if (cp >= 6448 && cp <= 6459) return true; + if (cp == 6464) return true; + if (cp >= 6468 && cp <= 6509) return true; + if (cp >= 6512 && cp <= 6516) return true; + if (cp >= 6528 && cp <= 6571) return true; + if (cp >= 6576 && cp <= 6601) return true; + if (cp >= 6608 && cp <= 6618) return true; + if (cp >= 6622 && cp <= 6683) return true; + if (cp >= 6686 && cp <= 6750) return true; + if (cp >= 6752 && cp <= 6780) return true; + if (cp >= 6783 && cp <= 6793) return true; + if (cp >= 6800 && cp <= 6809) return true; + if (cp >= 6816 && cp <= 6829) return true; + if (cp >= 6832 && cp <= 6846) return true; + if (cp >= 6912 && cp <= 6987) return true; + if (cp >= 6992 && cp <= 7036) return true; + if (cp >= 7040 && cp <= 7155) return true; + if (cp >= 7164 && cp <= 7223) return true; + if (cp >= 7227 && cp <= 7241) return true; + if (cp >= 7245 && cp <= 7304) return true; + if (cp >= 7360 && cp <= 7367) return true; + if (cp >= 7376 && cp <= 7417) return true; + if (cp >= 7424 && cp <= 7673) return true; + if (cp >= 7675 && cp <= 7957) return true; + if (cp >= 7960 && cp <= 7965) return true; + if (cp >= 7968 && cp <= 8005) return true; + if (cp >= 8008 && cp <= 8013) return true; + if (cp >= 8016 && cp <= 8023) return true; + if (cp == 8025) return true; + if (cp == 8027) return true; + if (cp == 8029) return true; + if (cp >= 8031 && cp <= 8061) return true; + if (cp >= 8064 && cp <= 8116) return true; + if (cp >= 8118 && cp <= 8132) return true; + if (cp >= 8134 && cp <= 8147) return true; + if (cp >= 8150 && cp <= 8155) return true; + if (cp >= 8157 && cp <= 8175) return true; + if (cp >= 8178 && cp <= 8180) return true; + if (cp >= 8182 && cp <= 8190) return true; + if (cp >= 8192 && cp <= 8231) return true; + if (cp >= 8234 && cp <= 8292) return true; + if (cp >= 8294 && cp <= 8305) return true; + if (cp >= 8308 && cp <= 8334) return true; + if (cp >= 8336 && cp <= 8348) return true; + if (cp >= 8352 && cp <= 8383) return true; + if (cp >= 8400 && cp <= 8432) return true; + if (cp >= 8448 && cp <= 8587) return true; + if (cp >= 8592 && cp <= 9254) return true; + if (cp >= 9280 && cp <= 9290) return true; + if (cp >= 9312 && cp <= 11123) return true; + if (cp >= 11126 && cp <= 11157) return true; + if (cp >= 11160 && cp <= 11193) return true; + if (cp >= 11197 && cp <= 11208) return true; + if (cp >= 11210 && cp <= 11218) return true; + if (cp >= 11244 && cp <= 11247) return true; + if (cp >= 11264 && cp <= 11310) return true; + if (cp >= 11312 && cp <= 11358) return true; + if (cp >= 11360 && cp <= 11507) return true; + if (cp >= 11513 && cp <= 11557) return true; + if (cp == 11559) return true; + if (cp == 11565) return true; + if (cp >= 11568 && cp <= 11623) return true; + if (cp >= 11631 && cp <= 11632) return true; + if (cp >= 11647 && cp <= 11670) return true; + if (cp >= 11680 && cp <= 11686) return true; + if (cp >= 11688 && cp <= 11694) return true; + if (cp >= 11696 && cp <= 11702) return true; + if (cp >= 11704 && cp <= 11710) return true; + if (cp >= 11712 && cp <= 11718) return true; + if (cp >= 11720 && cp <= 11726) return true; + if (cp >= 11728 && cp <= 11734) return true; + if (cp >= 11736 && cp <= 11742) return true; + if (cp >= 11744 && cp <= 11849) return true; + if (cp >= 11904 && cp <= 11929) return true; + if (cp >= 11931 && cp <= 12019) return true; + if (cp >= 12032 && cp <= 12245) return true; + if (cp >= 12272 && cp <= 12283) return true; + if (cp >= 12288 && cp <= 12351) return true; + if (cp >= 12353 && cp <= 12438) return true; + if (cp >= 12441 && cp <= 12543) return true; + if (cp >= 12549 && cp <= 12590) return true; + if (cp >= 12593 && cp <= 12686) return true; + if (cp >= 12688 && cp <= 12730) return true; + if (cp >= 12736 && cp <= 12771) return true; + if (cp >= 12784 && cp <= 12830) return true; + if (cp >= 12832 && cp <= 13054) return true; + if (cp >= 13056 && cp <= 19893) return true; + if (cp >= 19904 && cp <= 40938) return true; + if (cp >= 40960 && cp <= 42124) return true; + if (cp >= 42128 && cp <= 42182) return true; + if (cp >= 42192 && cp <= 42539) return true; + if (cp >= 42560 && cp <= 42743) return true; + if (cp >= 42752 && cp <= 42926) return true; + if (cp >= 42928 && cp <= 42935) return true; + if (cp >= 42999 && cp <= 43051) return true; + if (cp >= 43056 && cp <= 43065) return true; + if (cp >= 43072 && cp <= 43127) return true; + if (cp >= 43136 && cp <= 43205) return true; + if (cp >= 43214 && cp <= 43225) return true; + if (cp >= 43232 && cp <= 43261) return true; + if (cp >= 43264 && cp <= 43347) return true; + if (cp >= 43359 && cp <= 43388) return true; + if (cp >= 43392 && cp <= 43469) return true; + if (cp >= 43471 && cp <= 43481) return true; + if (cp >= 43486 && cp <= 43518) return true; + if (cp >= 43520 && cp <= 43574) return true; + if (cp >= 43584 && cp <= 43597) return true; + if (cp >= 43600 && cp <= 43609) return true; + if (cp >= 43612 && cp <= 43714) return true; + if (cp >= 43739 && cp <= 43766) return true; + if (cp >= 43777 && cp <= 43782) return true; + if (cp >= 43785 && cp <= 43790) return true; + if (cp >= 43793 && cp <= 43798) return true; + if (cp >= 43808 && cp <= 43814) return true; + if (cp >= 43816 && cp <= 43822) return true; + if (cp >= 43824 && cp <= 43877) return true; + if (cp >= 43888 && cp <= 44013) return true; + if (cp >= 44016 && cp <= 44025) return true; + if (cp >= 44032 && cp <= 55203) return true; + if (cp >= 55216 && cp <= 55238) return true; + if (cp >= 55243 && cp <= 55291) return true; + if (cp >= 57344 && cp <= 64109) return true; + if (cp >= 64112 && cp <= 64217) return true; + if (cp >= 64256 && cp <= 64262) return true; + if (cp >= 64275 && cp <= 64279) return true; + if (cp >= 64285 && cp <= 64310) return true; + if (cp >= 64312 && cp <= 64316) return true; + if (cp == 64318) return true; + if (cp >= 64320 && cp <= 64321) return true; + if (cp >= 64323 && cp <= 64324) return true; + if (cp >= 64326 && cp <= 64449) return true; + if (cp >= 64467 && cp <= 64831) return true; + if (cp >= 64848 && cp <= 64911) return true; + if (cp >= 64914 && cp <= 64967) return true; + if (cp >= 65008 && cp <= 65021) return true; + if (cp >= 65024 && cp <= 65049) return true; + if (cp >= 65056 && cp <= 65106) return true; + if (cp >= 65108 && cp <= 65126) return true; + if (cp >= 65128 && cp <= 65131) return true; + if (cp >= 65136 && cp <= 65140) return true; + if (cp >= 65142 && cp <= 65276) return true; + if (cp == 65279) return true; + if (cp >= 65281 && cp <= 65470) return true; + if (cp >= 65474 && cp <= 65479) return true; + if (cp >= 65482 && cp <= 65487) return true; + if (cp >= 65490 && cp <= 65495) return true; + if (cp >= 65498 && cp <= 65500) return true; + if (cp >= 65504 && cp <= 65510) return true; + if (cp >= 65512 && cp <= 65518) return true; + if (cp >= 65529 && cp <= 65533) return true; + if (cp >= 65536 && cp <= 65547) return true; + if (cp >= 65549 && cp <= 65574) return true; + if (cp >= 65576 && cp <= 65594) return true; + if (cp >= 65596 && cp <= 65597) return true; + if (cp >= 65599 && cp <= 65613) return true; + if (cp >= 65616 && cp <= 65629) return true; + if (cp >= 65664 && cp <= 65786) return true; + if (cp >= 65792 && cp <= 65794) return true; + if (cp >= 65799 && cp <= 65843) return true; + if (cp >= 65847 && cp <= 65934) return true; + if (cp >= 65936 && cp <= 65947) return true; + if (cp == 65952) return true; + if (cp >= 66000 && cp <= 66045) return true; + if (cp >= 66176 && cp <= 66204) return true; + if (cp >= 66208 && cp <= 66256) return true; + if (cp >= 66272 && cp <= 66299) return true; + if (cp >= 66304 && cp <= 66339) return true; + if (cp >= 66349 && cp <= 66378) return true; + if (cp >= 66384 && cp <= 66426) return true; + if (cp >= 66432 && cp <= 66461) return true; + if (cp >= 66463 && cp <= 66499) return true; + if (cp >= 66504 && cp <= 66517) return true; + if (cp >= 66560 && cp <= 66717) return true; + if (cp >= 66720 && cp <= 66729) return true; + if (cp >= 66736 && cp <= 66771) return true; + if (cp >= 66776 && cp <= 66811) return true; + if (cp >= 66816 && cp <= 66855) return true; + if (cp >= 66864 && cp <= 66915) return true; + if (cp == 66927) return true; + if (cp >= 67072 && cp <= 67382) return true; + if (cp >= 67392 && cp <= 67413) return true; + if (cp >= 67424 && cp <= 67431) return true; + if (cp >= 67584 && cp <= 67589) return true; + if (cp == 67592) return true; + if (cp >= 67594 && cp <= 67637) return true; + if (cp >= 67639 && cp <= 67640) return true; + if (cp == 67644) return true; + if (cp >= 67647 && cp <= 67669) return true; + if (cp >= 67671 && cp <= 67742) return true; + if (cp >= 67751 && cp <= 67759) return true; + if (cp >= 67808 && cp <= 67826) return true; + if (cp >= 67828 && cp <= 67829) return true; + if (cp >= 67835 && cp <= 67867) return true; + if (cp >= 67871 && cp <= 67897) return true; + if (cp == 67903) return true; + if (cp >= 67968 && cp <= 68023) return true; + if (cp >= 68028 && cp <= 68047) return true; + if (cp >= 68050 && cp <= 68099) return true; + if (cp >= 68101 && cp <= 68102) return true; + if (cp >= 68108 && cp <= 68115) return true; + if (cp >= 68117 && cp <= 68119) return true; + if (cp >= 68121 && cp <= 68147) return true; + if (cp >= 68152 && cp <= 68154) return true; + if (cp >= 68159 && cp <= 68167) return true; + if (cp >= 68176 && cp <= 68184) return true; + if (cp >= 68192 && cp <= 68255) return true; + if (cp >= 68288 && cp <= 68326) return true; + if (cp >= 68331 && cp <= 68342) return true; + if (cp >= 68352 && cp <= 68405) return true; + if (cp >= 68409 && cp <= 68437) return true; + if (cp >= 68440 && cp <= 68466) return true; + if (cp >= 68472 && cp <= 68497) return true; + if (cp >= 68505 && cp <= 68508) return true; + if (cp >= 68521 && cp <= 68527) return true; + if (cp >= 68608 && cp <= 68680) return true; + if (cp >= 68736 && cp <= 68786) return true; + if (cp >= 68800 && cp <= 68850) return true; + if (cp >= 68858 && cp <= 68863) return true; + if (cp >= 69216 && cp <= 69246) return true; + if (cp >= 69632 && cp <= 69709) return true; + if (cp >= 69714 && cp <= 69743) return true; + if (cp >= 69759 && cp <= 69825) return true; + if (cp >= 69840 && cp <= 69864) return true; + if (cp >= 69872 && cp <= 69881) return true; + if (cp >= 69888 && cp <= 69940) return true; + if (cp >= 69942 && cp <= 69955) return true; + if (cp >= 69968 && cp <= 70006) return true; + if (cp >= 70016 && cp <= 70093) return true; + if (cp >= 70096 && cp <= 70111) return true; + if (cp >= 70113 && cp <= 70132) return true; + if (cp >= 70144 && cp <= 70161) return true; + if (cp >= 70163 && cp <= 70206) return true; + if (cp >= 70272 && cp <= 70278) return true; + if (cp == 70280) return true; + if (cp >= 70282 && cp <= 70285) return true; + if (cp >= 70287 && cp <= 70301) return true; + if (cp >= 70303 && cp <= 70313) return true; + if (cp >= 70320 && cp <= 70378) return true; + if (cp >= 70384 && cp <= 70393) return true; + if (cp >= 70400 && cp <= 70403) return true; + if (cp >= 70405 && cp <= 70412) return true; + if (cp >= 70415 && cp <= 70416) return true; + if (cp >= 70419 && cp <= 70440) return true; + if (cp >= 70442 && cp <= 70448) return true; + if (cp >= 70450 && cp <= 70451) return true; + if (cp >= 70453 && cp <= 70457) return true; + if (cp >= 70460 && cp <= 70468) return true; + if (cp >= 70471 && cp <= 70472) return true; + if (cp >= 70475 && cp <= 70477) return true; + if (cp == 70480) return true; + if (cp == 70487) return true; + if (cp >= 70493 && cp <= 70499) return true; + if (cp >= 70502 && cp <= 70508) return true; + if (cp >= 70512 && cp <= 70516) return true; + if (cp >= 70656 && cp <= 70745) return true; + if (cp == 70747) return true; + if (cp == 70749) return true; + if (cp >= 70784 && cp <= 70855) return true; + if (cp >= 70864 && cp <= 70873) return true; + if (cp >= 71040 && cp <= 71093) return true; + if (cp >= 71096 && cp <= 71133) return true; + if (cp >= 71168 && cp <= 71236) return true; + if (cp >= 71248 && cp <= 71257) return true; + if (cp >= 71264 && cp <= 71276) return true; + if (cp >= 71296 && cp <= 71351) return true; + if (cp >= 71360 && cp <= 71369) return true; + if (cp >= 71424 && cp <= 71449) return true; + if (cp >= 71453 && cp <= 71467) return true; + if (cp >= 71472 && cp <= 71487) return true; + if (cp >= 71840 && cp <= 71922) return true; + if (cp == 71935) return true; + if (cp >= 72192 && cp <= 72263) return true; + if (cp >= 72272 && cp <= 72323) return true; + if (cp >= 72326 && cp <= 72348) return true; + if (cp >= 72350 && cp <= 72354) return true; + if (cp >= 72384 && cp <= 72440) return true; + if (cp >= 72704 && cp <= 72712) return true; + if (cp >= 72714 && cp <= 72758) return true; + if (cp >= 72760 && cp <= 72773) return true; + if (cp >= 72784 && cp <= 72812) return true; + if (cp >= 72816 && cp <= 72847) return true; + if (cp >= 72850 && cp <= 72871) return true; + if (cp >= 72873 && cp <= 72886) return true; + if (cp >= 72960 && cp <= 72966) return true; + if (cp >= 72968 && cp <= 72969) return true; + if (cp >= 72971 && cp <= 73014) return true; + if (cp == 73018) return true; + if (cp >= 73020 && cp <= 73021) return true; + if (cp >= 73023 && cp <= 73031) return true; + if (cp >= 73040 && cp <= 73049) return true; + if (cp >= 73728 && cp <= 74649) return true; + if (cp >= 74752 && cp <= 74862) return true; + if (cp >= 74864 && cp <= 74868) return true; + if (cp >= 74880 && cp <= 75075) return true; + if (cp >= 77824 && cp <= 78894) return true; + if (cp >= 82944 && cp <= 83526) return true; + if (cp >= 92160 && cp <= 92728) return true; + if (cp >= 92736 && cp <= 92766) return true; + if (cp >= 92768 && cp <= 92777) return true; + if (cp >= 92782 && cp <= 92783) return true; + if (cp >= 92880 && cp <= 92909) return true; + if (cp >= 92912 && cp <= 92917) return true; + if (cp >= 92928 && cp <= 92997) return true; + if (cp >= 93008 && cp <= 93017) return true; + if (cp >= 93019 && cp <= 93025) return true; + if (cp >= 93027 && cp <= 93047) return true; + if (cp >= 93053 && cp <= 93071) return true; + if (cp >= 93952 && cp <= 94020) return true; + if (cp >= 94032 && cp <= 94078) return true; + if (cp >= 94095 && cp <= 94111) return true; + if (cp >= 94176 && cp <= 94177) return true; + if (cp >= 94208 && cp <= 100332) return true; + if (cp >= 100352 && cp <= 101106) return true; + if (cp >= 110592 && cp <= 110878) return true; + if (cp >= 110960 && cp <= 111355) return true; + if (cp >= 113664 && cp <= 113770) return true; + if (cp >= 113776 && cp <= 113788) return true; + if (cp >= 113792 && cp <= 113800) return true; + if (cp >= 113808 && cp <= 113817) return true; + if (cp >= 113820 && cp <= 113827) return true; + if (cp >= 118784 && cp <= 119029) return true; + if (cp >= 119040 && cp <= 119078) return true; + if (cp >= 119081 && cp <= 119272) return true; + if (cp >= 119296 && cp <= 119365) return true; + if (cp >= 119552 && cp <= 119638) return true; + if (cp >= 119648 && cp <= 119665) return true; + if (cp >= 119808 && cp <= 119892) return true; + if (cp >= 119894 && cp <= 119964) return true; + if (cp >= 119966 && cp <= 119967) return true; + if (cp == 119970) return true; + if (cp >= 119973 && cp <= 119974) return true; + if (cp >= 119977 && cp <= 119980) return true; + if (cp >= 119982 && cp <= 119993) return true; + if (cp == 119995) return true; + if (cp >= 119997 && cp <= 120003) return true; + if (cp >= 120005 && cp <= 120069) return true; + if (cp >= 120071 && cp <= 120074) return true; + if (cp >= 120077 && cp <= 120084) return true; + if (cp >= 120086 && cp <= 120092) return true; + if (cp >= 120094 && cp <= 120121) return true; + if (cp >= 120123 && cp <= 120126) return true; + if (cp >= 120128 && cp <= 120132) return true; + if (cp == 120134) return true; + if (cp >= 120138 && cp <= 120144) return true; + if (cp >= 120146 && cp <= 120485) return true; + if (cp >= 120488 && cp <= 120779) return true; + if (cp >= 120782 && cp <= 121483) return true; + if (cp >= 121499 && cp <= 121503) return true; + if (cp >= 121505 && cp <= 121519) return true; + if (cp >= 122880 && cp <= 122886) return true; + if (cp >= 122888 && cp <= 122904) return true; + if (cp >= 122907 && cp <= 122913) return true; + if (cp >= 122915 && cp <= 122916) return true; + if (cp >= 122918 && cp <= 122922) return true; + if (cp >= 124928 && cp <= 125124) return true; + if (cp >= 125127 && cp <= 125142) return true; + if (cp >= 125184 && cp <= 125258) return true; + if (cp >= 125264 && cp <= 125273) return true; + if (cp >= 125278 && cp <= 125279) return true; + if (cp >= 126464 && cp <= 126467) return true; + if (cp >= 126469 && cp <= 126495) return true; + if (cp >= 126497 && cp <= 126498) return true; + if (cp == 126500) return true; + if (cp == 126503) return true; + if (cp >= 126505 && cp <= 126514) return true; + if (cp >= 126516 && cp <= 126519) return true; + if (cp == 126521) return true; + if (cp == 126523) return true; + if (cp == 126530) return true; + if (cp == 126535) return true; + if (cp == 126537) return true; + if (cp == 126539) return true; + if (cp >= 126541 && cp <= 126543) return true; + if (cp >= 126545 && cp <= 126546) return true; + if (cp == 126548) return true; + if (cp == 126551) return true; + if (cp == 126553) return true; + if (cp == 126555) return true; + if (cp == 126557) return true; + if (cp == 126559) return true; + if (cp >= 126561 && cp <= 126562) return true; + if (cp == 126564) return true; + if (cp >= 126567 && cp <= 126570) return true; + if (cp >= 126572 && cp <= 126578) return true; + if (cp >= 126580 && cp <= 126583) return true; + if (cp >= 126585 && cp <= 126588) return true; + if (cp == 126590) return true; + if (cp >= 126592 && cp <= 126601) return true; + if (cp >= 126603 && cp <= 126619) return true; + if (cp >= 126625 && cp <= 126627) return true; + if (cp >= 126629 && cp <= 126633) return true; + if (cp >= 126635 && cp <= 126651) return true; + if (cp >= 126704 && cp <= 126705) return true; + if (cp >= 126976 && cp <= 127019) return true; + if (cp >= 127024 && cp <= 127123) return true; + if (cp >= 127136 && cp <= 127150) return true; + if (cp >= 127153 && cp <= 127167) return true; + if (cp >= 127169 && cp <= 127183) return true; + if (cp >= 127185 && cp <= 127221) return true; + if (cp >= 127232 && cp <= 127244) return true; + if (cp >= 127248 && cp <= 127278) return true; + if (cp >= 127280 && cp <= 127339) return true; + if (cp >= 127344 && cp <= 127404) return true; + if (cp >= 127462 && cp <= 127490) return true; + if (cp >= 127504 && cp <= 127547) return true; + if (cp >= 127552 && cp <= 127560) return true; + if (cp >= 127568 && cp <= 127569) return true; + if (cp >= 127584 && cp <= 127589) return true; + if (cp >= 127744 && cp <= 128724) return true; + if (cp >= 128736 && cp <= 128748) return true; + if (cp >= 128752 && cp <= 128760) return true; + if (cp >= 128768 && cp <= 128883) return true; + if (cp >= 128896 && cp <= 128980) return true; + if (cp >= 129024 && cp <= 129035) return true; + if (cp >= 129040 && cp <= 129095) return true; + if (cp >= 129104 && cp <= 129113) return true; + if (cp >= 129120 && cp <= 129159) return true; + if (cp >= 129168 && cp <= 129197) return true; + if (cp >= 129280 && cp <= 129291) return true; + if (cp >= 129296 && cp <= 129342) return true; + if (cp >= 129344 && cp <= 129356) return true; + if (cp >= 129360 && cp <= 129387) return true; + if (cp >= 129408 && cp <= 129431) return true; + if (cp == 129472) return true; + if (cp >= 129488 && cp <= 129510) return true; + if (cp >= 131072 && cp <= 173782) return true; + if (cp >= 173824 && cp <= 177972) return true; + if (cp >= 177984 && cp <= 178205) return true; + if (cp >= 178208 && cp <= 183969) return true; + if (cp >= 183984 && cp <= 191456) return true; + if (cp >= 194560 && cp <= 195101) return true; + return false; +} function toLower(c) { var cp = ord(c); @@ -277,7 +2913,7 @@ function cons(v, ls) { function rev(ls) { var acc = null; for (; ls; ls = ls.next) - acc = cons(ls.data, acc); + acc = cons(ls.data, acc); return acc; } function concat(ls1, ls2) { @@ -299,8 +2935,8 @@ function remove(x, ls) { for (; ls; ls = ls.next) if (ls.data == x) return concat(acc, ls.next); - else - acc = cons(ls.data, acc); + else + acc = cons(ls.data, acc); return ls; } @@ -449,11 +3085,11 @@ function stringToTime(string) { } /* -strftime() implementation from: -YUI 3.4.1 (build 4118) -Copyright 2011 Yahoo! Inc. All rights reserved. -Licensed under the BSD License. -http://yuilibrary.com/license/ + strftime() implementation from: + YUI 3.4.1 (build 4118) + Copyright 2011 Yahoo! Inc. All rights reserved. + Licensed under the BSD License. + http://yuilibrary.com/license/ */ var xPad=function (x, pad, r) diff --git a/src/c/urweb.c b/src/c/urweb.c index 1394e068..e458a706 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4473,7 +4473,7 @@ uw_Basis_bool uw_Basis_isupper(uw_context ctx, uw_Basis_char c) { uw_Basis_bool uw_Basis_isxdigit(uw_context ctx, uw_Basis_char c) { (void)ctx; - return !!u_hasBinaryProperty(c, UCHAR_POSIX_XDIGIT); + return !!(c <= 0x7f && u_isxdigit(c)); } uw_Basis_char uw_Basis_tolower(uw_context ctx, uw_Basis_char c) { -- cgit v1.2.3 From 1ce628ae2ab01799b6f601f0677ea396d1ac1577 Mon Sep 17 00:00:00 2001 From: fab Date: Tue, 11 Dec 2018 20:44:50 +0000 Subject: migrate is_valid_hash, blessData, property, atom --- lib/js/urweb.js | 39 ++++++++++++++++++++++++--------------- src/c/urweb.c | 20 ++++++++++---------- 2 files changed, 34 insertions(+), 25 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index fe47959f..00637172 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -5109,11 +5109,14 @@ function bless(s) { // Attribute name blessing +var maxCh = chr(127); function blessData(s) { - for (var i = 0; i < s.length; ++i) { - var c = s[i]; - if (!isAlnum(c) && c != '-' && c != '_') + var chars = Array.from(s); + + for (var i = 0; i < chars.length; ++i) { + var c = chars[i]; + if (c > maxCh || (!isAlnum(c) && c != '-' && c != '_')) er("Disallowed character in data-* attribute name"); } @@ -5124,9 +5127,11 @@ function blessData(s) { // CSS validation function atom(s) { - for (var i = 0; i < s.length; ++i) { - var c = s[i]; - if (!isAlnum(c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#') + var chars = Array.from(s); + + for (var i = 0; i < chars.length; ++i) { + var c = chars[i]; + if (c > maxCh || (!isAlnum(c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#')) er("Disallowed character in CSS atom"); } @@ -5134,10 +5139,12 @@ function atom(s) { } function css_url(s) { - for (var i = 0; i < s.length; ++i) { - var c = s[i]; - if (!isAlnum(c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' - && c != '-' && c != '%' && c != '?' && c != '&' && c != '=' && c != '#') + var chars = Array.from(s); + + for (var i = 0; i < chars.length; ++i) { + var c = chars[i]; + if (c > maxCh || (!isAlnum(c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' + && c != '-' && c != '%' && c != '?' && c != '&' && c != '=' && c != '#')) er("Disallowed character in CSS URL"); } @@ -5145,15 +5152,17 @@ function css_url(s) { } function property(s) { - if (s.length <= 0) + var chars = Array.from(s); + + if (chars.length <= 0) er("Empty CSS property"); - if (!isLower(s[0]) && s[0] != '_') + if (chars[0] > maxCh || (!isLower(chars[0]) && chars[0] != '_')) er("Bad initial character in CSS property"); - for (var i = 0; i < s.length; ++i) { - var c = s[i]; - if (!isLower(c) && !isDigit(c) && c != '_' && c != '-') + for (var i = 0; i < chars.length; ++i) { + var c = chars[i]; + if (c > maxCh || (!isLower(c) && !isDigit(c) && c != '_' && c != '-')) er("Disallowed character in CSS property"); } diff --git a/src/c/urweb.c b/src/c/urweb.c index e458a706..96e30cec 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1975,7 +1975,7 @@ char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) { if (c == ' ') *p++ = '+'; - else if (isalnum(c)) + else if (U8_IS_SINGLE(c) && isalnum(c)) *p++ = c; else { sprintf(p, ".%02X", c); @@ -2067,7 +2067,7 @@ uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) { if (c == ' ') uw_writec_unsafe(ctx, '+'); - else if (isalnum(c)) + else if (U8_IS_SINGLE(c) && isalnum(c)) uw_writec_unsafe(ctx, c); else { sprintf(ctx->page.front, ".%02X", c); @@ -4758,7 +4758,7 @@ uw_Basis_string uw_Basis_atom(uw_context ctx, uw_Basis_string s) { for (p = s; *p; ++p) { char c = *p; - if (!U8_IS_SINGLE(c) && !isalnum((int)c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#') + if (!U8_IS_SINGLE(c) || (!isalnum((int)c) && c != '+' && c != '-' && c != '.' && c != '%' && c != '#')) uw_error(ctx, FATAL, "Disallowed character in CSS atom"); } @@ -4770,8 +4770,8 @@ uw_Basis_string uw_Basis_css_url(uw_context ctx, uw_Basis_string s) { for (p = s; *p; ++p) { char c = *p; - if (!U8_IS_SINGLE(c) && !isalnum((int)c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' - && c != '-' && c != '%' && c != '?' && c != '&' && c != '=' && c != '#') + if (!U8_IS_SINGLE(c) || (!isalnum((int)c) && c != ':' && c != '/' && c != '.' && c != '_' && c != '+' + && c != '-' && c != '%' && c != '?' && c != '&' && c != '=' && c != '#')) uw_error(ctx, FATAL, "Disallowed character in CSS URL"); } @@ -4784,12 +4784,12 @@ uw_Basis_string uw_Basis_property(uw_context ctx, uw_Basis_string s) { if (!*s) uw_error(ctx, FATAL, "Empty CSS property"); - if (!islower((int)s[0]) && s[0] != '_') + if (!U8_IS_SINGLE(s[0]) || (!islower((int)s[0]) && s[0] != '_')) uw_error(ctx, FATAL, "Bad initial character in CSS property"); for (p = s; *p; ++p) { char c = *p; - if (!U8_IS_SINGLE(c) && !islower((int)c) && !isdigit((int)c) && c != '_' && c != '-') + if (!U8_IS_SINGLE(c) || (!islower((int)c) && !isdigit((int)c) && c != '_' && c != '-')) uw_error(ctx, FATAL, "Disallowed character in CSS property"); } @@ -4840,9 +4840,9 @@ uw_Basis_postField *uw_Basis_firstFormField(uw_context ctx, uw_Basis_string s) { uw_Basis_string uw_Basis_blessData(uw_context ctx, uw_Basis_string s) { char *p = s; - + for (; *p; ++p) - if (!isalnum(*p) && *p != '-' && *p != '_') + if (!U8_IS_SINGLE(*p) || (!isalnum(*p) && *p != '-' && *p != '_')) uw_error(ctx, FATAL, "Illegal HTML5 data-* attribute: %s", s); return s; @@ -5174,7 +5174,7 @@ int strcmp_nullsafe(const char *str1, const char *str2) { static int is_valid_hash(uw_Basis_string hash) { for (; *hash; ++hash) - if (!U8_IS_SINGLE(*hash) && !isxdigit(*hash)) + if (!U8_IS_SINGLE(*hash) || !isxdigit(*hash)) return 0; return 1; -- cgit v1.2.3 From e452bb052b6c1afbaaa72efb653ea31561333866 Mon Sep 17 00:00:00 2001 From: fab Date: Tue, 11 Dec 2018 22:16:37 +0000 Subject: exhaustive testing brought to selenium. bug fix in isspace. useful function to test if char is <128 --- lib/js/urweb.js | 5 +- lib/ur/basis.urs | 1 + src/c/urweb.c | 5 ++ tests/utf8.py | 79 +++++++++++++++++--- tests/utf8.ur | 217 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 292 insertions(+), 15 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index 00637172..2d39bc69 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -2122,9 +2122,7 @@ function isBlank(c) { } function isSpace(c) { var cp = ord(c); - if (cp == 10) - return true; - if (cp == 13) + if (cp >= 10 && cp <= 13) return true; if (cp == 133) return true; @@ -2790,6 +2788,7 @@ function isPrint(c) { function toLower(c) { var cp = ord(c); + if (cp == 304) return chr(105); else if (cp >= 7312 && cp <= 7354) diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index c9d6556b..c893e65d 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -80,6 +80,7 @@ val ord : char -> int val chr : int -> char val iscodepoint : int -> bool +val issingle : char -> bool (** String operations *) diff --git a/src/c/urweb.c b/src/c/urweb.c index 96e30cec..78946872 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4496,6 +4496,11 @@ uw_Basis_bool uw_Basis_iscodepoint (uw_context ctx, uw_Basis_int n) { return !!(n <= 0x10FFFF); } +uw_Basis_bool uw_Basis_issingle (uw_context ctx, uw_Basis_char c) { + (void)ctx; + return !!(c < 128); +} + uw_Basis_char uw_Basis_chr(uw_context ctx, uw_Basis_int n) { (void)ctx; uw_Basis_char ch = (uw_Basis_char)n; diff --git a/tests/utf8.py b/tests/utf8.py index 440bc82a..ac8df5c3 100644 --- a/tests/utf8.py +++ b/tests/utf8.py @@ -2,51 +2,51 @@ import unittest import base class Suite(base.Base): - def test_1(self): + def test_99(self): """Test case: substring (1)""" self.start('Utf8/substrings') - def test_2(self): + def test_98(self): """Test case: strlen (2)""" self.start('Utf8/strlens') - def test_3(self): + def test_97(self): """Test case: strlenGe (3)""" self.start('Utf8/strlenGens') - def test_4(self): + def test_96(self): """Test case: strcat (4)""" self.start('Utf8/strcats') - def test_5(self): + def test_95(self): """Test case: strsub (5)""" self.start('Utf8/strsubs') - def test_6(self): + def test_94(self): """Test case: strsuffix (6)""" self.start('Utf8/strsuffixs') - def test_7(self): + def test_93(self): """Test case: strchr (7)""" self.start('Utf8/strchrs') - def test_8(self): + def test_92(self): """Test case: strindex (8)""" self.start('Utf8/strindexs') - def test_9(self): + def test_91(self): """Test case: strindex (9)""" self.start('Utf8/strsindexs') - def test_10(self): + def test_90(self): """Test case: strcspn (10)""" self.start('Utf8/strcspns') - def test_11(self): + def test_89(self): """Test case: str1 (11)""" self.start('Utf8/str1s') - def test_12(self): + def test_88(self): """Test case: isalnum (12)""" self.start('Utf8/isalnums') @@ -105,3 +105,58 @@ class Suite(base.Base): def test_26 (self): """Test case: test_db (26) """ self.start('Utf8/test_db') + + def full_test (self, name): + + gap = 1000 + i = 0 + while (i + gap < 130000): + self.start('Utf8/' + name + '/' + str(i) + '/' + str(i + gap)) + errors = self.body_text() + self.assertEqual("", errors, errors) + i = i + gap + + + def test_1 (self): + """Test case: ftTolower """ + self.full_test("ftTolower") + + def test_2 (self): + """Test case: ftToupper """ + self.full_test("ftToupper") + + def test_3 (self): + """Test case: ftIsalpha """ + self.full_test("ftIsalpha") + + def test_4 (self): + """Test case: ftIsdigit """ + self.full_test("ftIsdigit") + + def test_5 (self): + """Test case: ftIsalnum """ + self.full_test("ftIsalnum") + + def test_6 (self): + """Test case: ftIsspace """ + self.full_test("ftIsspace") + + def test_7 (self): + """Test case: ftIsblank """ + self.full_test("ftIsblank") + + def test_8 (self): + """Test case: ftIsprint """ + self.full_test("ftIsprint") + + def test_9 (self): + """Test case: ftIsxdigit """ + self.full_test("ftIsxdigit") + + def test_10 (self): + """Test case: ftIsupper """ + self.full_test("ftIsupper") + + def test_11 (self): + """Test case: ftIslower """ + self.full_test("ftIslower") diff --git a/tests/utf8.ur b/tests/utf8.ur index c7aefd79..777bb141 100644 --- a/tests/utf8.ur +++ b/tests/utf8.ur @@ -1,4 +1,13 @@ +fun from_m_upto_n f m n = + if m < n then + + { f m } + { from_m_upto_n f (m + 1) n } + + else + + fun test_fn_both_sides [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody =

Server side test: {[testname]}

@@ -31,6 +40,38 @@ fun test_fn_cside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected
+ +fun test_fn_cside_ch (f : unit -> char) (expected : char) (testname : string) : xbody = + + + else + return

ERROR {[testname]}: {[msgErr]}

+ end}> + + + +fun test_fn_cside_b (f : unit -> bool) (expected : bool) (testname : string) : xbody = + + + else + return

ERROR {[testname]}: {[msgErr]}

+ end}> + + + + fun highencode () : transaction page = return @@ -553,6 +594,182 @@ fun test_db () : transaction page = end +and ftTolower (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_ch (fn _ => tolower (chr n)) (tolower (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftToupper (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_ch (fn _ => toupper (chr n)) (toupper (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsalpha (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isalpha (chr n)) (isalpha (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsdigit (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isdigit (chr n)) (isdigit (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsalnum (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isalnum (chr n)) (isalnum (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsspace (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isspace (chr n)) (isspace (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsblank (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isblank (chr n)) (isblank (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsprint (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isprint (chr n)) (isprint (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsxdigit (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isxdigit (chr n)) (isxdigit (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIsupper (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => isupper (chr n)) (isupper (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + +and ftIslower (minCh : int) (maxCh : int) : transaction page = + let + fun test_chr (n : int) : xbody = + if iscodepoint n then + test_fn_cside_b (fn _ => islower (chr n)) (islower (chr n)) + ("test chr " ^ (show n) ^ " : " ^ (show (chr n))) + else + + in + return + + { from_m_upto_n (fn n => test_chr n) minCh maxCh } + + + end + fun index () : transaction page = return -- cgit v1.2.3 From 91c0e37b0ddc8495e31bd653b8bc363fd14f4375 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Wed, 19 Dec 2018 11:42:33 -0500 Subject: Follow-up to #146: make style consistent in C code --- src/c/urweb.c | 48 ++++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 26 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 6f36e3ed..ae2fc0a8 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1561,7 +1561,7 @@ const char *uw_Basis_get_settings(uw_context ctx, uw_unit u) { uw_Basis_bool uw_Basis_isprint(uw_context ctx, uw_Basis_char ch); -void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { +static void jsifyChar(char **buffer_ptr, uw_context ctx, uw_Basis_char c1) { char* buffer = *buffer_ptr; switch (c1) { @@ -1586,14 +1586,11 @@ void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { buffer += 4; break; default: - - if (uw_Basis_isprint(ctx, c1) == uw_Basis_True) - { - int offset = 0; - U8_APPEND_UNSAFE(buffer, offset, c1); - buffer += offset; - } - else { + if (uw_Basis_isprint(ctx, c1)) { + int offset = 0; + U8_APPEND_UNSAFE(buffer, offset, c1); + buffer += offset; + } else { if(65536 > c1) { sprintf(buffer, "\\u%04x", c1); buffer += 6; @@ -1604,7 +1601,6 @@ void jsifyChar(char**buffer_ptr, uw_context ctx, uw_Basis_char c1) { } } - *buffer_ptr = buffer; } @@ -1990,7 +1986,7 @@ char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) { char *uw_Basis_urlifyBool(uw_context ctx, uw_Basis_bool b) { (void)ctx; - if (b == uw_Basis_False) + if (!b) return "0"; else return "1"; @@ -2079,7 +2075,7 @@ uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) { } uw_unit uw_Basis_urlifyBool_w(uw_context ctx, uw_Basis_bool b) { - if (b == uw_Basis_False) + if (!b) uw_writec(ctx, '0'); else uw_writec(ctx, '1'); @@ -2355,7 +2351,7 @@ char *uw_Basis_htmlifyString(uw_context ctx, const char *s) { s2 += len; } } - + *s2++ = 0; ctx->heap.front = s2; return r; @@ -2393,14 +2389,14 @@ uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) { uw_Basis_string uw_Basis_htmlifyBool(uw_context ctx, uw_Basis_bool b) { (void)ctx; - if (b == uw_Basis_False) + if (!b) return "False"; else return "True"; } uw_unit uw_Basis_htmlifyBool_w(uw_context ctx, uw_Basis_bool b) { - if (b == uw_Basis_False) { + if (!b) { uw_check(ctx, 6); strcpy(ctx->page.front, "False"); ctx->page.front += 5; @@ -2448,7 +2444,7 @@ uw_unit uw_Basis_htmlifySource_w(uw_context ctx, uw_Basis_source src) { return uw_unit_v; } -uw_Basis_char uw_Basis_strsub(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { +uw_Basis_char uw_Basis_strsub(uw_context ctx, uw_Basis_string s, uw_Basis_int n) { uw_Basis_char c; int offset = 0; @@ -2505,7 +2501,7 @@ uw_Basis_bool uw_Basis_strlenGe(uw_context ctx, uw_Basis_string s, uw_Basis_int return uw_Basis_True; } -int aux_strchr(uw_Basis_string s, uw_Basis_char ch, int* o_offset) { +static int aux_strchr(uw_Basis_string s, uw_Basis_char ch, int *o_offset) { int u8idx = 0, offset = 0, offsetpr = 0; uw_Basis_char c; @@ -2909,7 +2905,7 @@ uw_Basis_string uw_Basis_sqlifyStringN(uw_context ctx, uw_Basis_string s) { char *uw_Basis_sqlifyBool(uw_context ctx, uw_Basis_bool b) { (void)ctx; - if (b == uw_Basis_False) + if (!b) return "FALSE"; else return "TRUE"; @@ -2993,7 +2989,7 @@ char *uw_Basis_ensqlBool(uw_Basis_bool b) { static uw_Basis_int true = 1; static uw_Basis_int false = 0; - if (b == uw_Basis_False) + if (!b) return (char *)&false; else return (char *)&true; @@ -3027,7 +3023,7 @@ uw_Basis_string uw_Basis_charToString(uw_context ctx, uw_Basis_char ch) { uw_Basis_string uw_Basis_boolToString(uw_context ctx, uw_Basis_bool b) { (void)ctx; - if (b == uw_Basis_False) + if (!b) return "False"; else return "True"; @@ -3082,7 +3078,7 @@ uw_Basis_char *uw_Basis_stringToChar(uw_context ctx, uw_Basis_string s) { uw_Basis_char *r = uw_malloc(ctx, 1); r[0] = 0; return r; - } else if (uw_Basis_strlenGe(ctx, s, 2) == uw_Basis_True) + } else if (uw_Basis_strlenGe(ctx, s, 2)) return NULL; else { uw_Basis_char *r = uw_malloc(ctx, 1); @@ -3212,7 +3208,7 @@ uw_Basis_float uw_Basis_stringToFloat_error(uw_context ctx, uw_Basis_string s) { uw_Basis_char uw_Basis_stringToChar_error(uw_context ctx, uw_Basis_string s) { if (s[0] == 0) return 0; - else if (uw_Basis_strlenGe(ctx, s, 2) == uw_Basis_True) + else if (uw_Basis_strlenGe(ctx, s, 2)) uw_error(ctx, FATAL, "Can't parse char: %s", uw_Basis_htmlifyString(ctx, s)); else { uw_Basis_char c; @@ -4491,12 +4487,12 @@ uw_Basis_int uw_Basis_ord(uw_context ctx, uw_Basis_char c) { return (uw_Basis_int)c; } -uw_Basis_bool uw_Basis_iscodepoint (uw_context ctx, uw_Basis_int n) { +uw_Basis_bool uw_Basis_iscodepoint(uw_context ctx, uw_Basis_int n) { (void)ctx; return !!(n <= 0x10FFFF); } -uw_Basis_bool uw_Basis_issingle (uw_context ctx, uw_Basis_char c) { +uw_Basis_bool uw_Basis_issingle(uw_context ctx, uw_Basis_char c) { (void)ctx; return !!(c < 128); } @@ -4845,7 +4841,7 @@ uw_Basis_postField *uw_Basis_firstFormField(uw_context ctx, uw_Basis_string s) { uw_Basis_string uw_Basis_blessData(uw_context ctx, uw_Basis_string s) { char *p = s; - + for (; *p; ++p) if (!U8_IS_SINGLE(*p) || (!isalnum(*p) && *p != '-' && *p != '_')) uw_error(ctx, FATAL, "Illegal HTML5 data-* attribute: %s", s); @@ -5170,7 +5166,7 @@ void uw_Sqlcache_flush(uw_context ctx, uw_Sqlcache_Cache *cache, char **keys) { pthread_rwlock_unlock(&cache->lockIn); } -int strcmp_nullsafe(const char *str1, const char *str2) { +int strcmp_nullsafe(const char *str1, const char *str2) { if (str1) return strcmp(str1, str2); else -- cgit v1.2.3 From b4d31722f1ee192d91717e40a3c1bed281ed9392 Mon Sep 17 00:00:00 2001 From: fab Date: Wed, 9 Jan 2019 22:21:14 +0000 Subject: fix unit tests. implement urlifyChar --- lib/js/urweb.js | 4 +- src/c/urweb.c | 95 +++- src/mono_opt.sml | 67 ++- tests/utf8.ur | 1638 ++++++++++++++++++++++++++++++++++++++++++------------ tests/utf8.urp | 1 + 5 files changed, 1412 insertions(+), 393 deletions(-) (limited to 'src/c/urweb.c') diff --git a/lib/js/urweb.js b/lib/js/urweb.js index 2a621a2d..6b493c4f 100644 --- a/lib/js/urweb.js +++ b/lib/js/urweb.js @@ -2498,9 +2498,9 @@ function sub(s, i) { return ch; } function suf(s, i) { - var offset = s.length; + var off = s.length; iterateString(s, function(_, idx, sidx) { if (idx == i) { off = sidx; return false; } }); - return s.substring(offset); + return s.substring(off); } function slen(s) { var len = 0; diff --git a/src/c/urweb.c b/src/c/urweb.c index ae2fc0a8..e98b5772 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -1954,29 +1954,61 @@ char *uw_Basis_urlifyFloat(uw_context ctx, uw_Basis_float n) { return r; } +static void aux_urlifyChar(char** ptr, uw_Basis_char c) { + char* p = *ptr; + + if((uint32_t)(c) <= 0x7f) { + sprintf(p, ".%02X", (uint8_t)(c)); + p += 3; + } else { + if((uint32_t)(c) <= 0x7ff) { + sprintf(p, ".%02X", (uint8_t)(((c)>>6)|0xc0)); + p += 3; + } else { + if((uint32_t)(c) <= 0xffff) { + sprintf(p, ".%02X", (uint8_t)(((c)>>12)|0xe0)); + p += 3; + } else { + sprintf(p, ".%02X", (uint8_t)(((c)>>18)|0xf0)); + p += 3; + sprintf(p, ".%02X", (uint8_t)((((c)>>12)&0x3f)|0x80)); + p += 3; + } + sprintf(p, ".%02X", (uint8_t)((((c)>>6)&0x3f)|0x80)); + p += 3; + } + sprintf(p, ".%02X", (uint8_t)(((c)&0x3f)|0x80)); + p += 3; + } + + *ptr = p; +} + char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) { char *r, *p; if (s[0] == '\0') return "_"; - uw_check_heap(ctx, strlen(s) * 3 + 1 + !!(s[0] == '_')); + uw_check_heap(ctx, strlen(s) * 12 + 1 + !!(s[0] == '_')); r = p = ctx->heap.front; if (s[0] == '_') *p++ = '_'; - for (; *s; s++) { - unsigned char c = *s; - - if (c == ' ') + uw_Basis_char c; + int offset = 0, curr = 0; + while (s[offset] != 0) { + U8_NEXT(s, offset, -1, c); + + if (U8_IS_SINGLE(s[curr]) && s[curr] == ' ') *p++ = '+'; - else if (U8_IS_SINGLE(c) && isalnum(c)) - *p++ = c; + else if (U8_IS_SINGLE(s[curr]) && isalnum(s[curr])) + *p++ = s[offset]; else { - sprintf(p, ".%02X", c); - p += 3; + aux_urlifyChar(&p, c); } + curr = offset; } *p++ = 0; @@ -2046,6 +2078,29 @@ uw_unit uw_Basis_urlifyTime_w(uw_context ctx, uw_Basis_time t) { return uw_Basis_urlifyInt_w(ctx, (uw_Basis_int)t.seconds * 1000000 + t.microseconds); } +uw_unit uw_Basis_urlifyChar_w(uw_context ctx, uw_Basis_char c) { + if (c == '\0') { + uw_check(ctx, 1); + uw_writec_unsafe(ctx, '_'); + return uw_unit_v; + } + + uw_check(ctx, 12 + !!(c == '_')); + + if (c == '_') + uw_writec_unsafe(ctx, '_'); + + if (c == ' ') + uw_writec_unsafe(ctx, '+'); + else if (isalnum(c) && c <= 0x7f) + uw_writec_unsafe(ctx, c); + else { + aux_urlifyChar(&(ctx->page.front), c); + } + + return uw_unit_v; +} + uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) { if (s[0] == '\0') { uw_check(ctx, 1); @@ -2053,22 +2108,24 @@ uw_unit uw_Basis_urlifyString_w(uw_context ctx, uw_Basis_string s) { return uw_unit_v; } - uw_check(ctx, strlen(s) * 3 + !!(s[0] == '_')); + uw_check(ctx, strlen(s) * 12 + !!(s[0] == '_')); if (s[0] == '_') uw_writec_unsafe(ctx, '_'); - for (; *s; s++) { - unsigned char c = *s; - - if (c == ' ') + uw_Basis_char c; + int offset = 0, curr = 0; + while (s[offset] != 0) { + U8_NEXT(s, offset, -1, c); + + if (U8_IS_SINGLE(s[curr]) && s[curr] == ' ') uw_writec_unsafe(ctx, '+'); - else if (U8_IS_SINGLE(c) && isalnum(c)) - uw_writec_unsafe(ctx, c); - else { - sprintf(ctx->page.front, ".%02X", c); - ctx->page.front += 3; + else if (U8_IS_SINGLE(s[curr]) && isalnum(s[curr])) + uw_writec_unsafe(ctx, s[curr]); + else { + aux_urlifyChar(&(ctx->page.front), c); } + curr = offset; } return uw_unit_v; diff --git a/src/mono_opt.sml b/src/mono_opt.sml index 40b865b0..218be1ba 100644 --- a/src/mono_opt.sml +++ b/src/mono_opt.sml @@ -66,16 +66,64 @@ val htmlifyString = String.translate (fn #"<" => "<" fun htmlifySpecialChar ch = "&#" ^ Int.toString (ord ch) ^ ";" -fun hexIt ch = +fun hexPad c = let - val s = Int.fmt StringCvt.HEX (ord ch) + val s = Int.fmt StringCvt.HEX c in - case size s of + case size s of 0 => "00" | 1 => "0" ^ s | _ => s end +fun rsh a b = + Int.fromLarge (IntInf.~>>(IntInf.fromInt a, Word.fromInt b)) + +fun orb a b = + Int.fromLarge (IntInf.orb(IntInf.fromInt a, IntInf.fromInt b)) + +fun andb a b = + Int.fromLarge (IntInf.andb(IntInf.fromInt a, IntInf.fromInt b)) + + +fun hexIt ch = + let + val c = ord ch + in + if (c <= 0x7f) then + hexPad c + else + ((if (c <= 0x7fff) then + hexPad (orb (rsh c 6) 0xc0) + else + (if (c <= 0xffff) then + hexPad (orb (rsh c 12) 0xe0) + else + hexPad (orb (rsh c 18) 0xf0) + ^ hexPad (orb (andb (rsh c 12) 0x3f) 0x80) + ) + ^ hexPad (orb (andb (rsh c 6) 0x3f) 0x80)) + ) ^ hexPad (orb (andb c 0x3f) 0x80) + end + +fun urlifyCharAux ch = + case ch of + #" " => "+" + | _ => + if ord ch = 0 then + "_" + else + if Char.isAlphaNum ch then + str ch + else + "." ^ hexIt ch + +fun urlifyChar c = + case c of + #"_" => "_" ^ urlifyCharAux c + | _ => urlifyCharAux c + + fun urlifyString s = case s of "" => "_" @@ -84,11 +132,7 @@ fun urlifyString s = "_" else "") - ^ String.translate (fn #" " => "+" - | ch => if Char.isAlphaNum ch then - str ch - else - "." ^ hexIt ch) s + ^ String.translate urlifyCharAux s fun sqlifyInt n = #p_cast (Settings.currentDbms ()) (attrifyInt n, Settings.Int) @@ -349,6 +393,13 @@ fun exp e = | EWrite (EFfiApp ("Basis", "urlifyString", [e]), _) => EFfiApp ("Basis", "urlifyString_w", [e]) + | EFfiApp ("Basis", "urlifyChar", [((EPrim (Prim.Char c), _), _)]) => + EPrim (Prim.String (Prim.Normal, urlifyChar c)) + | EWrite (EFfiApp ("Basis", "urlifyChar", [((EPrim (Prim.Char c), _), _)]), loc) => + EWrite (EPrim (Prim.String (Prim.Normal, urlifyChar c)), loc) + | EWrite (EFfiApp ("Basis", "urlifyChar", [e]), _) => + EFfiApp ("Basis", "urlifyChar_w", [e]) + | EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "True", ...}, NONE), _), _)]) => EPrim (Prim.String (Prim.Normal, "1")) | EFfiApp ("Basis", "urlifyBool", [((ECon (Enum, PConFfi {con = "False", ...}, NONE), _), _)]) => diff --git a/tests/utf8.ur b/tests/utf8.ur index 4a89c22b..2150fde6 100644 --- a/tests/utf8.ur +++ b/tests/utf8.ur @@ -8,11 +8,46 @@ fun from_m_upto_n f m n = else +fun from_m_upto_n2 (f : int -> transaction xbody) (m : int) (n : int) : transaction xbody = + if m < n then + h <- f m; + t <- from_m_upto_n2 f (m + 1) n; + return + { h } + { t } + + else + return + fun test_fn_both_sides [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody =

Server side test: {[testname]}

{[show (f () = expected)]}

Client side test: {[testname]}

{[show (f () = expected)]}
}> + +
+ +fun test_fn_both_sides2 [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (serverexp : a) (expected : a) (testname : string) : xbody = + +

Test: {[testname]}

+ +

Server side test: {[testname]}

+
{[show stest]}
+ {if stest then + + else + +

S: {[serverexp]}

+

E: {[expected]}

+
} +
+ end}> + +

Client side test: {[testname]}

{[show (f () = expected)]}
}>
@@ -22,12 +57,34 @@ fun test_fn_sside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected
{[show (f () = expected)]}
-fun test_fn_cside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody = - -

Client side test: {[testname]}

{[show (f () = expected)]}
}> - - + fun test_fn_cside [a ::: Type] (_ : eq a) (_ : show a) (f : unit -> a) (expected : a) (testname : string) : xbody = + let + val r = f () + val v = r = expected + in + +

Client side test: {[testname]}

{[show v]}
+ {if v then + + else + Expected '{[show expected]}', is '{[show r]}'} +
}> + + + end +fun test_fn_cside_int (f : unit -> int) (expected : int) (testname : string) : xbody = + +

{[testname]}

True
+ else + return

{[testname]}

False
+ end}> + + fun test_fn_cside_ch (f : unit -> char) (expected : char) (testname : string) : xbody = @@ -57,123 +114,297 @@ fun test_fn_cside_b (f : unit -> bool) (expected : bool) (testname : string) : x return

ERROR {[testname]}: {[msgErr]}

end}> -
+ +fun generateTests _ = + return { SL1 = (strlen "𝌆𝌇𝌈𝌉"), + SL2 = (strlen "𝌇𝌈𝌉"), + SL3 = (strlen "𝌈𝌉"), + SL4 = (strlen "𝌉"), + SS1 = (substring "𝌆𝌇𝌈𝌉" 1 3), + SS2 = (substring "𝌆𝌇𝌈𝌉" 2 2), + SS3 = (substring "𝌆𝌇𝌈𝌉" 3 1) , + SLSS1 = (strlen (substring "𝌆𝌇𝌈𝌉" 1 3)), + SLSS2 = (strlen (substring "𝌆𝌇𝌈𝌉" 2 2)), + SLSS3 = (strlen (substring "𝌆𝌇𝌈𝌉" 3 1)), + + SSB1 = (strsub "𝌆𝌇𝌈𝌉" 0), + SSB2 = (strsub "𝌆𝌇𝌈𝌉" 1), + SSB3 = (strsub "𝌆𝌇𝌈𝌉" 2), + SSB4 = (strsub "𝌆𝌇𝌈𝌉" 3), + + SSF1 = (strsuffix "𝌆𝌇𝌈𝌉" 0), + SSF2 = (strsuffix "𝌆𝌇𝌈𝌉" 1), + SSF3 = (strsuffix "𝌆𝌇𝌈𝌉" 2), + SSF4 = (strsuffix "𝌆𝌇𝌈𝌉" 3), + + SC1 = (strchr "𝌆𝌇𝌈𝌉" #"c"), + SC2 = (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)), + SC3 = (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)), + SC4 = (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)), + SC5 = (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)), + + SI1 = (strindex "𝌆𝌇𝌈𝌉" #"c"), + SI2 = (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)), + SI3 = (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)), + SI4 = (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)), + SI5 = (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)), + + SSI1 = (strsindex "𝌆𝌇𝌈𝌉" ""), + SSI2 = (strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉"), + SSI3 = (strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈c"), + SSI4 = (strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉"), + SSI5 = (strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈c"), + SSI6 = (strsindex "𝌆𝌇𝌈𝌉" "𝌈𝌉"), + SSI7 = (strsindex "𝌆𝌇𝌈𝌉" "𝌈c"), + SSI8 = (strsindex "𝌆𝌇𝌈𝌉" "𝌉"), + SSI9 = (strsindex "𝌆𝌇𝌈𝌉" "c"), + + SCSP1 = (strcspn "𝌆𝌇𝌈𝌉" ""), + SCSP2 = (strcspn "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉"), + SCSP3 = (strcspn "𝌆𝌇𝌈𝌉" "𝌆"), + SCSP4 = (strcspn "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉"), + SCSP5 = (strcspn "𝌆𝌇𝌈𝌉" "𝌈𝌉"), + SCSP6 = (strcspn "𝌆𝌇𝌈𝌉" "𝌉"), + + OSS1 = (ord (strsub "𝌆𝌇𝌈𝌉" 0)), + OSS2 = (ord (strsub "𝌆𝌇𝌈𝌉" 1)), + OSS3 = (ord (strsub "𝌆𝌇𝌈𝌉" 2)), + OSS4 = (ord (strsub "𝌆𝌇𝌈𝌉" 3)), + + SSS1 = (show (strsub "𝌆𝌇𝌈𝌉" 0)), + SSS2 = (show (strsub "𝌆𝌇𝌈𝌉" 1)), + SSS3 = (show (strsub "𝌆𝌇𝌈𝌉" 2)), + SSS4 = (show (strsub "𝌆𝌇𝌈𝌉" 3)) + } fun highencode () : transaction page = + t <- source None; return - - {test_fn_cside (fn _ => strlen "𝌆𝌇𝌈𝌉") (strlen "𝌆𝌇𝌈𝌉") "high encode - strlen 1"} - {test_fn_cside (fn _ => strlen "𝌇𝌈𝌉") (strlen "𝌇𝌈𝌉") "high encode - strlen 2"} - {test_fn_cside (fn _ => strlen "𝌈𝌉") (strlen "𝌈𝌉") "high encode - strlen 3"} - {test_fn_cside (fn _ => strlen "𝌉") (strlen "𝌉") "high encode - strlen 4"} - - {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 1 3) (substring "𝌆𝌇𝌈𝌉" 1 3) "high encode - substring 1"} - {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 2 2) (substring "𝌆𝌇𝌈𝌉" 2 2) "high encode - substring 2"} - {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 3 1) (substring "𝌆𝌇𝌈𝌉" 3 1) "high encode - substring 3"} - - {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 1 3)) (strlen (substring "𝌆𝌇𝌈𝌉" 1 3)) "high encode - strlen of substring 1"} - {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 2 2)) (strlen (substring "𝌆𝌇𝌈𝌉" 2 2)) "high encode - strlen of substring 2"} - {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 3 1)) (strlen (substring "𝌆𝌇𝌈𝌉" 3 1)) "high encode - strlen of substring 3"} - - {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 0) (strsub "𝌆𝌇𝌈𝌉" 0) "high encode - strsub 1"} - {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 1) (strsub "𝌆𝌇𝌈𝌉" 1) "high encode - strsub 2"} - {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 2) (strsub "𝌆𝌇𝌈𝌉" 2) "high encode - strsub 3"} - {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 3) (strsub "𝌆𝌇𝌈𝌉" 3) "high encode - strsub 4"} - - {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 0) (strsuffix "𝌆𝌇𝌈𝌉" 0) "high encode - strsuffix 1"} - {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 1) (strsuffix "𝌆𝌇𝌈𝌉" 1) "high encode - strsuffix 2"} - {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 2) (strsuffix "𝌆𝌇𝌈𝌉" 2) "high encode - strsuffix 3"} - {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 3) (strsuffix "𝌆𝌇𝌈𝌉" 3) "high encode - strsuffix 4"} - - {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" #"c") (strchr "𝌆𝌇𝌈𝌉" #"c") "high encode - strchr 1"} - {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) "high encode - strchr 2"} - {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) "high encode - strchr 3"} - {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) "high encode - strchr 4"} - {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) (strchr "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) "high encode - strchr 5"} - - {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" #"c") (strindex "𝌆𝌇𝌈𝌉" #"c") "high encode - strindex 1"} - {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) "high encode - strindex 2"} - {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) "high encode - strindex 3"} - {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) "high encode - strindex 4"} - {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) (strindex "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) "high encode - strindex 5"} - - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "") (strsindex "𝌆𝌇𝌈𝌉" "") "high encode - strsindex 1"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") (strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") "high encode - strsindex 2"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈c") (strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈c") "high encode - strsindex 3"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") (strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") "high encode - strsindex 4"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈c") (strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈c") "high encode - strsindex 5"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌈𝌉") (strsindex "𝌆𝌇𝌈𝌉" "𝌈𝌉") "high encode - strsindex 6"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌈c") (strsindex "𝌆𝌇𝌈𝌉" "𝌈c") "high encode - strsindex 7"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌉") (strsindex "𝌆𝌇𝌈𝌉" "𝌉") "high encode - strsindex 8"} - {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "c") (strsindex "𝌆𝌇𝌈𝌉" "c") "high encode - strsindex 9"} - - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "") (strcspn "𝌆𝌇𝌈𝌉" "") "high encode - strcspn 1"} - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") (strcspn "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") "high encode - strcspn 2"} - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌆") (strcspn "𝌆𝌇𝌈𝌉" "𝌆") "high encode - strcspn 3"} - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") (strcspn "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") "high encode - strcspn 4"} - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌈𝌉") (strcspn "𝌆𝌇𝌈𝌉" "𝌈𝌉") "high encode - strcspn 5"} - {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌉") (strcspn "𝌆𝌇𝌈𝌉" "𝌉") "high encode - strcspn 6"} - - {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 0)) (ord (strsub "𝌆𝌇𝌈𝌉" 0)) "high encode - ord 1"} - {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 1)) (ord (strsub "𝌆𝌇𝌈𝌉" 1)) "high encode - ord 2"} - {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 2)) (ord (strsub "𝌆𝌇𝌈𝌉" 2)) "high encode - ord 3"} - {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 3)) (ord (strsub "𝌆𝌇𝌈𝌉" 3)) "high encode - ord 4"} + + + return + | Some tests => return + + {test_fn_cside (fn _ => strlen "𝌆𝌇𝌈𝌉") tests.SL1 "high encode - strlen 1"} + {test_fn_cside (fn _ => strlen "𝌇𝌈𝌉") tests.SL2 "high encode - strlen 2"} + {test_fn_cside (fn _ => strlen "𝌈𝌉") tests.SL3 "high encode - strlen 3"} + {test_fn_cside (fn _ => strlen "𝌉") tests.SL4 "high encode - strlen 4"} + + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 1 3) tests.SS1 "high encode - substring 1"} + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 2 2) tests.SS2 "high encode - substring 2"} + {test_fn_cside (fn _ => substring "𝌆𝌇𝌈𝌉" 3 1) tests.SS3 "high encode - substring 3"} - {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 0)) (show (strsub "𝌆𝌇𝌈𝌉" 0)) "high encode - show 1"} - {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 1)) (show (strsub "𝌆𝌇𝌈𝌉" 1)) "high encode - show 2"} - {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 2)) (show (strsub "𝌆𝌇𝌈𝌉" 2)) "high encode - show 3"} - {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 3)) (show (strsub "𝌆𝌇𝌈𝌉" 3)) "high encode - show 4"} + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 1 3)) tests.SLSS1 "high encode - strlen of substring 1"} + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 2 2)) tests.SLSS2 "high encode - strlen of substring 2"} + {test_fn_cside (fn _ => strlen (substring "𝌆𝌇𝌈𝌉" 3 1)) tests.SLSS3 "high encode - strlen of substring 3"} + + {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 0) tests.SSB1 "high encode - strsub 1"} + {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 1) tests.SSB2 "high encode - strsub 2"} + {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 2) tests.SSB3 "high encode - strsub 3"} + {test_fn_cside (fn _ => strsub "𝌆𝌇𝌈𝌉" 3) tests.SSB4 "high encode - strsub 4"} + + {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 0) tests.SSF1 "high encode - strsuffix 1"} + {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 1) tests.SSF2 "high encode - strsuffix 2"} + {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 2) tests.SSF3 "high encode - strsuffix 3"} + {test_fn_cside (fn _ => strsuffix "𝌆𝌇𝌈𝌉" 3) tests.SSF4 "high encode - strsuffix 4"} + + {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" #"c") tests.SC1 "high encode - strchr 1"} + {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) tests.SC2 "high encode - strchr 2"} + {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) tests.SC3 "high encode - strchr 3"} + {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) tests.SC4 "high encode - strchr 4"} + {test_fn_cside (fn _ => strchr "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) tests.SC5 "high encode - strchr 5"} + + {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" #"c") tests.SI1 "high encode - strindex 1"} + {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌆" 0)) tests.SI2 "high encode - strindex 2"} + {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌇" 0)) tests.SI3 "high encode - strindex 3"} + {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌈" 0)) tests.SI4 "high encode - strindex 4"} + {test_fn_cside (fn _ => strindex "𝌆𝌇𝌈𝌉" (strsub "𝌉" 0)) tests.SI5 "high encode - strindex 5"} + + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "") tests.SSI1 "high encode - strsindex 1"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") tests.SSI2 "high encode - strsindex 2"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈c") tests.SSI3 "high encode - strsindex 3"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") tests.SSI4 "high encode - strsindex 4"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌇𝌈c") tests.SSI5 "high encode - strsindex 5"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌈𝌉") tests.SSI6 "high encode - strsindex 6"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌈c") tests.SSI7 "high encode - strsindex 7"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "𝌉") tests.SSI8 "high encode - strsindex 8"} + {test_fn_cside (fn _ => strsindex "𝌆𝌇𝌈𝌉" "c") tests.SSI9 "high encode - strsindex 9"} + + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "") tests.SCSP1 "high encode - strcspn 1"} + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌆𝌇𝌈𝌉") tests.SCSP2 "high encode - strcspn 2"} + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌆") tests.SCSP3 "high encode - strcspn 3"} + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌇𝌈𝌉") tests.SCSP4 "high encode - strcspn 4"} + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌈𝌉") tests.SCSP5 "high encode - strcspn 5"} + {test_fn_cside (fn _ => strcspn "𝌆𝌇𝌈𝌉" "𝌉") tests.SCSP6 "high encode - strcspn 6"} + + {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 0)) tests.OSS1 "high encode - ord 1"} + {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 1)) tests.OSS2 "high encode - ord 2"} + {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 2)) tests.OSS3 "high encode - ord 3"} + {test_fn_cside (fn _ => ord (strsub "𝌆𝌇𝌈𝌉" 3)) tests.OSS4 "high encode - ord 4"} + + {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 0)) tests.SSS1 "high encode - show 1"} + {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 1)) tests.SSS2 "high encode - show 2"} + {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 2)) tests.SSS3 "high encode - show 3"} + {test_fn_cside (fn _ => show (strsub "𝌆𝌇𝌈𝌉" 3)) tests.SSS4 "high encode - show 4"} + + } /> - + + +(* substrings *) +fun substring1 _ = substring "abc" 0 3 +fun substring2 _ = substring "abc" 1 2 +fun substring3 _ = substring "abc" 2 1 +fun substring4 _ = substring "ábó" 0 3 +fun substring5 _ = substring "ábó" 1 2 +fun substring6 _ = substring "ábó" 2 1 +fun substring7 _ = substring "ábó" 0 2 +fun substring8 _ = substring "ábó" 0 1 +fun substring9 _ = substring "" 0 0 +fun substringsserver _ = + return { + T1 = substring1 (), + T2 = substring2 (), + T3 = substring3 (), + T4 = substring4 (), + T5 = substring5 (), + T6 = substring6 (), + T7 = substring7 (), + T8 = substring8 (), + T9 = substring9 () + } + fun substrings () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => substring "abc" 0 3) "abc" "substrings 1"} - {test_fn_both_sides (fn _ => substring "abc" 1 2) "bc" "substrings 2"} - {test_fn_both_sides (fn _ => substring "abc" 2 1) "c" "substrings 3"} - {test_fn_both_sides (fn _ => substring "ábó" 0 3) "ábó" "substrings 4"} - {test_fn_both_sides (fn _ => substring "ábó" 1 2) "bó" "substrings 5"} - {test_fn_both_sides (fn _ => substring "ábó" 2 1) "ó" "substrings 6"} - {test_fn_both_sides (fn _ => substring "ábó" 0 2) "áb" "substrings 7"} - {test_fn_both_sides (fn _ => substring "ábó" 0 1) "á" "substrings 8"} - {test_fn_both_sides (fn _ => substring "" 0 0) "" "substrings 9"} + + + return + | Some t' => + return + {test_fn_both_sides2 substring1 t'.T1 "abc" "substrings 1"} + {test_fn_both_sides2 substring2 t'.T2 "bc" "substrings 2"} + {test_fn_both_sides2 substring3 t'.T3 "c" "substrings 3"} + {test_fn_both_sides2 substring4 t'.T4 "ábó" "substrings 4"} + {test_fn_both_sides2 substring5 t'.T5 "bó" "substrings 5"} + {test_fn_both_sides2 substring6 t'.T6 "ó" "substrings 6"} + {test_fn_both_sides2 substring7 t'.T7 "áb" "substrings 7"} + {test_fn_both_sides2 substring8 t'.T8 "á" "substrings 8"} + {test_fn_both_sides2 substring9 t'.T9 "" "substrings 9"} + + } /> +(* strlen *) +fun strlen1 _ = strlen "abc" +fun strlen2 _ = strlen "çbc" +fun strlen3 _ = strlen "çãc" +fun strlen4 _ = strlen "çãó" +fun strlen5 _ = strlen "ç" +fun strlen6 _ = strlen "c" +fun strlen7 _ = strlen "" +fun strlen8 _ = strlen "が" +fun strlen9 _ = strlen "漢" +fun strlen10 _ = strlen "カ" +fun strlen11 _ = strlen "وظيفية" +fun strlen12 _ = strlen "函數" +fun strlen13 _ = strlen "Функциональное" + +fun strlensserver _ = + return { + T1 = strlen1 (), + T2 = strlen2 (), + T3 = strlen3 (), + T4 = strlen4 (), + T5 = strlen5 (), + T6 = strlen6 (), + T7 = strlen7 (), + T8 = strlen8 (), + T9 = strlen9 (), + T10 = strlen10 (), + T11 = strlen11 (), + T12 = strlen12 (), + T13 = strlen13 () + } + +fun strlens () : transaction page = + t <- source None; + return + + + return + | Some t' => + return + {test_fn_both_sides2 strlen1 t'.T1 3 "strlen 1"} + {test_fn_both_sides2 strlen2 t'.T2 3 "strlen 2"} + {test_fn_both_sides2 strlen3 t'.T3 3 "strlen 3"} + {test_fn_both_sides2 strlen4 t'.T4 3 "strlen 4"} + {test_fn_both_sides2 strlen5 t'.T5 1 "strlen 5"} + {test_fn_both_sides2 strlen6 t'.T6 1 "strlen 6"} + {test_fn_both_sides2 strlen7 t'.T7 0 "strlen 7"} + {test_fn_both_sides2 strlen8 t'.T8 1 "strlen 8"} + {test_fn_both_sides2 strlen9 t'.T9 1 "strlen 9"} + {test_fn_both_sides2 strlen10 t'.T10 1 "strlen 10"} + {test_fn_both_sides2 strlen11 t'.T11 6 "strlen 11"} + {test_fn_both_sides2 strlen12 t'.T12 2 "strlen 12"} + {test_fn_both_sides2 strlen13 t'.T13 14 "strlen 13"} + } /> -fun strlens () : transaction page = return - - {test_fn_both_sides (fn _ => strlen "abc") 3 "strlen 1"} - {test_fn_both_sides (fn _ => strlen "çbc") 3 "strlen 2"} - {test_fn_both_sides (fn _ => strlen "çãc") 3 "strlen 3"} - {test_fn_both_sides (fn _ => strlen "çãó") 3 "strlen 4"} - {test_fn_both_sides (fn _ => strlen "ç") 1 "strlen 5"} - {test_fn_both_sides (fn _ => strlen "c") 1 "strlen 6"} - {test_fn_both_sides (fn _ => strlen "") 0 "strlen 7"} - {test_fn_both_sides (fn _ => strlen "が") 1 "strlen 8"} - {test_fn_both_sides (fn _ => strlen "漢") 1 "strlen 9"} - {test_fn_both_sides (fn _ => strlen "カ") 1 "strlen 10"} - {test_fn_both_sides (fn _ => strlen "وظيفية") 6 "strlen 11"} - {test_fn_both_sides (fn _ => strlen "函數") 2 "strlen 12"} - {test_fn_both_sides (fn _ => strlen "Функциональное") 14 "strlen 13"} - - - -fun strlenGens () : transaction page = return - - {test_fn_both_sides (fn _ => strlenGe "" 1) False "strlenGe 1"} - {test_fn_both_sides (fn _ => strlenGe "" 0) True "strlenGe 2"} - {test_fn_both_sides (fn _ => strlenGe "aba" 4) False "strlenGe 3"} - {test_fn_both_sides (fn _ => strlenGe "aba" 3) True "strlenGe 4"} - {test_fn_both_sides (fn _ => strlenGe "aba" 2) True "strlenGe 5"} - {test_fn_both_sides (fn _ => strlenGe "àçá" 4) False "strlenGe 6"} - {test_fn_both_sides (fn _ => strlenGe "àçá" 3) True "strlenGe 7"} - {test_fn_both_sides (fn _ => strlenGe "àçá" 2) True "strlenGe 8"} - + + +(* strlenGe *) +fun strlenGe1 _ = strlenGe "" 1 +fun strlenGe2 _ = strlenGe "" 0 +fun strlenGe3 _ = strlenGe "aba" 4 +fun strlenGe4 _ = strlenGe "aba" 3 +fun strlenGe5 _ = strlenGe "aba" 2 +fun strlenGe6 _ = strlenGe "àçá" 4 +fun strlenGe7 _ = strlenGe "àçá" 3 +fun strlenGe8 _ = strlenGe "àçá" 2 + +fun strleGesserver _ = return { + T1 = strlenGe1 (), + T2 = strlenGe2 (), + T3 = strlenGe3 (), + T4 = strlenGe4 (), + T5 = strlenGe5 (), + T6 = strlenGe6 (), + T7 = strlenGe7 (), + T8 = strlenGe8 () + } + +fun strlenGens () : transaction page = + t <- source None; + return + + + return + | Some t' => + return + {test_fn_both_sides2 strlenGe1 t'.T1 False "strlenGe 1"} + {test_fn_both_sides2 strlenGe2 t'.T2 True "strlenGe 2"} + {test_fn_both_sides2 strlenGe3 t'.T3 False "strlenGe 3"} + {test_fn_both_sides2 strlenGe4 t'.T4 True "strlenGe 4"} + {test_fn_both_sides2 strlenGe5 t'.T5 True "strlenGe 5"} + {test_fn_both_sides2 strlenGe6 t'.T6 False "strlenGe 6"} + {test_fn_both_sides2 strlenGe7 t'.T7 True "strlenGe 7"} + {test_fn_both_sides2 strlenGe8 t'.T8 True "strlenGe 8"} + } /> + + type clen = { S : string, L : int } @@ -182,181 +413,530 @@ val clen_eq : eq clen = mkEq (fn a b => val clen_show : show clen = mkShow (fn a => "{S = " ^ a.S ^ ", L = " ^ (show a.L) ^ "}") +(* strcat *) + +fun teststrcat a b = let val c = strcat a b in {S = c, L = strlen c} end +fun teststrcat1 _ = teststrcat "" "" +fun teststrcat2 _ = teststrcat "aa" "bb" +fun teststrcat3 _ = teststrcat "" "bb" +fun teststrcat4 _ = teststrcat "aa" "" +fun teststrcat5 _ = teststrcat "àà" "áá" +fun teststrcat6 _ = teststrcat "" "áá" +fun teststrcat7 _ = teststrcat "àà" "" +fun teststrcat8 _ = teststrcat "函數" "ãã" +fun teststrcat9 _ = teststrcat "ç" "ã" +fun teststrcat10 _ = teststrcat (show (strsub "ç" 0)) (show (strsub "ã" 0)) +fun teststrcat11 _ = teststrcat (show (chr 231)) (show (chr 227)) +fun strcatsserver () = + return { + T1 = teststrcat1 (), + T2 = teststrcat2 (), + T3 = teststrcat3 (), + T4 = teststrcat4 (), + T5 = teststrcat5 (), + T6 = teststrcat6 (), + T7 = teststrcat7 (), + T8 = teststrcat8 (), + T9 = teststrcat9 (), + T10 = teststrcat10 (), + T11 = teststrcat11 () + } + fun strcats () : transaction page = - let - fun test_cat_and_len n a b expS expL = - test_fn_both_sides (fn _ => let val c = strcat a b in {S = c, L = strlen c} end) {S=expS, L=expL} ("strcat " ^ (show n)) - in - return - - {test_cat_and_len 1 "" "" "" 0} - {test_cat_and_len 2 "aa" "bb" "aabb" 4} - {test_cat_and_len 3 "" "bb" "bb" 2} - {test_cat_and_len 4 "aa" "" "aa" 2} - {test_cat_and_len 5 "àà" "áá" "ààáá" 4} - {test_cat_and_len 6 "" "áá" "áá" 2} - {test_cat_and_len 7 "àà" "" "àà" 2} - {test_cat_and_len 8 "函數" "ãã" "函數ãã" 4} - {test_cat_and_len 9 "ç" "ã" "çã" 2} - {test_cat_and_len 10 (show (strsub "ç" 0)) (show (strsub "ã" 0)) "çã" 2} - {test_cat_and_len 11 (show (chr 231)) (show (chr 227)) "çã" 2} - - -end + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 teststrcat1 t'.T1 {S="",L=0} "strcat 1" } + {test_fn_both_sides2 teststrcat2 t'.T2 {S="aabb",L=4} "strcat 2" } + {test_fn_both_sides2 teststrcat3 t'.T3 {S="bb",L=2} "strcat 3" } + {test_fn_both_sides2 teststrcat4 t'.T4 {S="aa",L=2} "strcat 4" } + {test_fn_both_sides2 teststrcat5 t'.T5 {S="ààáá",L=4} "strcat 5" } + {test_fn_both_sides2 teststrcat6 t'.T6 {S="áá",L=2} "strcat 6" } + {test_fn_both_sides2 teststrcat7 t'.T7 {S="àà",L=2} "strcat 7" } + {test_fn_both_sides2 teststrcat8 t'.T8 {S="函數ãã",L=4} "strcat 8" } + {test_fn_both_sides2 teststrcat9 t'.T9 {S="çã",L=2} "strcat 9" } + {test_fn_both_sides2 teststrcat10 t'.T10 {S="çã",L=2} "strcat 10" } + {test_fn_both_sides2 teststrcat11 t'.T11 {S="çã",L=2} "strcat 11" } + } /> + + + +(* strsubs *) +fun strsub1 _ = strsub "abàç" 0 +fun strsub2 _ = strsub "abàç" 1 +fun strsub3 _ = strsub "àb" 0 +fun strsub4 _ = strsub "abàç" 2 +fun strsub5 _ = strsub "abàç" 3 + +fun strsubsserver _ = return { + T1 = strsub1 (), + T2 = strsub2 (), + T3 = strsub3 (), + T4 = strsub4 (), + T5 = strsub5 () + } + fun strsubs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strsub "abàç" 0) #"a" "strsub 1"} - {test_fn_both_sides (fn _ => strsub "abàç" 1) #"b" "strsub 2"} - {test_fn_both_sides (fn _ => strsub "àb" 0) (strsub "à" 0) "strsub 3"} - {test_fn_both_sides (fn _ => strsub "abàç" 2) (strsub "à" 0) "strsub 4"} - {test_fn_both_sides (fn _ => strsub "abàç" 3) (strsub "ç" 0) "strsub 5"} + + return + | Some t' => return + {test_fn_both_sides2 strsub1 t'.T1 #"a" "strsub 1"} + {test_fn_both_sides2 strsub2 t'.T2 #"b" "strsub 2"} + {test_fn_both_sides2 strsub3 t'.T3 (strsub "à" 0) "strsub 3"} + {test_fn_both_sides2 strsub4 t'.T4 (strsub "à" 0) "strsub 4"} + {test_fn_both_sides2 strsub5 t'.T5 (strsub "ç" 0) "strsub 5"} + + } /> + - + +(* strsuffixs *) +fun strsuffix1 _ = strsuffix "abàç" 0 +fun strsuffix2 _ = strsuffix "abàç" 1 +fun strsuffix3 _ = strsuffix "abàç" 2 +fun strsuffix4 _ = strsuffix "abàç" 3 + +fun strsuffixsserver _ = + return { + T1 = strsuffix1 (), + T2 = strsuffix2 (), + T3 = strsuffix3 (), + T4 = strsuffix4 () + } + fun strsuffixs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strsuffix "abàç" 0) "abàç" "strsuffix 1"} - {test_fn_both_sides (fn _ => strsuffix "abàç" 1) "bàç" "strsuffix 2"} - {test_fn_both_sides (fn _ => strsuffix "abàç" 2) "àç" "strsuffix 3"} - {test_fn_both_sides (fn _ => strsuffix "abàç" 3) "ç" "strsuffix 4"} + + return + | Some t' => return + {test_fn_both_sides2 strsuffix1 t'.T1 "abàç" "strsuffix 1"} + {test_fn_both_sides2 strsuffix2 t'.T2 "bàç" "strsuffix 2"} + {test_fn_both_sides2 strsuffix3 t'.T3 "àç" "strsuffix 3"} + {test_fn_both_sides2 strsuffix4 t'.T4 "ç" "strsuffix 4"} + + } /> + +(* strchrs *) + +fun strchr1 _ = strchr "abàç" #"c" +fun strchr2 _ = strchr "abàç" #"a" +fun strchr3 _ = strchr "abàç" #"b" +fun strchr4 _ = strchr "abàç" (strsub "à" 0) +fun strchr5 _ = strchr "abàç" (strsub "ç" 0) + +fun strchrssserver _ = + return { + T1 = strchr1 (), + T2 = strchr2 (), + T3 = strchr3 (), + T4 = strchr4 (), + T5 = strchr5 () + } + fun strchrs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strchr "abàç" #"c") None "strchr 1"} - {test_fn_both_sides (fn _ => strchr "abàç" #"a") (Some "abàç") "strchr 2"} - {test_fn_both_sides (fn _ => strchr "abàç" #"b") (Some "bàç") "strchr 3"} - {test_fn_both_sides (fn _ => strchr "abàç" (strsub "à" 0)) (Some "àç") "strchr 4"} - {test_fn_both_sides (fn _ => strchr "abàç" (strsub "ç" 0)) (Some "ç") "strchr 5"} + + return + | Some t' => return + {test_fn_both_sides2 strchr1 t'.T1 None "strchr 1"} + {test_fn_both_sides2 strchr2 t'.T2 (Some "abàç") "strchr 2"} + {test_fn_both_sides2 strchr3 t'.T3 (Some "bàç") "strchr 3"} + {test_fn_both_sides2 strchr4 t'.T4 (Some "àç") "strchr 4"} + {test_fn_both_sides2 strchr5 t'.T5 (Some "ç") "strchr 5"} + + } /> + - + + +(* strindexs *) +fun strindex1 _ = strindex "abàç" #"c" +fun strindex2 _ = strindex "abàç" #"a" +fun strindex3 _ = strindex "abàç" #"b" +fun strindex4 _ = strindex "abàç" (strsub "à" 0) +fun strindex5 _ = strindex "abàç" (strsub "ç" 0) +fun strindexsserver _ = + return { + T1 = strindex1 (), + T2 = strindex2 (), + T3 = strindex3 (), + T4 = strindex4 (), + T5 = strindex5 () + } + fun strindexs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strindex "abàç" #"c") None "strindex 1"} - {test_fn_both_sides (fn _ => strindex "abàç" #"a") (Some 0) "strindex 2"} - {test_fn_both_sides (fn _ => strindex "abàç" #"b") (Some 1) "strindex 3"} - {test_fn_both_sides (fn _ => strindex "abàç" (strsub "à" 0)) (Some 2) "strindex 4"} - {test_fn_both_sides (fn _ => strindex "abàç" (strsub "ç" 0)) (Some 3) "strindex 5"} + + return + | Some t' => return + {test_fn_both_sides2 strindex1 t'.T1 None "strindex 1"} + {test_fn_both_sides2 strindex2 t'.T2 (Some 0) "strindex 2"} + {test_fn_both_sides2 strindex3 t'.T3 (Some 1) "strindex 3"} + {test_fn_both_sides2 strindex4 t'.T4 (Some 2) "strindex 4"} + {test_fn_both_sides2 strindex5 t'.T5 (Some 3) "strindex 5"} + + } /> + +(*strsindexs*) +fun strsindex1 _ = strsindex "abàç" "" +fun strsindex2 _ = strsindex "abàç" "abàç" +fun strsindex3 _ = strsindex "abàç" "abàc" +fun strsindex4 _ = strsindex "abàç" "bàç" +fun strsindex5 _ = strsindex "abàç" "bàc" +fun strsindex6 _ = strsindex "abàç" "àç" +fun strsindex7 _ = strsindex "abàç" "àc" +fun strsindex8 _ = strsindex "abàç" "ç" +fun strsindex9 _ = strsindex "abàç" "c" + +fun strsindexsserver _ = + return { + T1 = strsindex1 (), + T2 = strsindex2 (), + T3 = strsindex3 (), + T4 = strsindex4 (), + T5 = strsindex5 (), + T6 = strsindex6 (), + T7 = strsindex7 (), + T8 = strsindex8 (), + T9 = strsindex9 () + } + fun strsindexs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strsindex "abàç" "") (Some 0) "strsindex 1"} - {test_fn_both_sides (fn _ => strsindex "abàç" "abàç") (Some 0) "strsindex 2"} - {test_fn_both_sides (fn _ => strsindex "abàç" "abàc") None "strsindex 3"} - {test_fn_both_sides (fn _ => strsindex "abàç" "bàç") (Some 1) "strsindex 4"} - {test_fn_both_sides (fn _ => strsindex "abàç" "bàc") None "strsindex 5"} - {test_fn_both_sides (fn _ => strsindex "abàç" "àç") (Some 2) "strsindex 6"} - {test_fn_both_sides (fn _ => strsindex "abàç" "àc") None "strsindex 7"} - {test_fn_both_sides (fn _ => strsindex "abàç" "ç") (Some 3) "strsindex 8"} - {test_fn_both_sides (fn _ => strsindex "abàç" "c") None "strsindex 9"} + + return + | Some t' => return + {test_fn_both_sides2 strsindex1 t'.T1 (Some 0) "strsindex 1"} + {test_fn_both_sides2 strsindex2 t'.T2 (Some 0) "strsindex 2"} + {test_fn_both_sides2 strsindex3 t'.T3 None "strsindex 3"} + {test_fn_both_sides2 strsindex4 t'.T4 (Some 1) "strsindex 4"} + {test_fn_both_sides2 strsindex5 t'.T5 None "strsindex 5"} + {test_fn_both_sides2 strsindex6 t'.T6 (Some 2) "strsindex 6"} + {test_fn_both_sides2 strsindex7 t'.T7 None "strsindex 7"} + {test_fn_both_sides2 strsindex8 t'.T8 (Some 3) "strsindex 8"} + {test_fn_both_sides2 strsindex9 t'.T9 None "strsindex 9"} + + } /> + - + + +(*strcspns*) +fun strcspn1 _ = strcspn "abàç" "" +fun strcspn2 _ = strcspn "abàç" "abàç" +fun strcspn3 _ = strcspn "abàç" "a" +fun strcspn4 _ = strcspn "abàç" "bà" +fun strcspn5 _ = strcspn "abàç" "àç" +fun strcspn6 _ = strcspn "abàç" "ç" +fun strcspnsserver _ = + return { + T1 = strcspn1 (), + T2 = strcspn2 (), + T3 = strcspn3 (), + T4 = strcspn4 (), + T5 = strcspn5 (), + T6 = strcspn6 () + } + fun strcspns () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => strcspn "abàç" "") 4 "strcspn 1"} - {test_fn_both_sides (fn _ => strcspn "abàç" "abàç") 0 "strcspn 2"} - {test_fn_both_sides (fn _ => strcspn "abàç" "a") 0 "strcspn 3"} - {test_fn_both_sides (fn _ => strcspn "abàç" "bàç") 1 "strcspn 4"} - {test_fn_both_sides (fn _ => strcspn "abàç" "àç") 2 "strcspn 5"} - {test_fn_both_sides (fn _ => strcspn "abàç" "ç") 3 "strcspn 6"} + + return + | Some t' => return + {test_fn_both_sides2 strcspn1 t'.T1 4 "strcspn 1"} + {test_fn_both_sides2 strcspn2 t'.T2 0 "strcspn 2"} + {test_fn_both_sides2 strcspn3 t'.T3 0 "strcspn 3"} + {test_fn_both_sides2 strcspn4 t'.T4 1 "strcspn 4"} + {test_fn_both_sides2 strcspn5 t'.T5 2 "strcspn 5"} + {test_fn_both_sides2 strcspn6 t'.T6 3 "strcspn 6"} + + } /> + - + -fun str1s () : transaction page = return - - {test_fn_both_sides (fn _ => str1 #"a") "a" "str1 1"} - {test_fn_both_sides (fn _ => str1 (strsub "à" 0)) "à" "str1 2"} - {test_fn_both_sides (fn _ => str1 (strsub "aá" 1)) "á" "str1 3"} - - - -fun isalnums () : transaction page = return - - {test_fn_both_sides (fn _ => isalnum #"a") True "isalnum 1"} - {test_fn_both_sides (fn _ => isalnum #"a") True "isalnum 2"} - {test_fn_both_sides (fn _ => isalnum (strsub "à" 0)) True "isalnum 3"} - {test_fn_both_sides (fn _ => isalnum #"A") True "isalnum 4"} - {test_fn_both_sides (fn _ => isalnum (strsub "À" 0)) True "isalnum 5"} - {test_fn_both_sides (fn _ => isalnum #"1") True "isalnum 6"} - {test_fn_both_sides (fn _ => not (isalnum #"!")) True "isalnum 7"} - {test_fn_both_sides (fn _ => not (isalnum #"#")) True "isalnum 8"} - {test_fn_both_sides (fn _ => not (isalnum #" ")) True "isalnum 9"} - - +(* str1 *) +fun str11 _ = str1 #"a" +fun str12 _ = str1 (strsub "à" 0) +fun str13 _ = str1 (strsub "aá" 1) -fun isalphas () : transaction page = return - - {test_fn_both_sides (fn _ => isalpha #"a") True "isalpha 1"} - {test_fn_both_sides (fn _ => isalpha (strsub "à" 0)) True "isalpha 2"} - {test_fn_both_sides (fn _ => isalpha #"A") True "isalpha 3"} - {test_fn_both_sides (fn _ => isalpha (strsub "À" 0)) True "isalpha 4"} - {test_fn_both_sides (fn _ => not (isalpha #"1")) True "isalpha 5"} - {test_fn_both_sides (fn _ => not (isalpha #"!")) True "isalpha 6"} - {test_fn_both_sides (fn _ => not (isalpha #"#")) True "isalpha 7"} - {test_fn_both_sides (fn _ => not (isalpha #" ")) True "isalpha 8"} - +fun str1server _ = + return { + T1 = str11 (), + T2 = str12 (), + T3 = str13 () + } + +fun str1s () : transaction page = + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 str11 t'.T1 "a" "str1 1"} + {test_fn_both_sides2 str12 t'.T2 "à" "str1 2"} + {test_fn_both_sides2 str13 t'.T3 "á" "str1 3"} + + } /> + + + + +(* isalnum *) + +fun isalnum1 _ = isalnum #"a" +fun isalnum2 _ = isalnum #"a" +fun isalnum3 _ = isalnum (strsub "à" 0) +fun isalnum4 _ = isalnum #"A" +fun isalnum5 _ = isalnum (strsub "À" 0) +fun isalnum6 _ = isalnum #"1" +fun isalnum7 _ = not (isalnum #"!") +fun isalnum8 _ = not (isalnum #"#") +fun isalnum9 _ = not (isalnum #" ") + +fun isalnumsserver _ = return { + T1 = isalnum1 (), + T2 = isalnum2 (), + T3 = isalnum3 (), + T4 = isalnum4 (), + T5 = isalnum5 (), + T6 = isalnum6 (), + T7 = isalnum7 (), + T8 = isalnum8 (), + T9 = isalnum9 () + } + +fun isalnums () : transaction page = + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 isalnum1 t'.T1 True "isalnum 1"} + {test_fn_both_sides2 isalnum2 t'.T2 True "isalnum 2"} + {test_fn_both_sides2 isalnum3 t'.T3 True "isalnum 3"} + {test_fn_both_sides2 isalnum4 t'.T4 True "isalnum 4"} + {test_fn_both_sides2 isalnum5 t'.T5 True "isalnum 5"} + {test_fn_both_sides2 isalnum6 t'.T6 True "isalnum 6"} + {test_fn_both_sides2 isalnum7 t'.T7 True "isalnum 7"} + {test_fn_both_sides2 isalnum8 t'.T8 True "isalnum 8"} + {test_fn_both_sides2 isalnum9 t'.T9 True "isalnum 9"} + + } /> + + + + +(* isalpha *) +fun isalpha1 _ = isalpha #"a" +fun isalpha2 _ = isalpha (strsub "à" 0) +fun isalpha3 _ = isalpha #"A" +fun isalpha4 _ = isalpha (strsub "À" 0) +fun isalpha5 _ = not (isalpha #"1") +fun isalpha6 _ = not (isalpha #"!") +fun isalpha7 _ = not (isalpha #"#") +fun isalpha8 _ = not (isalpha #" ") + +fun isalphasserver () = + return { + T1 = isalpha1 (), + T2 = isalpha2 (), + T3 = isalpha3 (), + T4 = isalpha4 (), + T5 = isalpha5 (), + T6 = isalpha6 (), + T7 = isalpha7 (), + T8 = isalpha8 () + } + +fun isalphas () : transaction page = + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 isalpha1 t'.T1 True "isalpha 1"} + {test_fn_both_sides2 isalpha2 t'.T2 True "isalpha 2"} + {test_fn_both_sides2 isalpha3 t'.T3 True "isalpha 3"} + {test_fn_both_sides2 isalpha4 t'.T4 True "isalpha 4"} + {test_fn_both_sides2 isalpha5 t'.T5 True "isalpha 5"} + {test_fn_both_sides2 isalpha6 t'.T6 True "isalpha 6"} + {test_fn_both_sides2 isalpha7 t'.T7 True "isalpha 7"} + {test_fn_both_sides2 isalpha8 t'.T8 True "isalpha 8"} + + } /> + + -fun isblanks () : transaction page = +(* isblanks *) +fun isblank1 _ = not (isblank #"a") +fun isblank2 _ = not (isblank (strsub "à" 0)) +fun isblank3 _ = not (isblank #"A") +fun isblank4 _ = not (isblank (strsub "À" 0)) +fun isblank5 _ = not (isblank #"1") +fun isblank6 _ = not (isblank #"!") +fun isblank7 _ = not (isblank #"#") +fun isblank8 _ = isblank #" " +fun isblank9 _ = isblank #"\t" +fun isblank10 _ = not (isblank #"\n") + +fun isblanksserver _ = + return { + T1 = isblank1 (), + T2 = isblank2 (), + T3 = isblank3 (), + T4 = isblank4 (), + T5 = isblank5 (), + T6 = isblank6 (), + T7 = isblank7 (), + T8 = isblank8 (), + T9 = isblank9 (), + T10 = isblank10 () + } + +fun isblanks () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => not (isblank #"a")) True "isblank 1"} - {test_fn_both_sides (fn _ => not (isblank (strsub "à" 0))) True "isblank 2"} - {test_fn_both_sides (fn _ => not (isblank #"A")) True "isblank 3"} - {test_fn_both_sides (fn _ => not (isblank (strsub "À" 0))) True "isblank 4"} - {test_fn_both_sides (fn _ => not (isblank #"1")) True "isblank 5"} - {test_fn_both_sides (fn _ => not (isblank #"!")) True "isblank 6"} - {test_fn_both_sides (fn _ => not (isblank #"#")) True "isblank 7"} - {test_fn_both_sides (fn _ => isblank #" ") True "isblank 8"} - {test_fn_both_sides (fn _ => isblank #"\t") True "isblank 9"} - {test_fn_both_sides (fn _ => not (isblank #"\n")) True "isblank 10"} + + return + | Some t' => return + {test_fn_both_sides2 isblank1 t'.T1 True "isblank 1"} + {test_fn_both_sides2 isblank2 t'.T2 True "isblank 2"} + {test_fn_both_sides2 isblank3 t'.T3 True "isblank 3"} + {test_fn_both_sides2 isblank4 t'.T4 True "isblank 4"} + {test_fn_both_sides2 isblank5 t'.T5 True "isblank 5"} + {test_fn_both_sides2 isblank6 t'.T6 True "isblank 6"} + {test_fn_both_sides2 isblank7 t'.T7 True "isblank 7"} + {test_fn_both_sides2 isblank8 t'.T8 True "isblank 8"} + {test_fn_both_sides2 isblank9 t'.T9 True "isblank 9"} + {test_fn_both_sides2 isblank10 t'.T10 True "isblank 10"} + + } /> + - + + +(* iscntrls *) +fun iscntrl1 _ = not (iscntrl #"a") +fun iscntrl2 _ = not (iscntrl (strsub "à" 0)) +fun iscntrl3 _ = not (iscntrl #"A") +fun iscntrl4 _ = not (iscntrl (strsub "À" 0)) +fun iscntrl5 _ = not (iscntrl #"1") +fun iscntrl6 _ = not (iscntrl #"!") +fun iscntrl7 _ = not (iscntrl #"#") +fun iscntrl8 _ = not (iscntrl #" ") +fun iscntrl9 _ = iscntrl #"\t" +fun iscntrl10 _ = iscntrl #"\n" fun iscntrls () : transaction page = return - {test_fn_sside (fn _ => not (iscntrl #"a")) True "iscntrl 1"} - {test_fn_sside (fn _ => not (iscntrl (strsub "à" 0))) True "iscntrl 2"} - {test_fn_sside (fn _ => not (iscntrl #"A")) True "iscntrl 3"} - {test_fn_sside (fn _ => not (iscntrl (strsub "À" 0))) True "iscntrl 4"} - {test_fn_sside (fn _ => not (iscntrl #"1")) True "iscntrl 5"} - {test_fn_sside (fn _ => not (iscntrl #"!")) True "iscntrl 6"} - {test_fn_sside (fn _ => not (iscntrl #"#")) True "iscntrl 7"} - {test_fn_sside (fn _ => not (iscntrl #" ")) True "iscntrl 8"} - {test_fn_sside (fn _ => iscntrl #"\t") True "iscntrl 9"} - {test_fn_sside (fn _ => iscntrl #"\n") True "iscntrl 10"} + {test_fn_sside iscntrl1 True "iscntrl 1"} + {test_fn_sside iscntrl2 True "iscntrl 2"} + {test_fn_sside iscntrl3 True "iscntrl 3"} + {test_fn_sside iscntrl4 True "iscntrl 4"} + {test_fn_sside iscntrl5 True "iscntrl 5"} + {test_fn_sside iscntrl6 True "iscntrl 6"} + {test_fn_sside iscntrl7 True "iscntrl 7"} + {test_fn_sside iscntrl8 True "iscntrl 8"} + {test_fn_sside iscntrl9 True "iscntrl 9"} + {test_fn_sside iscntrl10 True "iscntrl 10"} - + + +(* isdigits *) +fun isdigit1 _ = not (isdigit #"a") +fun isdigit2 _ = not (isdigit (strsub "à" 0)) +fun isdigit3 _ = not (isdigit #"A") +fun isdigit4 _ = not (isdigit (strsub "À" 0)) +fun isdigit5 _ = isdigit #"1" +fun isdigit6 _ = not (isdigit #"!") +fun isdigit7 _ = not (isdigit #"#") +fun isdigit8 _ = not (isdigit #" ") +fun isdigit9 _ = not (isdigit #"\t") +fun isdigit10 _ = not (isdigit #"\n") +fun isdigitsserver _ = + return { + T1 = isdigit1 (), + T2 = isdigit2 (), + T3 = isdigit3 (), + T4 = isdigit4 (), + T5 = isdigit5 (), + T6 = isdigit6 (), + T7 = isdigit7 (), + T8 = isdigit8 (), + T9 = isdigit9 (), + T10 = isdigit10 () + } + fun isdigits () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => not (isdigit #"a")) True "isdigit 1"} - {test_fn_both_sides (fn _ => not (isdigit (strsub "à" 0))) True "isdigit 2"} - {test_fn_both_sides (fn _ => not (isdigit #"A")) True "isdigit 3"} - {test_fn_both_sides (fn _ => not (isdigit (strsub "À" 0))) True "isdigit 4"} - {test_fn_both_sides (fn _ => isdigit #"1") True "isdigit 5"} - {test_fn_both_sides (fn _ => not (isdigit #"!")) True "isdigit 6"} - {test_fn_both_sides (fn _ => not (isdigit #"#")) True "isdigit 7"} - {test_fn_both_sides (fn _ => not (isdigit #" ")) True "isdigit 8"} - {test_fn_both_sides (fn _ => not (isdigit #"\t")) True "isdigit 9"} - {test_fn_both_sides (fn _ => not (isdigit #"\n")) True "isdigit 10"} - - + + return + | Some t' => return + {test_fn_both_sides2 isdigit1 t'.T1 True "isdigit 1"} + {test_fn_both_sides2 isdigit2 t'.T2 True "isdigit 2"} + {test_fn_both_sides2 isdigit3 t'.T3 True "isdigit 3"} + {test_fn_both_sides2 isdigit4 t'.T4 True "isdigit 4"} + {test_fn_both_sides2 isdigit5 t'.T5 True "isdigit 5"} + {test_fn_both_sides2 isdigit6 t'.T6 True "isdigit 6"} + {test_fn_both_sides2 isdigit7 t'.T7 True "isdigit 7"} + {test_fn_both_sides2 isdigit8 t'.T8 True "isdigit 8"} + {test_fn_both_sides2 isdigit9 t'.T9 True "isdigit 9"} + {test_fn_both_sides2 isdigit10 t'.T10 True "isdigit 10"} + + } /> + + + + fun isgraphs () : transaction page = return @@ -374,169 +954,498 @@ fun isgraphs () : transaction page = +(* islowers *) +fun islower1 _ = islower #"a" +fun islower2 _ = islower (strsub "à" 0) +fun islower3 _ = not (islower #"A") +fun islower4 _ = not (islower (strsub "À" 0)) +fun islower5 _ = not (islower #"1") +fun islower6 _ = not (islower #"!") +fun islower7 _ = not (islower #"#") +fun islower8 _ = not (islower #" ") +fun islower9 _ = not (islower #"\t") +fun islower10 _ = not (islower #"\n") + +fun islowersserver _ = + return { + T1 = islower1 (), + T2 = islower2 (), + T3 = islower3 (), + T4 = islower4 (), + T5 = islower5 (), + T6 = islower6 (), + T7 = islower7 (), + T8 = islower8 (), + T9 = islower9 (), + T10 = islower10 () + } + fun islowers () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => islower #"a") True "islower 1"} - {test_fn_both_sides (fn _ => islower (strsub "à" 0)) True "islower 2"} - {test_fn_both_sides (fn _ => not (islower #"A")) True "islower 3"} - {test_fn_both_sides (fn _ => not (islower (strsub "À" 0))) True "islower 4"} - {test_fn_both_sides (fn _ => not (islower #"1")) True "islower 5"} - {test_fn_both_sides (fn _ => not (islower #"!")) True "islower 6"} - {test_fn_both_sides (fn _ => not (islower #"#")) True "islower 7"} - {test_fn_both_sides (fn _ => not (islower #" ")) True "islower 8"} - {test_fn_both_sides (fn _ => not (islower #"\t")) True "islower 9"} - {test_fn_both_sides (fn _ => not (islower #"\n")) True "islower 10"} + + return + | Some t' => return + {test_fn_both_sides2 islower1 t'.T1 True "islower 1"} + {test_fn_both_sides2 islower2 t'.T2 True "islower 2"} + {test_fn_both_sides2 islower3 t'.T3 True "islower 3"} + {test_fn_both_sides2 islower4 t'.T4 True "islower 4"} + {test_fn_both_sides2 islower5 t'.T5 True "islower 5"} + {test_fn_both_sides2 islower6 t'.T6 True "islower 6"} + {test_fn_both_sides2 islower7 t'.T7 True "islower 7"} + {test_fn_both_sides2 islower8 t'.T8 True "islower 8"} + {test_fn_both_sides2 islower9 t'.T9 True "islower 9"} + {test_fn_both_sides2 islower10 t'.T10 True "islower 10"} + + } /> - + + +(* isprint *) +fun isprint1 _ = isprint #"a" +fun isprint2 _ = isprint (strsub "à" 0) +fun isprint3 _ = isprint #"A" +fun isprint4 _ = isprint (strsub "À" 0) +fun isprint5 _ = isprint #"1" +fun isprint6 _ = isprint #"!" +fun isprint7 _ = isprint #"#" +fun isprint8 _ = isprint #" " +fun isprint9 _ = not (isprint #"\t") +fun isprint10 _ = not (isprint #"\n") +fun isprintsserver _ = return { + T1 = isprint1 (), + T2 = isprint2 (), + T3 = isprint3 (), + T4 = isprint4 (), + T5 = isprint5 (), + T6 = isprint6 (), + T7 = isprint7 (), + T8 = isprint8 (), + T9 = isprint9 (), + T10 = isprint10 () + } + fun isprints () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => isprint #"a") True "isprint 1"} - {test_fn_both_sides (fn _ => isprint (strsub "à" 0)) True "isprint 2"} - {test_fn_both_sides (fn _ => isprint #"A") True "isprint 3"} - {test_fn_both_sides (fn _ => isprint (strsub "À" 0)) True "isprint 4"} - {test_fn_both_sides (fn _ => isprint #"1") True "isprint 5"} - {test_fn_both_sides (fn _ => isprint #"!") True "isprint 6"} - {test_fn_both_sides (fn _ => isprint #"#") True "isprint 7"} - {test_fn_both_sides (fn _ => isprint #" ") True "isprint 8"} - {test_fn_both_sides (fn _ => not (isprint #"\t")) True "isprint 9"} - {test_fn_both_sides (fn _ => not (isprint #"\n")) True "isprint 10"} - - + + return + | Some t' => return + {test_fn_both_sides2 isprint1 t'.T1 True "isprint 1"} + {test_fn_both_sides2 isprint2 t'.T2 True "isprint 2"} + {test_fn_both_sides2 isprint3 t'.T3 True "isprint 3"} + {test_fn_both_sides2 isprint4 t'.T4 True "isprint 4"} + {test_fn_both_sides2 isprint5 t'.T5 True "isprint 5"} + {test_fn_both_sides2 isprint6 t'.T6 True "isprint 6"} + {test_fn_both_sides2 isprint7 t'.T7 True "isprint 7"} + {test_fn_both_sides2 isprint8 t'.T8 True "isprint 8"} + {test_fn_both_sides2 isprint9 t'.T9 True "isprint 9"} + {test_fn_both_sides2 isprint10 t'.T10 True "isprint 10"} + + } /> + + +(* ispunct *) +fun ispunct1 _ = not (ispunct #"a") +fun ispunct2 _ = not (ispunct (strsub "à" 0)) +fun ispunct3 _ = not (ispunct #"A") +fun ispunct4 _ = not (ispunct (strsub "À" 0)) +fun ispunct5 _ = not (ispunct #"1") +fun ispunct6 _ = ispunct #"!" +fun ispunct7 _ = ispunct #"#" +fun ispunct8 _ = not (ispunct #" ") +fun ispunct9 _ = not (ispunct #"\t") +fun ispunct10 _ = not (ispunct #"\n") + fun ispuncts () : transaction page = return - - {test_fn_sside (fn _ => not (ispunct #"a")) True "ispunct 1"} - {test_fn_sside (fn _ => not (ispunct (strsub "à" 0))) True "ispunct 2"} - {test_fn_sside (fn _ => not (ispunct #"A")) True "ispunct 3"} - {test_fn_sside (fn _ => not (ispunct (strsub "À" 0))) True "ispunct 4"} - {test_fn_sside (fn _ => not (ispunct #"1")) True "ispunct 5"} - {test_fn_sside (fn _ => ispunct #"!") True "ispunct 6"} - {test_fn_sside (fn _ => ispunct #"#") True "ispunct 7"} - {test_fn_sside (fn _ => not (ispunct #" ")) True "ispunct 8"} - {test_fn_sside (fn _ => not (isprint #"\t")) True "ispunct 9"} - {test_fn_sside (fn _ => not (isprint #"\n")) True "ispunct 10"} + + {test_fn_sside ispunct1 True "ispunct 1"} + {test_fn_sside ispunct2 True "ispunct 2"} + {test_fn_sside ispunct3 True "ispunct 3"} + {test_fn_sside ispunct4 True "ispunct 4"} + {test_fn_sside ispunct5 True "ispunct 5"} + {test_fn_sside ispunct6 True "ispunct 6"} + {test_fn_sside ispunct7 True "ispunct 7"} + {test_fn_sside ispunct8 True "ispunct 8"} + {test_fn_sside ispunct9 True "ispunct 9"} + {test_fn_sside ispunct10 True "ispunct 10"} - + + +(* isspace *) +fun isspace1 _ = not (isspace #"a") +fun isspace2 _ = not (isspace (strsub "à" 0)) +fun isspace3 _ = not (isspace #"A") +fun isspace4 _ = not (isspace (strsub "À" 0)) +fun isspace5 _ = not (isspace #"1") +fun isspace6 _ = not (isspace #"!") +fun isspace7 _ = not (isspace #"#") +fun isspace8 _ = isspace #" " +fun isspace9 _ = isspace #"\t" +fun isspace10 _ = isspace #"\n" +fun isspacesserver _ = + return { + T1 = isspace1 (), + T2 = isspace2 (), + T3 = isspace3 (), + T4 = isspace4 (), + T5 = isspace5 (), + T6 = isspace6 (), + T7 = isspace7 (), + T8 = isspace8 (), + T9 = isspace9 (), + T10 = isspace10 () + } + fun isspaces () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => not (isspace #"a")) True "isspace 1"} - {test_fn_both_sides (fn _ => not (isspace (strsub "à" 0))) True "isspace 2"} - {test_fn_both_sides (fn _ => not (isspace #"A")) True "isspace 3"} - {test_fn_both_sides (fn _ => not (isspace (strsub "À" 0))) True "isspace 4"} - {test_fn_both_sides (fn _ => not (isspace #"1")) True "isspace 5"} - {test_fn_both_sides (fn _ => not (isspace #"!")) True "isspace 6"} - {test_fn_both_sides (fn _ => not (isspace #"#")) True "isspace 7"} - {test_fn_both_sides (fn _ => isspace #" ") True "isspace 8"} - {test_fn_both_sides (fn _ => isspace #"\t") True "isspace 9"} - {test_fn_both_sides (fn _ => isspace #"\n") True "isspace 10"} + + return + | Some t' => return + {test_fn_both_sides2 isspace1 t'.T1 True "isspace 1"} + {test_fn_both_sides2 isspace2 t'.T2 True "isspace 2"} + {test_fn_both_sides2 isspace3 t'.T3 True "isspace 3"} + {test_fn_both_sides2 isspace4 t'.T4 True "isspace 4"} + {test_fn_both_sides2 isspace5 t'.T5 True "isspace 5"} + {test_fn_both_sides2 isspace6 t'.T6 True "isspace 6"} + {test_fn_both_sides2 isspace7 t'.T7 True "isspace 7"} + {test_fn_both_sides2 isspace8 t'.T8 True "isspace 8"} + {test_fn_both_sides2 isspace9 t'.T9 True "isspace 9"} + {test_fn_both_sides2 isspace10 t'.T10 True "isspace 10"} + + } /> + - - + + +(* isupper *) +fun isupper1 _ = not (isupper #"a") +fun isupper2 _ = not (isupper (strsub "à" 0)) +fun isupper3 _ = isupper #"A" +fun isupper4 _ = isupper (strsub "À" 0) +fun isupper5 _ = not (isupper #"1") +fun isupper6 _ = not (isupper #"!") +fun isupper7 _ = not (isupper #"#") +fun isupper8 _ = not (isupper #" ") +fun isupper9 _ = not (isupper #"\t") +fun isupper10 _ = not (isupper #"\n") + +fun isuppersserver _ = + return { + T1 = isupper1 (), + T2 = isupper2 (), + T3 = isupper3 (), + T4 = isupper4 (), + T5 = isupper5 (), + T6 = isupper6 (), + T7 = isupper7 (), + T8 = isupper8 (), + T9 = isupper9 (), + T10 = isupper10 () + } + fun isuppers () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => not (isupper #"a")) True "isupper 1"} - {test_fn_both_sides (fn _ => not (isupper (strsub "à" 0))) True "isupper 2"} - {test_fn_both_sides (fn _ => isupper #"A") True "isupper 3"} - {test_fn_both_sides (fn _ => isupper (strsub "À" 0)) True "isupper 4"} - {test_fn_both_sides (fn _ => not (isupper #"1")) True "isupper 5"} - {test_fn_both_sides (fn _ => not (isupper #"!")) True "isupper 6"} - {test_fn_both_sides (fn _ => not (isupper #"#")) True "isupper 7"} - {test_fn_both_sides (fn _ => not (isupper #" ")) True "isupper 8"} - {test_fn_both_sides (fn _ => not (isupper #"\t")) True "isupper 9"} - {test_fn_both_sides (fn _ => not (isupper #"\n")) True "isupper 10"} - - + + return + | Some t' => return + {test_fn_both_sides2 isupper1 t'.T1 True "isupper 1"} + {test_fn_both_sides2 isupper2 t'.T2 True "isupper 2"} + {test_fn_both_sides2 isupper3 t'.T3 True "isupper 3"} + {test_fn_both_sides2 isupper4 t'.T4 True "isupper 4"} + {test_fn_both_sides2 isupper5 t'.T5 True "isupper 5"} + {test_fn_both_sides2 isupper6 t'.T6 True "isupper 6"} + {test_fn_both_sides2 isupper7 t'.T7 True "isupper 7"} + {test_fn_both_sides2 isupper8 t'.T8 True "isupper 8"} + {test_fn_both_sides2 isupper9 t'.T9 True "isupper 9"} + {test_fn_both_sides2 isupper10 t'.T10 True "isupper 10"} + + } /> + + + +(* isxdigit *) +fun isxdigit1 _ = isxdigit #"a" +fun isxdigit2 _ = not (isxdigit (strsub "à" 0)) +fun isxdigit3 _ = isxdigit #"A" +fun isxdigit4 _ = not (isxdigit (strsub "À" 0)) +fun isxdigit5 _ = isxdigit #"1" +fun isxdigit6 _ = not (isxdigit #"!") +fun isxdigit7 _ = not (isxdigit #"#") +fun isxdigit8 _ = not (isxdigit #" ") +fun isxdigit9 _ = not (isxdigit #"\t") +fun isxdigit10 _ = not (isxdigit #"\n") + +fun isxdigitsserver _ = + return { + T1 = isxdigit1 (), + T2 = isxdigit2 (), + T3 = isxdigit3 (), + T4 = isxdigit4 (), + T5 = isxdigit5 (), + T6 = isxdigit6 (), + T7 = isxdigit7 (), + T8 = isxdigit8 (), + T9 = isxdigit9 (), + T10 = isxdigit10 () + } + fun isxdigits () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => isxdigit #"a") True "isxdigit 1"} - {test_fn_both_sides (fn _ => not (isxdigit (strsub "à" 0))) True "isxdigit 2"} - {test_fn_both_sides (fn _ => isxdigit #"A") True "isxdigit 3"} - {test_fn_both_sides (fn _ => not (isxdigit (strsub "À" 0))) True "isxdigit 4"} - {test_fn_both_sides (fn _ => isxdigit #"1") True "isxdigit 5"} - {test_fn_both_sides (fn _ => not (isxdigit #"!")) True "isxdigit 6"} - {test_fn_both_sides (fn _ => not (isxdigit #"#")) True "isxdigit 7"} - {test_fn_both_sides (fn _ => not (isxdigit #" ")) True "isxdigit 8"} - {test_fn_both_sides (fn _ => not (isxdigit #"\t")) True "isxdigit 9"} - {test_fn_both_sides (fn _ => not (isxdigit #"\n")) True "isxdigit 10"} + + return + | Some t' => return + {test_fn_both_sides2 isxdigit1 t'.T1 True "isxdigit 1"} + {test_fn_both_sides2 isxdigit2 t'.T2 True "isxdigit 2"} + {test_fn_both_sides2 isxdigit3 t'.T3 True "isxdigit 3"} + {test_fn_both_sides2 isxdigit4 t'.T4 True "isxdigit 4"} + {test_fn_both_sides2 isxdigit5 t'.T5 True "isxdigit 5"} + {test_fn_both_sides2 isxdigit6 t'.T6 True "isxdigit 6"} + {test_fn_both_sides2 isxdigit7 t'.T7 True "isxdigit 7"} + {test_fn_both_sides2 isxdigit8 t'.T8 True "isxdigit 8"} + {test_fn_both_sides2 isxdigit9 t'.T9 True "isxdigit 9"} + {test_fn_both_sides2 isxdigit10 t'.T10 True "isxdigit 10"} + + } /> + - + + +(* tolower *) + +fun tolower1 _ = tolower #"A" +fun tolower2 _ = tolower #"a" +fun tolower3 _ = tolower (strsub "á" 0) +fun tolower4 _ = tolower (strsub "Á" 0) +fun tolower5 _ = tolower #"1" +fun tolower6 _ = tolower (strsub "ß" 0) + +fun tolowersserver _ = + return { + T1 = tolower1 (), + T2 = tolower2 (), + T3 = tolower3 (), + T4 = tolower4 (), + T5 = tolower5 (), + T6 = tolower6 () + } fun tolowers () : transaction page = - let - fun lower_of a _ = - tolower a - in - return - - {test_fn_both_sides (lower_of #"A") #"a" "tolower 1"} - {test_fn_both_sides (lower_of #"a") #"a" "tolower 2"} - {test_fn_both_sides (lower_of (strsub "á" 0)) (strsub "á" 0) "tolower 3"} - {test_fn_both_sides (lower_of (strsub "Á" 0)) (strsub "á" 0) "tolower 4"} - {test_fn_both_sides (lower_of #"1") #"1" "tolower 5"} - {test_fn_cside (lower_of (strsub "ß" 0)) (lower_of (strsub "ß" 0) ()) "tolower 6"} - + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 tolower1 t'.T1 #"a" "tolower 1"} + {test_fn_both_sides2 tolower2 t'.T2 #"a" "tolower 2"} + {test_fn_both_sides2 tolower3 t'.T3 (strsub "á" 0) "tolower 3"} + {test_fn_both_sides2 tolower4 t'.T4 (strsub "á" 0) "tolower 4"} + {test_fn_both_sides2 tolower5 t'.T5 #"1" "tolower 5"} + {test_fn_both_sides2 tolower6 t'.T6 (strsub "ß" 0) "tolower 6"} + + + } /> + + - end - + +(* toupper *) +fun toupper1 _ = toupper #"A" +fun toupper2 _ = toupper #"a" +fun toupper3 _ = toupper (strsub "á" 0) +fun toupper4 _ = toupper (strsub "Á" 0) +fun toupper5 _ = toupper #"1" +fun toupper6 _ = toupper (strsub "ß" 0) + +fun touppersserver _ = + return { + T1 = toupper1 (), + T2 = toupper2 (), + T3 = toupper3 (), + T4 = toupper4 (), + T5 = toupper5 (), + T6 = toupper6 () + } + fun touppers () : transaction page = - let - fun upper_of a _ = - toupper a - in - return - - {test_fn_both_sides (upper_of #"A") #"A" "toupper 1"} - {test_fn_both_sides (upper_of #"a") #"A" "toupper 2"} - {test_fn_both_sides (upper_of (strsub "á" 0)) (strsub "Á" 0) "toupper 3"} - {test_fn_both_sides (upper_of (strsub "Á" 0)) (strsub "Á" 0) "toupper 4"} - {test_fn_both_sides (upper_of #"1") #"1" "toupper 5"} - - {test_fn_cside (upper_of (strsub "ß" 0)) (upper_of (strsub "ß" 0) ()) "toupper 6"} - + t <- source None; + return + + return + | Some t' => return + {test_fn_both_sides2 toupper1 t'.T1 #"A" "toupper 1"} + {test_fn_both_sides2 toupper2 t'.T2 #"A" "toupper 2"} + {test_fn_both_sides2 toupper3 t'.T3 (strsub "Á" 0) "toupper 3"} + {test_fn_both_sides2 toupper4 t'.T4 (strsub "Á" 0) "toupper 4"} + {test_fn_both_sides2 toupper5 t'.T5 #"1" "toupper 5"} + {test_fn_both_sides2 toupper6 t'.T6 (strsub "ß" 0) "toupper 6"} + + + } /> + + - end +(* ord and chr*) +fun ordchr1 _ = chr (ord #"A") +fun ordchr2 _ = chr (ord #"a") +fun ordchr3 _ = chr (ord (strsub "á" 0)) +fun ordchr4 _ = chr (ord (strsub "Á" 0)) +fun ordchr5 _ = chr (ord #"1") +fun ordchr6 _ = chr (ord #"\n") +fun ordchr7 _ = chr (ord (strsub "が" 0)) +fun ordchr8 _ = chr (ord (strsub "漢" 0)) +fun ordchr9 _ = chr (ord (strsub "カ" 0)) + +fun ordchrsserver _ = return { + T1 = ordchr1 (), + T2 = ordchr2 (), + T3 = ordchr3 (), + T4 = ordchr4 (), + T5 = ordchr5 (), + T6 = ordchr6 (), + T7 = ordchr7 (), + T8 = ordchr8 (), + T9 = ordchr9 () + } + fun ord_and_chrs () : transaction page = + t <- source None; return - - {test_fn_both_sides (fn _ => chr (ord #"A")) #"A" "ord => chr 1"} - {test_fn_both_sides (fn _ => chr (ord #"a")) #"a" "ord => chr 2"} - {test_fn_both_sides (fn _ => chr (ord (strsub "á" 0))) (strsub "á" 0) "ord => chr 3"} - {test_fn_both_sides (fn _ => chr (ord (strsub "Á" 0))) (strsub "Á" 0) "ord => chr 4"} - {test_fn_both_sides (fn _ => chr (ord #"1")) #"1" "ord => chr 5"} - {test_fn_both_sides (fn _ => chr (ord #"\n")) #"\n" "ord => chr 6"} - {test_fn_both_sides (fn _ => chr (ord (strsub "が" 0))) (strsub "が" 0) "ord => chr 7"} - {test_fn_both_sides (fn _ => chr (ord (strsub "漢" 0))) (strsub "漢" 0) "ord => chr 8"} - {test_fn_both_sides (fn _ => chr (ord (strsub "カ" 0))) (strsub "カ" 0) "ord => chr 9"} + + return + | Some t' => return + + {test_fn_both_sides2 ordchr1 t'.T1 #"A" "ord => chr 1"} + {test_fn_both_sides2 ordchr2 t'.T2 #"a" "ord => chr 2"} + {test_fn_both_sides2 ordchr3 t'.T3 (strsub "á" 0) "ord => chr 3"} + {test_fn_both_sides2 ordchr4 t'.T4 (strsub "Á" 0) "ord => chr 4"} + {test_fn_both_sides2 ordchr5 t'.T5 #"1" "ord => chr 5"} + {test_fn_both_sides2 ordchr6 t'.T6 #"\n" "ord => chr 6"} + {test_fn_both_sides2 ordchr7 t'.T7 (strsub "が" 0) "ord => chr 7"} + {test_fn_both_sides2 ordchr8 t'.T8 (strsub "漢" 0) "ord => chr 8"} + {test_fn_both_sides2 ordchr9 t'.T9 (strsub "カ" 0) "ord => chr 9"} + + } /> +(* ord *) +fun ord1 _ = ord #"a" +fun ord2 _ = ord (strsub "á" 0) +fun ord3 _ = ord #"5" +fun ord4 _ = ord (strsub "が" 0) +fun ord5 _ = ord (strsub "漢" 0) +fun ord6 _ = ord (strsub "カ" 0) + +fun ordsserver _ = + return { + T1 = ord1 (), + T2 = ord2 (), + T3 = ord3 (), + T4 = ord4 (), + T5 = ord5 (), + T6 = ord6 () + } + fun test_ords () : transaction page = + t <- source None; + return + + return + | Some t' => return + {test_fn_cside ord1 t'.T1 "test ord 1"} + {test_fn_cside ord2 t'.T2 "test ord 2"} + {test_fn_cside ord3 t'.T3 "test ord 3"} + {test_fn_cside ord4 t'.T4 "test ord 4"} + {test_fn_cside ord5 t'.T5 "test ord 5"} + {test_fn_cside ord6 t'.T6 "test ord 6"} + + } /> + + + + + +and test_post () : transaction page = let - fun ord_of c _ = - ord c + fun test_post_cb r = + return + +
+		  {[r.T1]}
+		
+
+		  {[r.T2]}
+		
+
+		  {[r.T3]}
+		
+
+		  {[r.T4]}
+		
+
+		  {[r.T5]}
+		
+
+		  {[r.T6]}
+		
+
+		  {[r.T7]}
+		
+ +
+ in + t1 <- source ""; + t2 <- source "aco"; + t3 <- source "áçõ"; + t4 <- source "が"; + t5 <- source "𝌆𝌇𝌈𝌉"; + t6 <- source "Функциональное"; + t7 <- source "وظيفية"; return - {test_fn_cside (ord_of (strsub "a" 0)) (ord_of (strsub "a" 0) ()) "test ord 1"} - {test_fn_cside (ord_of (strsub "á" 0)) (ord_of (strsub "á" 0) ()) "test ord 2"} - {test_fn_cside (ord_of (strsub "5" 0)) (ord_of (strsub "5" 0) ()) "test ord 3"} - {test_fn_cside (ord_of (strsub "が" 0)) (ord_of (strsub "が" 0) ()) "test ord 4"} - {test_fn_cside (ord_of (strsub "漢" 0)) (ord_of (strsub "漢" 0) ()) "test ord 5"} - {test_fn_cside (ord_of (strsub "カ" 0)) (ord_of (strsub "カ" 0) ()) "test ord 6"} +
+ + + + + + + + +
end - + table t : { Id : int, Text : string } fun test_db () : transaction page = @@ -790,5 +1699,6 @@ fun index () : transaction page = test ord highencode test_db + test_post
diff --git a/tests/utf8.urp b/tests/utf8.urp index 25288aa8..74fcb1c2 100644 --- a/tests/utf8.urp +++ b/tests/utf8.urp @@ -1,6 +1,7 @@ database dbname=utf8 sql utf8.sql safeGet Utf8/test_db +serverOnly Utf8.generateTests $/option utf8 \ No newline at end of file -- cgit v1.2.3 From 1448db1b509db4a897a5fb11a8d35ec643d82b50 Mon Sep 17 00:00:00 2001 From: fab Date: Mon, 14 Jan 2019 23:06:29 +0000 Subject: bug fix --- src/c/urweb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index e98b5772..4742bc3e 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -2004,7 +2004,7 @@ char *uw_Basis_urlifyString(uw_context ctx, uw_Basis_string s) { if (U8_IS_SINGLE(s[curr]) && s[curr] == ' ') *p++ = '+'; else if (U8_IS_SINGLE(s[curr]) && isalnum(s[curr])) - *p++ = s[offset]; + *p++ = s[curr]; else { aux_urlifyChar(&p, c); } -- cgit v1.2.3 From 87d2eab53f8e9f81cc459429675123c9ff36f41e Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Mon, 21 Jan 2019 18:09:59 -0500 Subject: Basis.textOfBlob; try creating filecache directory if it doesn't exist --- include/urweb/urweb_cpp.h | 1 + lib/ur/basis.urs | 2 ++ src/c/urweb.c | 16 +++++++++++++++- src/cjr_print.sml | 24 +++++++++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 25f97fb3..67312015 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -262,6 +262,7 @@ uw_Basis_string uw_Basis_fileMimeType(struct uw_context *, uw_Basis_file); uw_Basis_blob uw_Basis_fileData(struct uw_context *, uw_Basis_file); uw_Basis_int uw_Basis_blobSize(struct uw_context *, uw_Basis_blob); uw_Basis_blob uw_Basis_textBlob(struct uw_context *, uw_Basis_string); +uw_Basis_string uw_Basis_textOfBlob(struct uw_context *, uw_Basis_blob); uw_Basis_string uw_Basis_postType(struct uw_context *, uw_Basis_postBody); uw_Basis_string uw_Basis_postData(struct uw_context *, uw_Basis_postBody); diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index c893e65d..be13c684 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -1019,6 +1019,8 @@ val checkMime : string -> option mimeType val returnBlob : t ::: Type -> blob -> mimeType -> transaction t val blobSize : blob -> int val textBlob : string -> blob +val textOfBlob : blob -> option string +(* Returns [Some] exactly when the blob contains no zero bytes. *) type postBody val postType : postBody -> string diff --git a/src/c/urweb.c b/src/c/urweb.c index ae2fc0a8..c8cfb0c6 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4075,6 +4075,20 @@ uw_Basis_blob uw_Basis_textBlob(uw_context ctx, uw_Basis_string s) { return b; } +uw_Basis_string uw_Basis_textOfBlob(uw_context ctx, uw_Basis_blob b) { + size_t i; + uw_Basis_string r; + + for (i = 0; i < b.size; ++i) + if (b.data[i] == 0) + return NULL; + + r = uw_malloc(ctx, b.size + 1); + memcpy(r, b.data, b.size); + r[b.size] = 0; + return r; +} + uw_Basis_blob uw_Basis_fileData(uw_context ctx, uw_Basis_file f) { (void)ctx; return f.data; @@ -5207,7 +5221,7 @@ uw_unit uw_Basis_cache_file(uw_context ctx, uw_Basis_blob contents) { fd = mkstemp(tempfile); if (fd < 0) - uw_error(ctx, FATAL, "Error creating temporary file for cache"); + uw_error(ctx, FATAL, "Error creating temporary file %s for cache", tempfile); while (written_so_far < contents.size) { ssize_t written_just_now = write(fd, contents.data + written_so_far, contents.size - written_so_far); diff --git a/src/cjr_print.sml b/src/cjr_print.sml index 31653a74..09cd9c7f 100644 --- a/src/cjr_print.sml +++ b/src/cjr_print.sml @@ -3391,6 +3391,14 @@ fun p_file env (ds, ps) = newline, string "#include ", newline, + (case Settings.getFileCache () of + NONE => box [] + | SOME _ => box [string "#include ", + newline, + string "#include ", + newline, + string "#include ", + newline]), if hasDb then box [string ("#include <" ^ #header (Settings.currentDbms ()) ^ ">"), newline] @@ -3655,7 +3663,21 @@ fun p_file env (ds, ps) = newline, string "static void uw_initializer(uw_context ctx) {", newline, - box [string "uw_begin_initializing(ctx);", + box [(case Settings.getFileCache () of + NONE => box [] + | SOME dir => box [newline, + string "struct stat st = {0};", + newline, + newline, + string "if (stat(\"", + string (Prim.toCString dir), + string "\", &st) == -1)", + newline, + box [string "mkdir(\"", + string (Prim.toCString dir), + string "\", 0700);", + newline]]), + string "uw_begin_initializing(ctx);", newline, p_list_sep newline (fn x => x) (rev (!global_initializers)), string "uw_end_initializing(ctx);", -- cgit v1.2.3 From 3f119f5c0a5f210ed442841dfed3ae98786004e9 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Sat, 23 Mar 2019 20:16:15 -0400 Subject: Supporting 'char' arguments to handlers called from client code --- include/urweb/urweb_cpp.h | 1 + src/c/urweb.c | 17 +++++++++++++++++ src/settings.sml | 2 ++ 3 files changed, 20 insertions(+) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index 18b5f583..dcf67fef 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -149,6 +149,7 @@ uw_Basis_unit uw_Basis_unurlifyUnit(struct uw_context * ctx, char **s); uw_Basis_int uw_Basis_unurlifyInt(struct uw_context *, char **); uw_Basis_float uw_Basis_unurlifyFloat(struct uw_context *, char **); uw_Basis_string uw_Basis_unurlifyString(struct uw_context *, char **); +uw_Basis_char uw_Basis_unurlifyChar(struct uw_context *, char **); uw_Basis_string uw_Basis_unurlifyString_fromClient(struct uw_context *, char **); uw_Basis_bool uw_Basis_unurlifyBool(struct uw_context *, char **); uw_Basis_time uw_Basis_unurlifyTime(struct uw_context *, char **); diff --git a/src/c/urweb.c b/src/c/urweb.c index 58f7884d..4d9e8630 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -2267,6 +2267,23 @@ uw_Basis_string uw_Basis_unurlifyString(uw_context ctx, char **s) { return r; } +uw_Basis_char uw_Basis_unurlifyChar(uw_context ctx, char **s) { + char *new_s = uw_unurlify_advance(*s); + char *r; + int len; + + len = strlen(*s); + uw_check_heap(ctx, len + 1); + + r = ctx->heap.front; + ctx->heap.front = uw_unurlifyString_to(0, ctx, ctx->heap.front, *s); + *s = new_s; + if (strlen(r) == 1) + return r[0]; + else + uw_error(ctx, FATAL, "Unurlified character is multiple characters long"); +} + uw_Basis_unit uw_Basis_unurlifyUnit(uw_context ctx, char **s) { (void)ctx; *s = uw_unurlify_advance(*s); diff --git a/src/settings.sml b/src/settings.sml index abb26f72..edc03d4c 100644 --- a/src/settings.sml +++ b/src/settings.sml @@ -117,6 +117,7 @@ fun basis x = S.addList (S.empty, map (fn x : string => ("Basis", x)) x) val clientToServerBase = basis ["int", "float", "string", + "char", "time", "file", "unit", @@ -277,6 +278,7 @@ val jsFuncsBase = basisM [("alert", "alert"), ("urlifyFloat", "ts"), ("urlifyTime", "ts"), ("urlifyString", "uf"), + ("urlifyChar", "uf"), ("urlifyBool", "ub"), ("recv", "rv"), ("strcat", "cat"), -- cgit v1.2.3 From 94ea84354715c4a2bb30cd4aaeaaba506358d1d6 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Fri, 31 May 2019 09:58:37 -0400 Subject: Filecache support for MySQL --- src/c/urweb.c | 5 ++--- src/cjr_print.sml | 2 +- src/filecache.sml | 5 ++++- src/mysql.sml | 3 ++- src/postgres.sml | 3 ++- src/settings.sig | 8 +++++--- src/settings.sml | 2 +- 7 files changed, 17 insertions(+), 11 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 4d9e8630..8a7c439a 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -5327,9 +5327,8 @@ uw_Basis_blob uw_Basis_check_filecache(uw_context ctx, uw_Basis_string hash) { // Hashes come formatted for printing by Postgres, which means they start with // two extra characters. Let's remove them. - if (!hash[0] || !hash[1]) - uw_error(ctx, FATAL, "Hash to check against file cache came in not in Postgres format: %s", hash); - hash += 2; + if (hash[0] == '\\' && hash[1] == 'x') + hash += 2; if (!dir) uw_error(ctx, FATAL, "Checking file cache when no directory is set"); diff --git a/src/cjr_print.sml b/src/cjr_print.sml index 1e948943..4aa8d51e 100644 --- a/src/cjr_print.sml +++ b/src/cjr_print.sml @@ -3827,7 +3827,7 @@ fun p_sql env (ds, _) = | SOME _ => case #supportsSHA512 (Settings.currentDbms ()) of NONE => (ErrorMsg.error "Using file cache with database that doesn't support SHA512"; []) - | SOME line => [string line, newline, newline]) + | SOME r => [string (#InitializeDb r), newline, newline]) @ string (#sqlPrefix (Settings.currentDbms ())) :: pps) end diff --git a/src/filecache.sml b/src/filecache.sml index e2291c10..a0da4b05 100644 --- a/src/filecache.sml +++ b/src/filecache.sml @@ -81,7 +81,10 @@ fun instrument file = fun wrapCol (name, t) = case #1 t of TFfi ("Basis", "blob") => - "DIGEST(" ^ name ^ ", 'sha512')" + (case #supportsSHA512 (Settings.currentDbms ()) of + NONE => (ErrorMsg.error "DBMS doesn't support SHA512."; + "ERROR") + | SOME r => #GenerateHash r name) | TOption t' => wrapCol (name, t') | _ => name diff --git a/src/mysql.sml b/src/mysql.sml index 768c5441..a826f3ef 100644 --- a/src/mysql.sml +++ b/src/mysql.sml @@ -1610,6 +1610,7 @@ val () = addDbms {name = "mysql", nestedRelops = false, windowFunctions = false, supportsIsDistinctFrom = true, - supportsSHA512 = NONE} + supportsSHA512 = SOME {InitializeDb = "", + GenerateHash = fn name => "SHA2(" ^ name ^ ", 512)"}} end diff --git a/src/postgres.sml b/src/postgres.sml index a33a1de4..2b0a710d 100644 --- a/src/postgres.sml +++ b/src/postgres.sml @@ -1154,7 +1154,8 @@ val () = addDbms {name = "postgres", nestedRelops = true, windowFunctions = true, supportsIsDistinctFrom = true, - supportsSHA512 = SOME "CREATE EXTENSION pgcrypto;"} + supportsSHA512 = SOME {InitializeDb = "CREATE EXTENSION pgcrypto;", + GenerateHash = fn name => "DIGEST(" ^ name ^ ", 'sha512')"}} val () = setDbms "postgres" diff --git a/src/settings.sig b/src/settings.sig index 97d56b45..7ca7a0cd 100644 --- a/src/settings.sig +++ b/src/settings.sig @@ -222,9 +222,11 @@ signature SETTINGS = sig nestedRelops : bool, windowFunctions : bool, supportsIsDistinctFrom : bool, - supportsSHA512 : string option (* If supported, give the SQL code to - * enable the feature in a particular - * database. *) + supportsSHA512 : {InitializeDb : string, + GenerateHash : string -> string} option + (* If supported, give the SQL code to + * enable the feature in a particular + * database and to compute a hash of a value. *) } val addDbms : dbms -> unit diff --git a/src/settings.sml b/src/settings.sml index ac403027..a31f5cda 100644 --- a/src/settings.sml +++ b/src/settings.sml @@ -652,7 +652,7 @@ type dbms = { nestedRelops : bool, windowFunctions: bool, supportsIsDistinctFrom : bool, - supportsSHA512 : string option + supportsSHA512 : {InitializeDb : string, GenerateHash : string -> string} option } val dbmses = ref ([] : dbms list) -- cgit v1.2.3 From ea30ab5c6e5ff7cfa6576f8ef9b8f19876247279 Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Thu, 4 Jul 2019 13:56:28 -0400 Subject: Make uw_set_error_message actually act printf-y --- src/c/urweb.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 8a7c439a..b820354f 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -902,9 +902,12 @@ char *uw_error_message(uw_context ctx) { return ctx->error_message; } -void uw_set_error_message(uw_context ctx, const char *msg) { - strncpy(ctx->error_message, msg, sizeof(ctx->error_message)); - ctx->error_message[sizeof(ctx->error_message)-1] = 0; +void uw_set_error_message(uw_context ctx, const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); + + vsnprintf(ctx->error_message, ERROR_BUF_LEN, fmt, ap); + ctx->error_message[ERROR_BUF_LEN-1] = 0; } static input *INP(uw_context ctx) { -- cgit v1.2.3 From d7e10798f1905161e5790444e604f439281d4220 Mon Sep 17 00:00:00 2001 From: Oisín Mac Fhearaí Date: Sun, 11 Aug 2019 05:04:43 +0100 Subject: * When htmlifying characters, don't use numeric escapes if they're printable -- instead, try to convert them to UTF-8. * Add libicuio to linked C libraries --- src/c/Makefile.am | 2 +- src/c/urweb.c | 19 ++++++++++++++++--- src/compiler.sml | 8 ++++++-- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/Makefile.am b/src/c/Makefile.am index 95582793..ff4b6eaf 100644 --- a/src/c/Makefile.am +++ b/src/c/Makefile.am @@ -11,7 +11,7 @@ AM_CFLAGS = -Wall -Wunused-parameter -Werror -Wno-format-security -Wno-deprecate liburweb_la_LDFLAGS = $(AM_LDFLAGS) $(OPENSSL_LDFLAGS) \ -export-symbols-regex '^(client_pruner|pthread_create_big|strcmp_nullsafe|uw_.*)' \ -version-info 1:0:0 -liburweb_la_LIBADD = $(PTHREAD_LIBS) -lm $(OPENSSL_LIBS) $(ICU_LIBS) -licui18n -licuuc -licudata +liburweb_la_LIBADD = $(PTHREAD_LIBS) -lm $(OPENSSL_LIBS) $(ICU_LIBS) -licui18n -licuuc -licudata -licuio liburweb_http_la_LIBADD = liburweb.la liburweb_http_la_LDFLAGS = -export-symbols-regex '^(main|uw_.*)' \ -version-info 1:0:0 diff --git a/src/c/urweb.c b/src/c/urweb.c index b820354f..dad15568 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -20,7 +20,6 @@ #include -#include #include #include "types.h" @@ -2347,7 +2346,21 @@ uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { int len; uw_check(ctx, INTS_MAX+3); - len = sprintf(ctx->page.front, "&#%u;", n); + + if(uw_Basis_isprint(ctx, ch)) { + + UChar32 ins[1] = { ch }; + char buf[5]; + int32_t len_written = 0; + UErrorCode err = U_ZERO_ERROR; + + u_strToUTF8(buf, 5, &len_written, ins, 1, &err); + sprintf(ctx->page.front, "%s", buf); + // printf("buf: %s, hex: %x, len_written: %d, err: %s\n", buf, ch, len_written, u_errorName(err)); + len = len_written; + } else { + len = sprintf(ctx->page.front, "&#%u;", n); + } ctx->page.front += len; return uw_unit_v; @@ -2459,7 +2472,7 @@ uw_unit uw_Basis_htmlifyString_w(uw_context ctx, uw_Basis_string s) { else { uw_Basis_htmlifySpecialChar_w(ctx, c1); } - } + } return uw_unit_v; } diff --git a/src/compiler.sml b/src/compiler.sml index 0aba3a40..c00fe807 100644 --- a/src/compiler.sml +++ b/src/compiler.sml @@ -1610,9 +1610,13 @@ fun compileC {cname, oname, ename, libs, profile, debug, linker, link = link'} = val proto = Settings.currentProtocol () val lib = if Settings.getBootLinking () then - !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a " ^ !Settings.configIcuLibs ^ " -licui18n -licuuc -licudata" + !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ + !Settings.configLib ^ "/liburweb.a " ^ + !Settings.configIcuLibs ^ " -licui18n -licuuc -licudata -licuio" else if Settings.getStaticLinking () then - " -static " ^ !Settings.configLib ^ "/" ^ #linkStatic proto ^ " " ^ !Settings.configLib ^ "/liburweb.a " ^ !Settings.configIcuLibs ^ " -licui18n -licuuc -licudata" + " -static " ^ !Settings.configLib ^ "/" ^ #linkStatic + proto ^ " " ^ !Settings.configLib ^ "/liburweb.a " ^ + !Settings.configIcuLibs ^ " -licui18n -licuuc -licudata -licuio" else "-L" ^ !Settings.configLib ^ " " ^ #linkDynamic proto ^ " -lurweb" -- cgit v1.2.3 From 71e1eb7be7ebd566a19be3cab381f813d9c2e4fc Mon Sep 17 00:00:00 2001 From: Oisín Mac Fhearaí Date: Sun, 11 Aug 2019 06:04:35 +0100 Subject: Add missing include --- src/c/urweb.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index dad15568..509ba10d 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -21,6 +21,7 @@ #include #include +#include #include "types.h" -- cgit v1.2.3 From 35eaf23643fcd2eb4376f07a490c959737179eef Mon Sep 17 00:00:00 2001 From: Oisín Mac Fhearaí Date: Sun, 11 Aug 2019 06:14:10 +0100 Subject: Try to avoid a pointer conversion error --- src/c/urweb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 509ba10d..a76f0004 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -20,8 +20,8 @@ #include -#include #include +#include #include "types.h" @@ -2350,7 +2350,7 @@ uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { if(uw_Basis_isprint(ctx, ch)) { - UChar32 ins[1] = { ch }; + const UChar ins[1] = { ch }; char buf[5]; int32_t len_written = 0; UErrorCode err = U_ZERO_ERROR; -- cgit v1.2.3 From 5e2ebc973f19fe8e5fdbe20e102e445329b528b0 Mon Sep 17 00:00:00 2001 From: Oisín Mac Fhearaí Date: Wed, 28 Aug 2019 01:56:53 +0100 Subject: Minor cleanup -- handle the case where we couldn't successfully generate a UTF8 codepoint by outputting a HTML escape (the default behaviour before for all multi-byte characters). --- src/c/urweb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index a76f0004..62561828 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -20,6 +20,7 @@ #include +#include #include #include @@ -2344,7 +2345,7 @@ char *uw_Basis_htmlifySpecialChar(uw_context ctx, uw_Basis_char ch) { uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { unsigned int n = ch; - int len; + int len = 0; uw_check(ctx, INTS_MAX+3); @@ -2359,7 +2360,10 @@ uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { sprintf(ctx->page.front, "%s", buf); // printf("buf: %s, hex: %x, len_written: %d, err: %s\n", buf, ch, len_written, u_errorName(err)); len = len_written; - } else { + } + + // either it's a non-printable character, or we failed to convert to UTF-8 + if(len == 0) { len = sprintf(ctx->page.front, "&#%u;", n); } ctx->page.front += len; -- cgit v1.2.3 From 0490176b675eb3ea36cd51fa5d1fd41a3126c10c Mon Sep 17 00:00:00 2001 From: Oisín Mac Fhearaí Date: Thu, 29 Aug 2019 21:39:53 +0100 Subject: PR suggestions (with thanks to @fabriceleal). --- src/c/urweb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 62561828..af929269 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -2351,14 +2351,10 @@ uw_unit uw_Basis_htmlifySpecialChar_w(uw_context ctx, uw_Basis_char ch) { if(uw_Basis_isprint(ctx, ch)) { - const UChar ins[1] = { ch }; - char buf[5]; int32_t len_written = 0; UErrorCode err = U_ZERO_ERROR; - u_strToUTF8(buf, 5, &len_written, ins, 1, &err); - sprintf(ctx->page.front, "%s", buf); - // printf("buf: %s, hex: %x, len_written: %d, err: %s\n", buf, ch, len_written, u_errorName(err)); + u_strToUTF8(ctx->page.front, 5, &len_written, (const UChar*)&ch, 1, &err); len = len_written; } -- cgit v1.2.3 From 8728f397bee2b567611dcd7a7c359c7e92159c1c Mon Sep 17 00:00:00 2001 From: Adam Chlipala Date: Wed, 25 Sep 2019 19:54:59 -0400 Subject: Unicode escapes in JSON --- include/urweb/urweb_cpp.h | 1 + lib/ur/basis.urs | 1 + lib/ur/json.ur | 29 +++++++++++++++++++++++++++++ src/c/urweb.c | 12 ++++++++++++ 4 files changed, 43 insertions(+) (limited to 'src/c/urweb.c') diff --git a/include/urweb/urweb_cpp.h b/include/urweb/urweb_cpp.h index dcf67fef..e4ad6e61 100644 --- a/include/urweb/urweb_cpp.h +++ b/include/urweb/urweb_cpp.h @@ -166,6 +166,7 @@ uw_Basis_string uw_Basis_strchr(struct uw_context *, const char *, uw_Basis_char uw_Basis_int uw_Basis_strcspn(struct uw_context *, const char *, const char *); uw_Basis_string uw_Basis_substring(struct uw_context *, const char *, uw_Basis_int, uw_Basis_int); uw_Basis_string uw_Basis_str1(struct uw_context *, uw_Basis_char); +uw_Basis_string uw_Basis_ofUnicode(struct uw_context *, uw_Basis_int); uw_Basis_string uw_strdup(struct uw_context *, const char *); uw_Basis_string uw_maybe_strdup(struct uw_context *, const char *); diff --git a/lib/ur/basis.urs b/lib/ur/basis.urs index 2a98bf6f..d29bf6e6 100644 --- a/lib/ur/basis.urs +++ b/lib/ur/basis.urs @@ -95,6 +95,7 @@ val strsindex : string -> string -> option int val strcspn : string -> string -> int val substring : string -> int -> int -> string val str1 : char -> string +val ofUnicode : int -> string class show val show : t ::: Type -> show t -> t -> string diff --git a/lib/ur/json.ur b/lib/ur/json.ur index 05406739..70f0c797 100644 --- a/lib/ur/json.ur +++ b/lib/ur/json.ur @@ -59,6 +59,17 @@ fun escape s = "\"" ^ esc s end +fun unhex ch = + if Char.isDigit ch then + Char.toInt ch - Char.toInt #"0" + else if Char.isXdigit ch then + if Char.isUpper ch then + 10 + (Char.toInt ch - Char.toInt #"A") + else + 10 + (Char.toInt ch - Char.toInt #"a") + else + error Invalid hexadecimal digit "{[ch]}" + fun unescape s = let val len = String.length s @@ -75,6 +86,11 @@ fun unescape s = | #"\\" => if i+1 >= len then error JSON unescape: Bad escape sequence: {[s]} + else if String.sub s (i + 1) = #"u" then + if i+5 >= len then + error JSON unescape: Bad escape sequence: {[s]} + else + findEnd (i+6) else findEnd (i+2) | _ => findEnd (i+1) @@ -93,6 +109,19 @@ fun unescape s = #"\\" => if i+1 >= len then error JSON unescape: Bad escape sequence: {[s]} + else if String.sub s (i+1) = #"u" then + if i+5 >= len then + error JSON unescape: Unicode ends early + else + let + val n = + unhex (String.sub s (i+2)) * (256*16) + + unhex (String.sub s (i+3)) * 256 + + unhex (String.sub s (i+4)) * 16 + + unhex (String.sub s (i+5)) + in + ofUnicode n ^ unesc (i+6) + end else (case String.sub s (i+1) of #"n" => "\n" diff --git a/src/c/urweb.c b/src/c/urweb.c index af929269..8c445f39 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -2724,6 +2724,18 @@ uw_Basis_string uw_Basis_str1(uw_context ctx, uw_Basis_char ch) { return r; } +uw_Basis_string uw_Basis_ofUnicode(uw_context ctx, uw_Basis_int n) { + UChar buf16[] = {n}; + uw_Basis_string out = uw_malloc(ctx, 3); + int32_t outLen; + UErrorCode pErrorCode = 0; + + if (u_strToUTF8(out, 3, &outLen, buf16, 1, &pErrorCode) == NULL || outLen == 0) + uw_error(ctx, FATAL, "Bad Unicode string to unescape (error %s)", u_errorName(pErrorCode)); + + return out; +} + uw_Basis_string uw_strdup(uw_context ctx, uw_Basis_string s1) { int len = strlen(s1) + 1; char *s; -- cgit v1.2.3 From ce9b6ef5ec667d474f6e6644046b27905441660a Mon Sep 17 00:00:00 2001 From: Simon Van Casteren Date: Mon, 4 Nov 2019 14:50:56 +0100 Subject: Fix for #181: unurlify x-www-form-urlencoded without custom serialization using period --- src/c/urweb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index 8c445f39..a01b4aae 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -4941,13 +4941,13 @@ uw_Basis_postField *uw_Basis_firstFormField(uw_context ctx, uw_Basis_string s) { f = uw_malloc(ctx, sizeof(uw_Basis_postField)); unurl = s; - f->name = uw_Basis_unurlifyString(ctx, &unurl); + f->name = uw_Basis_unurlifyString_fromClient(ctx, &unurl); s = strchr(s, 0); if (!s) uw_error(ctx, FATAL, "firstFormField: Missing null terminator"); ++s; unurl = s; - f->value = uw_Basis_unurlifyString(ctx, &unurl); + f->value = uw_Basis_unurlifyString_fromClient(ctx, &unurl); s = strchr(s, 0); if (!s) uw_error(ctx, FATAL, "firstFormField: Missing null terminator"); -- cgit v1.2.3 From 10eb72ad6a4fc0426305e3bd85893f76cb772545 Mon Sep 17 00:00:00 2001 From: Simon Van Casteren Date: Tue, 17 Dec 2019 13:35:20 +0100 Subject: Remove sscanf from blob processing --- src/c/urweb.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/c/urweb.c') diff --git a/src/c/urweb.c b/src/c/urweb.c index a01b4aae..8ffe7dd3 100644 --- a/src/c/urweb.c +++ b/src/c/urweb.c @@ -3421,10 +3421,19 @@ uw_Basis_blob uw_Basis_stringToBlob_error(uw_context ctx, uw_Basis_string s, siz s += 2; while (*s) { + char a = s[0]; + s += 1; + char b; + if (*s){ + b = s[0]; + } else { + b = 0; + } int n; - sscanf(s, "%02x", &n); + char buf[3] = {a, b, 0}; + n = strtol(buf, NULL, 16); *r++ = n; - s += 2; + s += 1; } } else { while (*s) { -- cgit v1.2.3