PageRenderTime 89ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/src/racket/src/string.c

http://github.com/dyoo/racket
C | 5990 lines | 4895 code | 748 blank | 347 comment | 1095 complexity | b7e0ccf9aaca8c8d36abccaac11d9421 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. Racket
  3. Copyright (c) 2004-2013 PLT Design Inc.
  4. Copyright (c) 1995-2001 Matthew Flatt
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public
  7. License as published by the Free Software Foundation; either
  8. version 2 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Library General Public License for more details.
  13. You should have received a copy of the GNU Library General Public
  14. License along with this library; if not, write to the Free
  15. Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  16. Boston, MA 02110-1301 USA.
  17. libscheme
  18. Copyright (c) 1994 Brent Benson
  19. All rights reserved.
  20. */
  21. #include "schpriv.h"
  22. #include "schvers.h"
  23. #include <string.h>
  24. #include <ctype.h>
  25. #ifndef DONT_USE_LOCALE
  26. # include <locale.h>
  27. # ifdef MZ_NO_ICONV
  28. # define USE_ICONV_DLL
  29. # endif
  30. # ifndef USE_ICONV_DLL
  31. # include <iconv.h>
  32. # include <langinfo.h>
  33. # endif
  34. # include <wchar.h>
  35. # include <wctype.h>
  36. # include <errno.h>
  37. # ifdef MACOS_UNICODE_SUPPORT
  38. # include <CoreFoundation/CFString.h>
  39. # include <CoreFoundation/CFLocale.h>
  40. # endif
  41. # ifdef WINDOWS_UNICODE_SUPPORT
  42. # include <windows.h>
  43. # endif
  44. #endif
  45. #ifndef SCHEME_PLATFORM_LIBRARY_SUBPATH
  46. # include "schsys.h"
  47. #endif
  48. #include "schustr.inc"
  49. #ifdef USE_ICONV_DLL
  50. typedef intptr_t iconv_t;
  51. typedef int *(*errno_proc_t)();
  52. typedef size_t (*iconv_proc_t)(iconv_t cd,
  53. char **inbuf, size_t *inbytesleft,
  54. char **outbuf, size_t *outbytesleft);
  55. typedef iconv_t (*iconv_open_proc_t)(const char *tocode, const char *fromcode);
  56. typedef void (*iconv_close_proc_t)(iconv_t cd);
  57. typedef char *(*locale_charset_proc_t)();
  58. static errno_proc_t iconv_errno;
  59. static iconv_proc_t iconv;
  60. static iconv_open_proc_t iconv_open;
  61. static iconv_close_proc_t iconv_close;
  62. static locale_charset_proc_t locale_charset; /* Not used, currently */
  63. #define mzCHK_PROC(x) x
  64. static int get_iconv_errno(void)
  65. {
  66. int *a;
  67. a = iconv_errno();
  68. return *a;
  69. }
  70. # undef HAVE_CODESET
  71. # define HAVE_CODESET 1
  72. # define CODESET 0
  73. # define ICONV_errno get_iconv_errno()
  74. static int iconv_ready = 0;
  75. static void init_iconv()
  76. {
  77. # ifdef MZ_NO_ICONV
  78. # else
  79. HMODULE m;
  80. m = LoadLibraryW(scheme_get_dll_path(L"iconv.dll"));
  81. if (!m)
  82. m = LoadLibraryW(scheme_get_dll_path(L"libiconv.dll"));
  83. if (!m)
  84. m = LoadLibraryW(scheme_get_dll_path(L"libiconv-2.dll"));
  85. if (!m)
  86. m = LoadLibrary("iconv.dll");
  87. if (!m)
  88. m = LoadLibrary("libiconv.dll");
  89. if (!m)
  90. m = LoadLibrary("libiconv-2.dll");
  91. if (m) {
  92. iconv = (iconv_proc_t)GetProcAddress(m, "libiconv");
  93. iconv_open = (iconv_open_proc_t)GetProcAddress(m, "libiconv_open");
  94. iconv_close = (iconv_close_proc_t)GetProcAddress(m, "libiconv_close");
  95. locale_charset = (locale_charset_proc_t)GetProcAddress(m, "locale_charset");
  96. /* Make sure we have all of them or none: */
  97. if (!iconv || !iconv_open || !iconv_close) {
  98. iconv = NULL;
  99. iconv_open = NULL;
  100. iconv_close = NULL;
  101. }
  102. }
  103. if (iconv) {
  104. iconv_errno = (errno_proc_t)GetProcAddress(m, "_errno");
  105. if (!iconv_errno) {
  106. /* The iconv.dll distributed with Racket links to msvcrt.dll.
  107. It's a slighly dangerous assumption that whatever iconv we
  108. found also uses msvcrt.dll. */
  109. m = LoadLibrary("msvcrt.dll");
  110. if (m) {
  111. iconv_errno = (errno_proc_t)GetProcAddress(m, "_errno");
  112. if (!iconv_errno) {
  113. iconv = NULL;
  114. iconv_open = NULL;
  115. iconv_close = NULL;
  116. }
  117. }
  118. }
  119. }
  120. # endif
  121. iconv_ready = 1;
  122. }
  123. #else
  124. # define ICONV_errno errno
  125. # define iconv_ready 1
  126. # define mzCHK_PROC(x) 1
  127. static void init_iconv() { }
  128. #endif
  129. #ifdef MACOS_UNICODE_SUPPORT
  130. # define mzLOCALE_IS_UTF_8(s) (!s || !(*s))
  131. #endif
  132. #ifdef WINDOWS_UNICODE_SUPPORT
  133. # define mzLOCALE_IS_UTF_8(s) (!s || !(*s))
  134. #endif
  135. #ifndef mzLOCALE_IS_UTF_8
  136. # define mzLOCALE_IS_UTF_8(s) !mzCHK_PROC(iconv_open)
  137. #endif
  138. #define mzICONV_KIND 0
  139. #define mzUTF8_KIND 1
  140. #define mzUTF8_TO_UTF16_KIND 2
  141. #define mzUTF16_TO_UTF8_KIND 3
  142. typedef struct Scheme_Converter {
  143. Scheme_Object so;
  144. short closed;
  145. short kind;
  146. iconv_t cd;
  147. int permissive;
  148. Scheme_Custodian_Reference *mref;
  149. } Scheme_Converter;
  150. /* locals */
  151. /* These two locale variables are only valid when reset_locale()
  152. is called after continuation marks (and hence parameterization)
  153. may have changed. Similarly, setlocale() is only up-to-date
  154. when reset_locale() has been called. */
  155. THREAD_LOCAL_DECL(static int locale_on);
  156. THREAD_LOCAL_DECL(static void *current_locale_name_ptr);
  157. static void reset_locale(void);
  158. #define current_locale_name ((const mzchar *)current_locale_name_ptr)
  159. #ifdef USE_ICONV_DLL
  160. static char *nl_langinfo(int which)
  161. {
  162. int i;
  163. reset_locale();
  164. if (!current_locale_name)
  165. current_locale_name_ptr = "\0\0\0\0";
  166. if ((current_locale_name[0] == 'C')
  167. && !current_locale_name[1])
  168. return "US-ASCII";
  169. for (i = 0; current_locale_name[i]; i++) {
  170. if (current_locale_name[i] == '.') {
  171. if (current_locale_name[i + 1]) {
  172. int len, j = 0;
  173. char *enc;
  174. i++;
  175. len = scheme_char_strlen(current_locale_name) - i;
  176. enc = (char *)scheme_malloc_atomic(len + 1);
  177. while (current_locale_name[i]) {
  178. if (current_locale_name[i] > 127)
  179. return "UTF-8";
  180. enc[j++] = current_locale_name[i++];
  181. }
  182. enc[j] = 0;
  183. return enc;
  184. }
  185. }
  186. }
  187. return "UTF-8";
  188. }
  189. #endif
  190. #ifdef DONT_USE_LOCALE
  191. # define mz_iconv_nl_langinfo() ""
  192. #else
  193. static char *mz_iconv_nl_langinfo(){
  194. char *s;
  195. # if HAVE_CODESET
  196. s = nl_langinfo(CODESET);
  197. # else
  198. s = NULL;
  199. # endif
  200. if (!s)
  201. return "";
  202. else
  203. return s;
  204. }
  205. #endif
  206. static Scheme_Object *make_string (int argc, Scheme_Object *argv[]);
  207. static Scheme_Object *string (int argc, Scheme_Object *argv[]);
  208. static Scheme_Object *string_p (int argc, Scheme_Object *argv[]);
  209. static Scheme_Object *string_length (int argc, Scheme_Object *argv[]);
  210. static Scheme_Object *string_eq (int argc, Scheme_Object *argv[]);
  211. static Scheme_Object *string_locale_eq (int argc, Scheme_Object *argv[]);
  212. static Scheme_Object *string_ci_eq (int argc, Scheme_Object *argv[]);
  213. static Scheme_Object *string_locale_ci_eq (int argc, Scheme_Object *argv[]);
  214. static Scheme_Object *string_lt (int argc, Scheme_Object *argv[]);
  215. static Scheme_Object *string_locale_lt (int argc, Scheme_Object *argv[]);
  216. static Scheme_Object *string_gt (int argc, Scheme_Object *argv[]);
  217. static Scheme_Object *string_locale_gt (int argc, Scheme_Object *argv[]);
  218. static Scheme_Object *string_lt_eq (int argc, Scheme_Object *argv[]);
  219. static Scheme_Object *string_gt_eq (int argc, Scheme_Object *argv[]);
  220. static Scheme_Object *string_ci_lt (int argc, Scheme_Object *argv[]);
  221. static Scheme_Object *string_locale_ci_lt (int argc, Scheme_Object *argv[]);
  222. static Scheme_Object *string_ci_gt (int argc, Scheme_Object *argv[]);
  223. static Scheme_Object *string_locale_ci_gt (int argc, Scheme_Object *argv[]);
  224. static Scheme_Object *string_ci_lt_eq (int argc, Scheme_Object *argv[]);
  225. static Scheme_Object *string_ci_gt_eq (int argc, Scheme_Object *argv[]);
  226. static Scheme_Object *string_upcase (int argc, Scheme_Object *argv[]);
  227. static Scheme_Object *string_downcase (int argc, Scheme_Object *argv[]);
  228. static Scheme_Object *string_titlecase (int argc, Scheme_Object *argv[]);
  229. static Scheme_Object *string_foldcase (int argc, Scheme_Object *argv[]);
  230. static Scheme_Object *string_locale_upcase (int argc, Scheme_Object *argv[]);
  231. static Scheme_Object *string_locale_downcase (int argc, Scheme_Object *argv[]);
  232. static Scheme_Object *substring (int argc, Scheme_Object *argv[]);
  233. static Scheme_Object *string_append (int argc, Scheme_Object *argv[]);
  234. static Scheme_Object *string_to_list (int argc, Scheme_Object *argv[]);
  235. static Scheme_Object *list_to_string (int argc, Scheme_Object *argv[]);
  236. static Scheme_Object *string_copy (int argc, Scheme_Object *argv[]);
  237. static Scheme_Object *string_copy_bang (int argc, Scheme_Object *argv[]);
  238. static Scheme_Object *string_fill (int argc, Scheme_Object *argv[]);
  239. static Scheme_Object *string_to_immutable (int argc, Scheme_Object *argv[]);
  240. static Scheme_Object *string_normalize_c (int argc, Scheme_Object *argv[]);
  241. static Scheme_Object *string_normalize_kc (int argc, Scheme_Object *argv[]);
  242. static Scheme_Object *string_normalize_d (int argc, Scheme_Object *argv[]);
  243. static Scheme_Object *string_normalize_kd (int argc, Scheme_Object *argv[]);
  244. static Scheme_Object *make_shared_byte_string (int argc, Scheme_Object *argv[]);
  245. static Scheme_Object *shared_byte_string (int argc, Scheme_Object *argv[]);
  246. static Scheme_Object *make_byte_string (int argc, Scheme_Object *argv[]);
  247. static Scheme_Object *byte_string (int argc, Scheme_Object *argv[]);
  248. static Scheme_Object *byte_p (int argc, Scheme_Object *argv[]);
  249. static Scheme_Object *byte_string_p (int argc, Scheme_Object *argv[]);
  250. static Scheme_Object *byte_string_length (int argc, Scheme_Object *argv[]);
  251. static Scheme_Object *byte_string_eq (int argc, Scheme_Object *argv[]);
  252. static Scheme_Object *byte_string_lt (int argc, Scheme_Object *argv[]);
  253. static Scheme_Object *byte_string_gt (int argc, Scheme_Object *argv[]);
  254. static Scheme_Object *byte_substring (int argc, Scheme_Object *argv[]);
  255. static Scheme_Object *byte_string_append (int argc, Scheme_Object *argv[]);
  256. static Scheme_Object *byte_string_to_list (int argc, Scheme_Object *argv[]);
  257. static Scheme_Object *list_to_byte_string (int argc, Scheme_Object *argv[]);
  258. static Scheme_Object *byte_string_copy (int argc, Scheme_Object *argv[]);
  259. static Scheme_Object *byte_string_copy_bang (int argc, Scheme_Object *argv[]);
  260. static Scheme_Object *byte_string_fill (int argc, Scheme_Object *argv[]);
  261. static Scheme_Object *byte_string_to_immutable (int argc, Scheme_Object *argv[]);
  262. static Scheme_Object *byte_string_utf8_index (int argc, Scheme_Object *argv[]);
  263. static Scheme_Object *byte_string_utf8_ref (int argc, Scheme_Object *argv[]);
  264. static Scheme_Object *byte_string_utf8_length (int argc, Scheme_Object *argv[]);
  265. static Scheme_Object *byte_string_to_char_string (int argc, Scheme_Object *argv[]);
  266. static Scheme_Object *byte_string_to_char_string_locale (int argc, Scheme_Object *argv[]);
  267. static Scheme_Object *byte_string_to_char_string_latin1 (int argc, Scheme_Object *argv[]);
  268. static Scheme_Object *char_string_to_byte_string (int argc, Scheme_Object *argv[]);
  269. static Scheme_Object *char_string_to_byte_string_locale (int argc, Scheme_Object *argv[]);
  270. static Scheme_Object *char_string_to_byte_string_latin1 (int argc, Scheme_Object *argv[]);
  271. static Scheme_Object *char_string_utf8_length (int argc, Scheme_Object *argv[]);
  272. static Scheme_Object *version(int argc, Scheme_Object *argv[]);
  273. static Scheme_Object *format(int argc, Scheme_Object *argv[]);
  274. static Scheme_Object *sch_printf(int argc, Scheme_Object *argv[]);
  275. static Scheme_Object *sch_eprintf(int argc, Scheme_Object *argv[]);
  276. static Scheme_Object *sch_fprintf(int argc, Scheme_Object *argv[]);
  277. static Scheme_Object *banner(int argc, Scheme_Object *argv[]);
  278. static Scheme_Object *env_p(int argc, Scheme_Object *argv[]);
  279. static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[]);
  280. static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[]);
  281. static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[]);
  282. static Scheme_Object *env_copy(int argc, Scheme_Object *argv[]);
  283. static Scheme_Object *env_make(int argc, Scheme_Object *argv[]);
  284. static Scheme_Object *current_environment_variables(int argc, Scheme_Object *argv[]);
  285. static Scheme_Object *system_type(int argc, Scheme_Object *argv[]);
  286. static Scheme_Object *system_library_subpath(int argc, Scheme_Object *argv[]);
  287. static Scheme_Object *cmdline_args(int argc, Scheme_Object *argv[]);
  288. static Scheme_Object *current_locale(int argc, Scheme_Object *argv[]);
  289. static Scheme_Object *locale_string_encoding(int argc, Scheme_Object *argv[]);
  290. static Scheme_Object *system_language_country(int argc, Scheme_Object *argv[]);
  291. static Scheme_Object *byte_string_open_converter(int argc, Scheme_Object *argv[]);
  292. static Scheme_Object *byte_string_close_converter(int argc, Scheme_Object *argv[]);
  293. static Scheme_Object *byte_string_convert(int argc, Scheme_Object *argv[]);
  294. static Scheme_Object *byte_string_convert_end(int argc, Scheme_Object *argv[]);
  295. static Scheme_Object *byte_converter_p(int argc, Scheme_Object *argv[]);
  296. #ifdef MZ_PRECISE_GC
  297. static void register_traversers(void);
  298. #endif
  299. static int mz_char_strcmp(const char *who, const mzchar *str1, intptr_t l1, const mzchar *str2, intptr_t l2, int locale, int size_shortcut);
  300. static int mz_char_strcmp_ci(const char *who, const mzchar *str1, intptr_t l1, const mzchar *str2, intptr_t l2, int locale, int size_shortcut);
  301. static int mz_strcmp(const char *who, unsigned char *str1, intptr_t l1, unsigned char *str2, intptr_t l2);
  302. XFORM_NONGCING static intptr_t utf8_decode_x(const unsigned char *s, intptr_t start, intptr_t end,
  303. unsigned int *us, intptr_t dstart, intptr_t dend,
  304. intptr_t *ipos, intptr_t *jpos,
  305. char compact, char utf16,
  306. int *state, int might_continue, int permissive);
  307. XFORM_NONGCING static intptr_t utf8_encode_x(const unsigned int *us, intptr_t start, intptr_t end,
  308. unsigned char *s, intptr_t dstart, intptr_t dend,
  309. intptr_t *_ipos, intptr_t *_opos, char utf16);
  310. static char *string_to_from_locale(int to_bytes,
  311. char *in, intptr_t delta, intptr_t len,
  312. intptr_t *olen, int perm,
  313. int *no_cvt);
  314. #define portable_isspace(x) (((x) < 128) && isspace(x))
  315. ROSYM static Scheme_Object *sys_symbol;
  316. ROSYM static Scheme_Object *link_symbol, *machine_symbol, *gc_symbol;
  317. ROSYM static Scheme_Object *so_suffix_symbol, *so_mode_symbol, *word_symbol;
  318. ROSYM static Scheme_Object *os_symbol;
  319. ROSYM static Scheme_Object *platform_3m_path, *platform_cgc_path;
  320. READ_ONLY static Scheme_Object *zero_length_char_string;
  321. READ_ONLY static Scheme_Object *zero_length_byte_string;
  322. SHARED_OK static Scheme_Hash_Table *putenv_str_table;
  323. SHARED_OK static char *embedding_banner;
  324. SHARED_OK static Scheme_Object *vers_str;
  325. SHARED_OK static Scheme_Object *banner_str;
  326. READ_ONLY static Scheme_Object *complete_symbol, *continues_symbol, *aborts_symbol, *error_symbol;
  327. void
  328. scheme_init_string (Scheme_Env *env)
  329. {
  330. Scheme_Object *p;
  331. REGISTER_SO(sys_symbol);
  332. sys_symbol = scheme_intern_symbol(SYSTEM_TYPE_NAME);
  333. REGISTER_SO(link_symbol);
  334. REGISTER_SO(machine_symbol);
  335. REGISTER_SO(gc_symbol);
  336. REGISTER_SO(so_suffix_symbol);
  337. REGISTER_SO(so_mode_symbol);
  338. REGISTER_SO(word_symbol);
  339. REGISTER_SO(os_symbol);
  340. link_symbol = scheme_intern_symbol("link");
  341. machine_symbol = scheme_intern_symbol("machine");
  342. gc_symbol = scheme_intern_symbol("gc");
  343. so_suffix_symbol = scheme_intern_symbol("so-suffix");
  344. so_mode_symbol = scheme_intern_symbol("so-mode");
  345. word_symbol = scheme_intern_symbol("word");
  346. os_symbol = scheme_intern_symbol("os");
  347. REGISTER_SO(zero_length_char_string);
  348. REGISTER_SO(zero_length_byte_string);
  349. zero_length_char_string = scheme_alloc_char_string(0, 0);
  350. zero_length_byte_string = scheme_alloc_byte_string(0, 0);
  351. REGISTER_SO(complete_symbol);
  352. REGISTER_SO(continues_symbol);
  353. REGISTER_SO(aborts_symbol);
  354. REGISTER_SO(error_symbol);
  355. complete_symbol = scheme_intern_symbol("complete");
  356. continues_symbol = scheme_intern_symbol("continues");
  357. aborts_symbol = scheme_intern_symbol("aborts");
  358. error_symbol = scheme_intern_symbol("error");
  359. REGISTER_SO(platform_3m_path);
  360. #ifdef UNIX_FILE_SYSTEM
  361. # define MZ3M_SUBDIR "/3m"
  362. #else
  363. # ifdef DOS_FILE_SYSTEM
  364. # define MZ3M_SUBDIR "\\3m"
  365. # else
  366. # define MZ3M_SUBDIR ":3m"
  367. # endif
  368. #endif
  369. REGISTER_SO(platform_3m_path);
  370. REGISTER_SO(platform_cgc_path);
  371. platform_cgc_path = scheme_make_path(SCHEME_PLATFORM_LIBRARY_SUBPATH);
  372. platform_3m_path = scheme_make_path(SCHEME_PLATFORM_LIBRARY_SUBPATH MZ3M_SUBDIR);
  373. REGISTER_SO(putenv_str_table);
  374. REGISTER_SO(embedding_banner);
  375. REGISTER_SO(vers_str);
  376. REGISTER_SO(banner_str);
  377. vers_str = scheme_make_utf8_string(scheme_version());
  378. SCHEME_SET_CHAR_STRING_IMMUTABLE(vers_str);
  379. banner_str = scheme_make_utf8_string(scheme_banner());
  380. SCHEME_SET_CHAR_STRING_IMMUTABLE(banner_str);
  381. p = scheme_make_folding_prim(string_p, "string?", 1, 1, 1);
  382. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_UNARY_INLINED
  383. | SCHEME_PRIM_IS_OMITABLE);
  384. scheme_add_global_constant("string?", p, env);
  385. scheme_add_global_constant("make-string",
  386. scheme_make_immed_prim(make_string,
  387. "make-string",
  388. 1, 2),
  389. env);
  390. scheme_add_global_constant("string",
  391. scheme_make_immed_prim(string,
  392. "string",
  393. 0, -1),
  394. env);
  395. p = scheme_make_folding_prim(string_length, "string-length", 1, 1, 1);
  396. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_PRODUCES_FIXNUM);
  397. scheme_add_global_constant("string-length", p,
  398. env);
  399. p = scheme_make_immed_prim(scheme_checked_string_ref, "string-ref", 2, 2);
  400. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_BINARY_INLINED);
  401. scheme_add_global_constant("string-ref", p, env);
  402. p = scheme_make_immed_prim(scheme_checked_string_set, "string-set!", 3, 3);
  403. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED);
  404. scheme_add_global_constant("string-set!", p, env);
  405. scheme_add_global_constant("string=?",
  406. scheme_make_immed_prim(string_eq,
  407. "string=?",
  408. 2, -1),
  409. env);
  410. scheme_add_global_constant("string-locale=?",
  411. scheme_make_immed_prim(string_locale_eq,
  412. "string-locale=?",
  413. 2, -1),
  414. env);
  415. scheme_add_global_constant("string-ci=?",
  416. scheme_make_immed_prim(string_ci_eq,
  417. "string-ci=?",
  418. 2, -1),
  419. env);
  420. scheme_add_global_constant("string-locale-ci=?",
  421. scheme_make_immed_prim(string_locale_ci_eq,
  422. "string-locale-ci=?",
  423. 2, -1),
  424. env);
  425. scheme_add_global_constant("string<?",
  426. scheme_make_immed_prim(string_lt,
  427. "string<?",
  428. 2, -1),
  429. env);
  430. scheme_add_global_constant("string-locale<?",
  431. scheme_make_immed_prim(string_locale_lt,
  432. "string-locale<?",
  433. 2, -1),
  434. env);
  435. scheme_add_global_constant("string>?",
  436. scheme_make_immed_prim(string_gt,
  437. "string>?",
  438. 2, -1),
  439. env);
  440. scheme_add_global_constant("string-locale>?",
  441. scheme_make_immed_prim(string_locale_gt,
  442. "string-locale>?",
  443. 2, -1),
  444. env);
  445. scheme_add_global_constant("string<=?",
  446. scheme_make_immed_prim(string_lt_eq,
  447. "string<=?",
  448. 2, -1),
  449. env);
  450. scheme_add_global_constant("string>=?",
  451. scheme_make_immed_prim(string_gt_eq,
  452. "string>=?",
  453. 2, -1),
  454. env);
  455. scheme_add_global_constant("string-ci<?",
  456. scheme_make_immed_prim(string_ci_lt,
  457. "string-ci<?",
  458. 2, -1),
  459. env);
  460. scheme_add_global_constant("string-locale-ci<?",
  461. scheme_make_immed_prim(string_locale_ci_lt,
  462. "string-locale-ci<?",
  463. 2, -1),
  464. env);
  465. scheme_add_global_constant("string-ci>?",
  466. scheme_make_immed_prim(string_ci_gt,
  467. "string-ci>?",
  468. 2, -1),
  469. env);
  470. scheme_add_global_constant("string-locale-ci>?",
  471. scheme_make_immed_prim(string_locale_ci_gt,
  472. "string-locale-ci>?",
  473. 2, -1),
  474. env);
  475. scheme_add_global_constant("string-ci<=?",
  476. scheme_make_immed_prim(string_ci_lt_eq,
  477. "string-ci<=?",
  478. 2, -1),
  479. env);
  480. scheme_add_global_constant("string-ci>=?",
  481. scheme_make_immed_prim(string_ci_gt_eq,
  482. "string-ci>=?",
  483. 2, -1),
  484. env);
  485. scheme_add_global_constant("substring",
  486. scheme_make_immed_prim(substring,
  487. "substring",
  488. 2, 3),
  489. env);
  490. scheme_add_global_constant("string-append",
  491. scheme_make_immed_prim(string_append,
  492. "string-append",
  493. 0, -1),
  494. env);
  495. scheme_add_global_constant("string->list",
  496. scheme_make_immed_prim(string_to_list,
  497. "string->list",
  498. 1, 1),
  499. env);
  500. scheme_add_global_constant("list->string",
  501. scheme_make_immed_prim(list_to_string,
  502. "list->string",
  503. 1, 1),
  504. env);
  505. scheme_add_global_constant("string-copy",
  506. scheme_make_immed_prim(string_copy,
  507. "string-copy",
  508. 1, 1),
  509. env);
  510. scheme_add_global_constant("string-copy!",
  511. scheme_make_immed_prim(string_copy_bang,
  512. "string-copy!",
  513. 3, 5),
  514. env);
  515. scheme_add_global_constant("string-fill!",
  516. scheme_make_immed_prim(string_fill,
  517. "string-fill!",
  518. 2, 2),
  519. env);
  520. scheme_add_global_constant("string->immutable-string",
  521. scheme_make_immed_prim(string_to_immutable,
  522. "string->immutable-string",
  523. 1, 1),
  524. env);
  525. scheme_add_global_constant("string-normalize-nfc",
  526. scheme_make_immed_prim(string_normalize_c,
  527. "string-normalize-nfc",
  528. 1, 1),
  529. env);
  530. scheme_add_global_constant("string-normalize-nfkc",
  531. scheme_make_immed_prim(string_normalize_kc,
  532. "string-normalize-nfkc",
  533. 1, 1),
  534. env);
  535. scheme_add_global_constant("string-normalize-nfd",
  536. scheme_make_immed_prim(string_normalize_d,
  537. "string-normalize-nfd",
  538. 1, 1),
  539. env);
  540. scheme_add_global_constant("string-normalize-nfkd",
  541. scheme_make_immed_prim(string_normalize_kd,
  542. "string-normalize-nfkd",
  543. 1, 1),
  544. env);
  545. scheme_add_global_constant("string-upcase",
  546. scheme_make_immed_prim(string_upcase,
  547. "string-upcase",
  548. 1, 1),
  549. env);
  550. scheme_add_global_constant("string-downcase",
  551. scheme_make_immed_prim(string_downcase,
  552. "string-downcase",
  553. 1, 1),
  554. env);
  555. scheme_add_global_constant("string-titlecase",
  556. scheme_make_immed_prim(string_titlecase,
  557. "string-titlecase",
  558. 1, 1),
  559. env);
  560. scheme_add_global_constant("string-foldcase",
  561. scheme_make_immed_prim(string_foldcase,
  562. "string-foldcase",
  563. 1, 1),
  564. env);
  565. scheme_add_global_constant("string-locale-upcase",
  566. scheme_make_immed_prim(string_locale_upcase,
  567. "string-locale-upcase",
  568. 1, 1),
  569. env);
  570. scheme_add_global_constant("string-locale-downcase",
  571. scheme_make_immed_prim(string_locale_downcase,
  572. "string-locale-downcase",
  573. 1, 1),
  574. env);
  575. scheme_add_global_constant("current-locale",
  576. scheme_register_parameter(current_locale,
  577. "current-locale",
  578. MZCONFIG_LOCALE),
  579. env);
  580. scheme_add_global_constant("locale-string-encoding",
  581. scheme_make_immed_prim(locale_string_encoding,
  582. "locale-string-encoding",
  583. 0, 0),
  584. env);
  585. scheme_add_global_constant("system-language+country",
  586. scheme_make_immed_prim(system_language_country,
  587. "system-language+country",
  588. 0, 0),
  589. env);
  590. scheme_add_global_constant("bytes-converter?",
  591. scheme_make_immed_prim(byte_converter_p,
  592. "bytes-converter?",
  593. 1, 1),
  594. env);
  595. scheme_add_global_constant("bytes-convert",
  596. scheme_make_prim_w_arity2(byte_string_convert,
  597. "bytes-convert",
  598. 1, 7,
  599. 3, 3),
  600. env);
  601. scheme_add_global_constant("bytes-convert-end",
  602. scheme_make_prim_w_arity2(byte_string_convert_end,
  603. "bytes-convert-end",
  604. 0, 3,
  605. 2, 2),
  606. env);
  607. scheme_add_global_constant("bytes-open-converter",
  608. scheme_make_immed_prim(byte_string_open_converter,
  609. "bytes-open-converter",
  610. 2, 2),
  611. env);
  612. scheme_add_global_constant("bytes-close-converter",
  613. scheme_make_immed_prim(byte_string_close_converter,
  614. "bytes-close-converter",
  615. 1, 1),
  616. env);
  617. scheme_add_global_constant("format",
  618. scheme_make_noncm_prim(format,
  619. "format",
  620. 1, -1),
  621. env);
  622. scheme_add_global_constant("printf",
  623. scheme_make_noncm_prim(sch_printf,
  624. "printf",
  625. 1, -1),
  626. env);
  627. scheme_add_global_constant("eprintf",
  628. scheme_make_noncm_prim(sch_eprintf,
  629. "eprintf",
  630. 1, -1),
  631. env);
  632. scheme_add_global_constant("fprintf",
  633. scheme_make_noncm_prim(sch_fprintf,
  634. "fprintf",
  635. 2, -1),
  636. env);
  637. scheme_add_global_constant("byte?",
  638. scheme_make_folding_prim(byte_p,
  639. "byte?",
  640. 1, 1, 1),
  641. env);
  642. p = scheme_make_folding_prim(byte_string_p, "bytes?", 1, 1, 1);
  643. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED
  644. | SCHEME_PRIM_IS_OMITABLE);
  645. scheme_add_global_constant("bytes?", p, env);
  646. scheme_add_global_constant("make-bytes",
  647. scheme_make_immed_prim(make_byte_string,
  648. "make-bytes",
  649. 1, 2),
  650. env);
  651. scheme_add_global_constant("bytes",
  652. scheme_make_immed_prim(byte_string,
  653. "bytes",
  654. 0, -1),
  655. env);
  656. GLOBAL_PRIM_W_ARITY("make-shared-bytes", make_shared_byte_string, 1, 2, env);
  657. GLOBAL_PRIM_W_ARITY("shared-bytes", shared_byte_string, 0, -1, env);
  658. p = scheme_make_folding_prim(byte_string_length, "bytes-length", 1, 1, 1);
  659. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_PRODUCES_FIXNUM);
  660. scheme_add_global_constant("bytes-length", p, env);
  661. p = scheme_make_immed_prim(scheme_checked_byte_string_ref, "bytes-ref", 2, 2);
  662. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_BINARY_INLINED
  663. | SCHEME_PRIM_PRODUCES_FIXNUM);
  664. scheme_add_global_constant("bytes-ref", p, env);
  665. p = scheme_make_immed_prim(scheme_checked_byte_string_set, "bytes-set!", 3, 3);
  666. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_IS_NARY_INLINED);
  667. scheme_add_global_constant("bytes-set!", p, env);
  668. scheme_add_global_constant("bytes=?",
  669. scheme_make_immed_prim(byte_string_eq,
  670. "bytes=?",
  671. 2, -1),
  672. env);
  673. scheme_add_global_constant("bytes<?",
  674. scheme_make_immed_prim(byte_string_lt,
  675. "bytes<?",
  676. 2, -1),
  677. env);
  678. scheme_add_global_constant("bytes>?",
  679. scheme_make_immed_prim(byte_string_gt,
  680. "bytes>?",
  681. 2, -1),
  682. env);
  683. scheme_add_global_constant("subbytes",
  684. scheme_make_immed_prim(byte_substring,
  685. "subbytes",
  686. 2, 3),
  687. env);
  688. scheme_add_global_constant("bytes-append",
  689. scheme_make_immed_prim(byte_string_append,
  690. "bytes-append",
  691. 0, -1),
  692. env);
  693. scheme_add_global_constant("bytes->list",
  694. scheme_make_immed_prim(byte_string_to_list,
  695. "bytes->list",
  696. 1, 1),
  697. env);
  698. scheme_add_global_constant("list->bytes",
  699. scheme_make_immed_prim(list_to_byte_string,
  700. "list->bytes",
  701. 1, 1),
  702. env);
  703. scheme_add_global_constant("bytes-copy",
  704. scheme_make_immed_prim(byte_string_copy,
  705. "bytes-copy",
  706. 1, 1),
  707. env);
  708. scheme_add_global_constant("bytes-copy!",
  709. scheme_make_immed_prim(byte_string_copy_bang,
  710. "bytes-copy!",
  711. 3, 5),
  712. env);
  713. scheme_add_global_constant("bytes-fill!",
  714. scheme_make_immed_prim(byte_string_fill,
  715. "bytes-fill!",
  716. 2, 2),
  717. env);
  718. scheme_add_global_constant("bytes->immutable-bytes",
  719. scheme_make_immed_prim(byte_string_to_immutable,
  720. "bytes->immutable-bytes",
  721. 1, 1),
  722. env);
  723. p = scheme_make_immed_prim(byte_string_utf8_index, "bytes-utf-8-index", 2, 4);
  724. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_PRODUCES_FIXNUM);
  725. scheme_add_global_constant("bytes-utf-8-index", p, env);
  726. p = scheme_make_immed_prim(byte_string_utf8_length, "bytes-utf-8-length", 1, 4);
  727. SCHEME_PRIM_PROC_FLAGS(p) |= scheme_intern_prim_opt_flags(SCHEME_PRIM_PRODUCES_FIXNUM);
  728. scheme_add_global_constant("bytes-utf-8-length", p, env);
  729. scheme_add_global_constant("bytes-utf-8-ref",
  730. scheme_make_immed_prim(byte_string_utf8_ref,
  731. "bytes-utf-8-ref",
  732. 2, 4),
  733. env);
  734. scheme_add_global_constant("bytes->string/utf-8",
  735. scheme_make_immed_prim(byte_string_to_char_string,
  736. "bytes->string/utf-8",
  737. 1, 4),
  738. env);
  739. scheme_add_global_constant("bytes->string/locale",
  740. scheme_make_immed_prim(byte_string_to_char_string_locale,
  741. "bytes->string/locale",
  742. 1, 4),
  743. env);
  744. scheme_add_global_constant("bytes->string/latin-1",
  745. scheme_make_immed_prim(byte_string_to_char_string_latin1,
  746. "bytes->string/latin-1",
  747. 1, 4),
  748. env);
  749. scheme_add_global_constant("string->bytes/utf-8",
  750. scheme_make_immed_prim(char_string_to_byte_string,
  751. "string->bytes/utf-8",
  752. 1, 4),
  753. env);
  754. scheme_add_global_constant("string->bytes/locale",
  755. scheme_make_immed_prim(char_string_to_byte_string_locale,
  756. "string->bytes/locale",
  757. 1, 4),
  758. env);
  759. scheme_add_global_constant("string->bytes/latin-1",
  760. scheme_make_immed_prim(char_string_to_byte_string_latin1,
  761. "string->bytes/latin-1",
  762. 1, 4),
  763. env);
  764. scheme_add_global_constant("string-utf-8-length",
  765. scheme_make_immed_prim(char_string_utf8_length,
  766. "string-utf-8-length",
  767. 1, 3),
  768. env);
  769. /* In principle, `version' could be foldable, but it invites
  770. more problems than it solves... */
  771. scheme_add_global_constant("version",
  772. scheme_make_immed_prim(version,
  773. "version",
  774. 0, 0),
  775. env);
  776. scheme_add_global_constant("banner",
  777. scheme_make_immed_prim(banner,
  778. "banner",
  779. 0, 0),
  780. env);
  781. /* Environment variables */
  782. scheme_add_global_constant("environment-variables?",
  783. scheme_make_folding_prim(env_p,
  784. "environment-variables?",
  785. 1, 1, 1),
  786. env);
  787. scheme_add_global_constant("current-environment-variables",
  788. scheme_register_parameter(current_environment_variables,
  789. "current-environment-variables",
  790. MZCONFIG_CURRENT_ENV_VARS),
  791. env);
  792. scheme_add_global_constant("environment-variables-ref",
  793. scheme_make_immed_prim(sch_getenv,
  794. "environment-variables-ref",
  795. 2, 2),
  796. env);
  797. scheme_add_global_constant("environment-variables-set!",
  798. scheme_make_prim_w_arity(sch_putenv,
  799. "environment-variables-set!",
  800. 3, 4),
  801. env);
  802. scheme_add_global_constant("environment-variables-names",
  803. scheme_make_immed_prim(sch_getenv_names,
  804. "environment-variables-names",
  805. 1, 1),
  806. env);
  807. scheme_add_global_constant("environment-variables-copy",
  808. scheme_make_immed_prim(env_copy,
  809. "environment-variables-copy",
  810. 1, 1),
  811. env);
  812. scheme_add_global_constant("make-environment-variables",
  813. scheme_make_immed_prim(env_make,
  814. "make-environment-variables",
  815. 0, -1),
  816. env);
  817. /* Don't make these folding, since they're platform-specific: */
  818. scheme_add_global_constant("system-type",
  819. scheme_make_immed_prim(system_type,
  820. "system-type",
  821. 0, 1),
  822. env);
  823. scheme_add_global_constant("system-library-subpath",
  824. scheme_make_immed_prim(system_library_subpath,
  825. "system-library-subpath",
  826. 0, 1),
  827. env);
  828. scheme_add_global_constant("current-command-line-arguments",
  829. scheme_register_parameter(cmdline_args,
  830. "current-command-line-arguments",
  831. MZCONFIG_CMDLINE_ARGS),
  832. env);
  833. #ifdef MZ_PRECISE_GC
  834. register_traversers();
  835. #endif
  836. }
  837. void scheme_init_string_places(void) {
  838. REGISTER_SO(current_locale_name_ptr);
  839. current_locale_name_ptr = "xxxx\0\0\0\0";
  840. }
  841. /**********************************************************************/
  842. /* UTF-8 char constructors */
  843. /**********************************************************************/
  844. Scheme_Object *scheme_make_sized_offset_utf8_string(char *chars, intptr_t d, intptr_t len)
  845. {
  846. intptr_t ulen;
  847. mzchar *us;
  848. if (len) {
  849. ulen = scheme_utf8_decode((unsigned char *)chars, d, d + len,
  850. NULL, 0, -1,
  851. NULL, 0 /* not UTF-16 */, 0xFFFD);
  852. us = scheme_malloc_atomic(sizeof(mzchar) * (ulen + 1));
  853. scheme_utf8_decode((unsigned char *)chars, d, d + len,
  854. us, 0, -1,
  855. NULL, 0 /* not UTF-16 */, 0xFFFD);
  856. us[ulen] = 0;
  857. } else {
  858. us = (mzchar *)"\0\0\0";
  859. ulen = 0;
  860. }
  861. return scheme_make_sized_offset_char_string(us, 0, ulen, 0);
  862. }
  863. Scheme_Object *
  864. scheme_make_sized_utf8_string(char *chars, intptr_t len)
  865. {
  866. return scheme_make_sized_offset_utf8_string(chars, 0, len);
  867. }
  868. Scheme_Object *
  869. scheme_make_immutable_sized_utf8_string(char *chars, intptr_t len)
  870. {
  871. Scheme_Object *s;
  872. s = scheme_make_sized_offset_utf8_string(chars, 0, len);
  873. if (len)
  874. SCHEME_SET_CHAR_STRING_IMMUTABLE(s);
  875. return s;
  876. }
  877. Scheme_Object *
  878. scheme_make_utf8_string(const char *chars)
  879. {
  880. return scheme_make_sized_offset_utf8_string((char *)chars, 0, -1);
  881. }
  882. Scheme_Object *
  883. scheme_make_locale_string(const char *chars)
  884. {
  885. return scheme_byte_string_to_char_string_locale(scheme_make_byte_string((char *)chars));
  886. }
  887. /**********************************************************************/
  888. /* index helpers */
  889. /**********************************************************************/
  890. intptr_t scheme_extract_index(const char *name, int pos, int argc, Scheme_Object **argv, intptr_t top, int false_ok)
  891. {
  892. intptr_t i;
  893. int is_top = 0;
  894. if (SCHEME_INTP(argv[pos])) {
  895. i = SCHEME_INT_VAL(argv[pos]);
  896. } else if (SCHEME_BIGNUMP(argv[pos])) {
  897. if (SCHEME_BIGPOS(argv[pos])) {
  898. i = top; /* out-of-bounds */
  899. is_top = 1;
  900. } else
  901. i = -1; /* negative */
  902. } else
  903. i = -1;
  904. if (!is_top && (i < 0))
  905. scheme_wrong_contract(name,
  906. (false_ok ? "(or/c exact-nonnegative-integer? #f)" : "exact-nonnegative-integer?"),
  907. pos, argc, argv);
  908. return i;
  909. }
  910. void scheme_get_substring_indices(const char *name, Scheme_Object *str,
  911. int argc, Scheme_Object **argv,
  912. int spos, int fpos, intptr_t *_start, intptr_t *_finish)
  913. {
  914. intptr_t len;
  915. intptr_t start, finish;
  916. if (SCHEME_CHAPERONE_VECTORP(str))
  917. len = SCHEME_VEC_SIZE(str);
  918. else if (SCHEME_CHAR_STRINGP(str))
  919. len = SCHEME_CHAR_STRTAG_VAL(str);
  920. else
  921. len = SCHEME_BYTE_STRTAG_VAL(str);
  922. if (argc > spos)
  923. start = scheme_extract_index(name, spos, argc, argv, len + 1, 0);
  924. else
  925. start = 0;
  926. if (argc > fpos)
  927. finish = scheme_extract_index(name, fpos, argc, argv, len + 1, 0);
  928. else
  929. finish = len;
  930. if (!(start <= len)) {
  931. scheme_out_of_range(name, NULL, (fpos < 100) ? "starting " : "", argv[spos], str, 0, len);
  932. }
  933. if (!(finish >= start && finish <= len)) {
  934. scheme_out_of_range(name, NULL, "ending ", argv[fpos], str, start, len);
  935. }
  936. *_start = start;
  937. *_finish = finish;
  938. }
  939. void scheme_do_get_substring_indices(const char *name, Scheme_Object *str,
  940. int argc, Scheme_Object **argv,
  941. int spos, int fpos, intptr_t *_start, intptr_t *_finish, intptr_t len)
  942. {
  943. if (argc > spos) {
  944. if (SCHEME_INTP(argv[spos])) {
  945. intptr_t start = SCHEME_INT_VAL(argv[spos]);
  946. if ((start >= 0) && (start < len)) {
  947. *_start = start;
  948. if (argc > fpos) {
  949. intptr_t finish = SCHEME_INT_VAL(argv[fpos]);
  950. if ((finish >= start) && (finish <= len)) {
  951. *_finish = finish;
  952. return;
  953. }
  954. } else {
  955. *_finish = len;
  956. return;
  957. }
  958. }
  959. }
  960. } else {
  961. *_start = 0;
  962. *_finish = len;
  963. return;
  964. }
  965. scheme_get_substring_indices(name, str, argc, argv, spos, fpos, _start, _finish);
  966. }
  967. /**********************************************************************/
  968. /* char strings */
  969. /**********************************************************************/
  970. #define SCHEME_X_STR_VAL(x) SCHEME_CHAR_STR_VAL(x)
  971. #define SCHEME_X_STRTAG_VAL(x) SCHEME_CHAR_STRTAG_VAL(x)
  972. #define SCHEME_X_STRINGP(x) SCHEME_CHAR_STRINGP(x)
  973. #define SCHEME_MUTABLE_X_STRINGP(x) SCHEME_MUTABLE_CHAR_STRINGP(x)
  974. #define SCHEME_SET_X_STRING_IMMUTABLE(x) SCHEME_SET_CHAR_STRING_IMMUTABLE(x)
  975. #define scheme_x_string_type scheme_char_string_type
  976. #define X(a, b) a##_char##b
  977. #define X_(a, b) a##_##b
  978. #define X__(a) a
  979. #define EMPTY (mzchar *)"\0\0\0"
  980. #define Xchar mzchar
  981. #define uXchar mzchar
  982. #define XSTR ""
  983. #define IS_STR "string?"
  984. #define XSTRINGSTR "string"
  985. #define SUBXSTR "substring"
  986. #define CHARP(x) SCHEME_CHARP(x)
  987. #define CHAR_VAL(x) SCHEME_CHAR_VAL(x)
  988. #define CHAR_STR "char?"
  989. #define MAKE_CHAR(x) _scheme_make_char(x)
  990. #define xstrlen scheme_char_strlen
  991. #include "strops.inc"
  992. #define GEN_STRING_COMP(name, scheme_name, comp, op, ul, size_shortcut) \
  993. static Scheme_Object * name (int argc, Scheme_Object *argv[]) \
  994. { mzchar *s, *prev; int i, sl, pl; int falz = 0;\
  995. if (!SCHEME_CHAR_STRINGP(argv[0])) \
  996. scheme_wrong_contract(scheme_name, "string?", 0, argc, argv); \
  997. prev = SCHEME_CHAR_STR_VAL(argv[0]); pl = SCHEME_CHAR_STRTAG_VAL(argv[0]); \
  998. for (i = 1; i < argc; i++) { \
  999. if (!SCHEME_CHAR_STRINGP(argv[i])) \
  1000. scheme_wrong_contract(scheme_name, "string?", i, argc, argv); \
  1001. s = SCHEME_CHAR_STR_VAL(argv[i]); sl = SCHEME_CHAR_STRTAG_VAL(argv[i]); \
  1002. if (!falz) if (!(comp(scheme_name, \
  1003. prev, pl, \
  1004. s, sl, ul, size_shortcut) op 0)) falz = 1; \
  1005. prev = s; pl = sl; \
  1006. } \
  1007. return falz ? scheme_false : scheme_true; \
  1008. }
  1009. GEN_STRING_COMP(string_eq, "string=?", mz_char_strcmp, ==, 0, 1)
  1010. GEN_STRING_COMP(string_lt, "string<?", mz_char_strcmp, <, 0, 0)
  1011. GEN_STRING_COMP(string_gt, "string>?", mz_char_strcmp, >, 0, 0)
  1012. GEN_STRING_COMP(string_lt_eq, "string<=?", mz_char_strcmp, <=, 0, 0)
  1013. GEN_STRING_COMP(string_gt_eq, "string>=?", mz_char_strcmp, >=, 0, 0)
  1014. GEN_STRING_COMP(string_ci_eq, "string-ci=?", mz_char_strcmp_ci, ==, 0, 0)
  1015. GEN_STRING_COMP(string_ci_lt, "string-ci<?", mz_char_strcmp_ci, <, 0, 0)
  1016. GEN_STRING_COMP(string_ci_gt, "string-ci>?", mz_char_strcmp_ci, >, 0, 0)
  1017. GEN_STRING_COMP(string_ci_lt_eq, "string-ci<=?", mz_char_strcmp_ci, <=, 0, 0)
  1018. GEN_STRING_COMP(string_ci_gt_eq, "string-ci>=?", mz_char_strcmp_ci, >=, 0, 0)
  1019. GEN_STRING_COMP(string_locale_eq, "string-locale=?", mz_char_strcmp, ==, 1, 0)
  1020. GEN_STRING_COMP(string_locale_lt, "string-locale<?", mz_char_strcmp, <, 1, 0)
  1021. GEN_STRING_COMP(string_locale_gt, "string-locale>?", mz_char_strcmp, >, 1, 0)
  1022. GEN_STRING_COMP(string_locale_ci_eq, "string-locale-ci=?", mz_char_strcmp_ci, ==, 1, 0)
  1023. GEN_STRING_COMP(string_locale_ci_lt, "string-locale-ci<?", mz_char_strcmp_ci, <, 1, 0)
  1024. GEN_STRING_COMP(string_locale_ci_gt, "string-locale-ci>?", mz_char_strcmp_ci, >, 1, 0)
  1025. /**********************************************************************/
  1026. /* byte strings */
  1027. /**********************************************************************/
  1028. #define SCHEME_BYTEP(x) ((SCHEME_INTP(x)) && (SCHEME_INT_VAL(x) >= 0) && (SCHEME_INT_VAL(x) <= 255))
  1029. static Scheme_Object *
  1030. byte_p(int argc, Scheme_Object *argv[])
  1031. {
  1032. return (SCHEME_BYTEP(argv[0]) ? scheme_true : scheme_false);
  1033. }
  1034. #define SCHEME_X_STR_VAL(x) SCHEME_BYTE_STR_VAL(x)
  1035. #define SCHEME_X_STRTAG_VAL(x) SCHEME_BYTE_STRTAG_VAL(x)
  1036. #define SCHEME_X_STRINGP(x) SCHEME_BYTE_STRINGP(x)
  1037. #define SCHEME_MUTABLE_X_STRINGP(x) SCHEME_MUTABLE_BYTE_STRINGP(x)
  1038. #define SCHEME_SET_X_STRING_IMMUTABLE(x) SCHEME_SET_BYTE_STRING_IMMUTABLE(x)
  1039. #define scheme_x_string_type scheme_byte_string_type
  1040. #define X(a, b) a##_byte##b
  1041. #define X_(a, b) a##_byte_##b
  1042. #define X__(a) byte_##a
  1043. #define EMPTY ""
  1044. #define Xchar char
  1045. #define uXchar unsigned char
  1046. #define XSTR "byte "
  1047. #define IS_STR "bytes?"
  1048. #define XSTRINGSTR "bytes"
  1049. #define SUBXSTR "subbytes"
  1050. #define CHARP(x) SCHEME_BYTEP(x)
  1051. #define CHAR_VAL(x) SCHEME_INT_VAL(x)
  1052. #define CHAR_STR "byte?"
  1053. #define MAKE_CHAR(x) scheme_make_integer_value(x)
  1054. #define xstrlen strlen
  1055. #define GENERATING_BYTE
  1056. #include "strops.inc"
  1057. #undef GENERATING_BYTE
  1058. /* comparisons */
  1059. #define GEN_BYTE_STRING_COMP(name, scheme_name, comp, op) \
  1060. static Scheme_Object * name (int argc, Scheme_Object *argv[]) \
  1061. { char *s, *prev; int i, sl, pl; int falz = 0;\
  1062. if (!SCHEME_BYTE_STRINGP(argv[0])) \
  1063. scheme_wrong_contract(scheme_name, "bytes?", 0, argc, argv); \
  1064. prev = SCHEME_BYTE_STR_VAL(argv[0]); pl = SCHEME_BYTE_STRTAG_VAL(argv[0]); \
  1065. for (i = 1; i < argc; i++) { \
  1066. if (!SCHEME_BYTE_STRINGP(argv[i])) \
  1067. scheme_wrong_contract(scheme_name, "bytes?", i, argc, argv); \
  1068. s = SCHEME_BYTE_STR_VAL(argv[i]); sl = SCHEME_BYTE_STRTAG_VAL(argv[i]); \
  1069. if (!falz) if (!(comp(scheme_name, \
  1070. (unsigned char *)prev, pl, \
  1071. (unsigned char *)s, sl) op 0)) falz = 1; \
  1072. prev = s; pl = sl; \
  1073. } \
  1074. return falz ? scheme_false : scheme_true; \
  1075. }
  1076. GEN_BYTE_STRING_COMP(byte_string_eq, "bytes=?", mz_strcmp, ==)
  1077. GEN_BYTE_STRING_COMP(byte_string_lt, "bytes<?", mz_strcmp, <)
  1078. GEN_BYTE_STRING_COMP(byte_string_gt, "bytes>?", mz_strcmp, >)
  1079. /**********************************************************************/
  1080. /* byte string <-> char string */
  1081. /**********************************************************************/
  1082. /************************* bytes->string *************************/
  1083. static Scheme_Object *
  1084. do_byte_string_to_char_string(const char *who,
  1085. Scheme_Object *bstr,
  1086. intptr_t istart, intptr_t ifinish,
  1087. int perm, int as_locale)
  1088. {
  1089. int i, ulen;
  1090. char *chars;
  1091. unsigned int *v;
  1092. chars = SCHEME_BYTE_STR_VAL(bstr);
  1093. ulen = utf8_decode_x((unsigned char *)chars, istart, ifinish,
  1094. NULL, 0, -1,
  1095. NULL, NULL, 0, 0,
  1096. NULL, 0,
  1097. (perm > -1) ? 0xD800 : 0);
  1098. if (ulen < 0) {
  1099. scheme_contract_error(who,
  1100. "string is not a well-formed UTF-8 encoding",
  1101. "string", 1, bstr,
  1102. NULL);
  1103. }
  1104. v = (unsigned int *)scheme_malloc_atomic((ulen + 1) * sizeof(unsigned int));
  1105. utf8_decode_x((unsigned char *)chars, istart, ifinish,
  1106. v, 0, -1,
  1107. NULL, NULL, 0, 0,
  1108. NULL, 0,
  1109. (perm > -1) ? 0xD800 : 0);
  1110. if (perm > -1) {
  1111. for (i = 0; i < ulen; i++) {
  1112. if (v[i] == 0xD800)
  1113. v[i] = perm;
  1114. }
  1115. }
  1116. v[ulen] = 0;
  1117. return scheme_make_sized_char_string(v, ulen, 0);
  1118. }
  1119. static Scheme_Object *
  1120. do_byte_string_to_char_string_locale(const char *who,
  1121. Scheme_Object *bstr,
  1122. intptr_t istart, intptr_t ifinish,
  1123. int perm)
  1124. {
  1125. char *us;
  1126. intptr_t olen;
  1127. reset_locale();
  1128. if (!iconv_ready) init_iconv();
  1129. if (mzLOCALE_IS_UTF_8(current_locale_name) || !locale_on || !mzCHK_PROC(iconv_open))
  1130. return do_byte_string_to_char_string(who, bstr, istart, ifinish, perm, 1);
  1131. if (istart < ifinish) {
  1132. int no_cvt;
  1133. us = string_to_from_locale(0, SCHEME_BYTE_STR_VAL(bstr),
  1134. istart, ifinish - istart,
  1135. &olen, perm, &no_cvt);
  1136. if (!us) {
  1137. if (no_cvt) {
  1138. return do_byte_string_to_char_string(who, bstr, istart, ifinish, perm, 1);
  1139. } else {
  1140. scheme_contract_error(who,
  1141. "byte string is not a valid encoding for the current locale",
  1142. "byte string", 1, bstr,
  1143. NULL);
  1144. }
  1145. }
  1146. ((mzchar *)us)[olen] = 0;
  1147. } else {
  1148. us = "\0\0\0";
  1149. olen = 0;
  1150. }
  1151. return scheme_make_sized_char_string((mzchar *)us, olen, 0);
  1152. }
  1153. static Scheme_Object *
  1154. do_string_to_vector(const char *who, int mode, int argc, Scheme_Object *argv[])
  1155. {
  1156. int permc;
  1157. intptr_t istart, ifinish;
  1158. if (!SCHEME_BYTE_STRINGP(argv[0]))
  1159. scheme_wrong_contract(who, "bytes?", 0, argc, argv);
  1160. if ((argc < 2) || SCHEME_FALSEP(argv[1]))
  1161. permc = -1;
  1162. else {
  1163. if (!SCHEME_CHARP(argv[1]))
  1164. scheme_wrong_contract(who, "(or/c char? #f)", 1, argc, argv);
  1165. permc = SCHEME_CHAR_VAL(argv[1]);
  1166. }
  1167. scheme_get_substring_indices(who, argv[0], argc, argv,
  1168. 2, 3,
  1169. &istart, &ifinish);
  1170. if (mode == 0)
  1171. return do_byte_string_to_char_string(who, argv[0], istart, ifinish, permc, 0);
  1172. else if (mode == 1)
  1173. return do_byte_string_to_char_string_locale(who, argv[0], istart, ifinish, permc);
  1174. else {
  1175. /* Latin-1 */
  1176. mzchar *us;
  1177. unsigned char *s;
  1178. intptr_t i, len;
  1179. len = ifinish - istart;
  1180. s = (unsigned char *)SCHEME_BYTE_STR_VAL(argv[0]);
  1181. us = (mzchar *)scheme_malloc_atomic((len + 1) * sizeof(mzchar));
  1182. for (i = istart; i < ifinish; i++) {
  1183. us[i - istart] = s[i];
  1184. }
  1185. us[len] = 0;
  1186. return scheme_make_sized_char_string(us, len, 0);
  1187. }
  1188. }
  1189. static Scheme_Object *
  1190. byte_string_to_char_string (int argc, Scheme_Object *argv[])
  1191. {
  1192. return do_string_to_vector("bytes->string/utf-8", 0, argc, argv);
  1193. }
  1194. static Scheme_Object *
  1195. byte_string_to_char_string_locale (int argc, Scheme_Object *argv[])
  1196. {
  1197. return do_string_to_vector("bytes->string/locale", 1, argc, argv);
  1198. }
  1199. static Scheme_Object *
  1200. byte_string_to_char_string_latin1 (int argc, Scheme_Object *argv[])
  1201. {
  1202. return do_string_to_vector("bytes->string/latin-1", 2, argc, argv);
  1203. }
  1204. Scheme_Object *scheme_byte_string_to_char_string(Scheme_Object *o)
  1205. {
  1206. return do_byte_string_to_char_string("s->s", o, 0, SCHEME_BYTE_STRLEN_VAL(o), 0xFFFD, 0);
  1207. }
  1208. Scheme_Object *scheme_byte_string_to_char_string_locale(Scheme_Object *o)
  1209. {
  1210. return do_byte_string_to_char_string_locale("s->s", o, 0, SCHEME_BYTE_STRLEN_VAL(o), 0xFFFD);
  1211. }
  1212. /************************* string->bytes *************************/
  1213. static Scheme_Object *do_char_string_to_byte_string(Scheme_Object *s, intptr_t istart, intptr_t ifinish,
  1214. int as_locale)
  1215. {
  1216. char *bs;
  1217. int slen;
  1218. slen = scheme_utf8_encode(SCHEME_CHAR_STR_VAL(s), istart, ifinish,
  1219. NULL, 0,
  1220. 0 /* UTF-16 */);
  1221. bs = (char *)scheme_malloc_atomic(slen + 1);
  1222. scheme_utf8_encode(SCHEME_CHAR_STR_VAL(s), istart, ifinish,
  1223. (unsigned char *)bs, 0,
  1224. 0 /* UTF-16 */);
  1225. bs[slen] = 0;
  1226. return scheme_make_sized_byte_string(bs, slen, 0);
  1227. }
  1228. static Scheme_Object *
  1229. do_char_string_to_byte_string_locale(const char *who,
  1230. Scheme_Object *cstr,
  1231. intptr_t istart, intptr_t ifinish,
  1232. int perm)
  1233. {
  1234. char *s;
  1235. intptr_t olen;
  1236. reset_locale();
  1237. if (!iconv_ready) init_iconv();
  1238. if (mzLOCALE_IS_UTF_8(current_locale_name) || !locale_on || !mzCHK_PROC(iconv_open))
  1239. return do_char_string_to_byte_string(cstr, istart, ifinish, 1);
  1240. if (istart < ifinish) {
  1241. int no_cvt;
  1242. s = string_to_from_locale(1, (char *)SCHEME_CHAR_STR_VAL(cstr),
  1243. istart, ifinish - istart,
  1244. &olen, perm, &no_cvt);
  1245. if (!s) {
  1246. if (no_cvt) {
  1247. return do_char_string_to_byte_string(cstr, istart, ifinish, 1);
  1248. } else {
  1249. scheme_contract_error(who,
  1250. "string cannot be encoded for the current locale",
  1251. "string", 1, cstr,
  1252. NULL);
  1253. }
  1254. }
  1255. s[olen] = 0;
  1256. } else {
  1257. s = "";
  1258. olen = 0;
  1259. }
  1260. return scheme_make_sized_byte_string(s, olen, 0);
  1261. }
  1262. Scheme_Object *scheme_char_string_to_byte_string(Scheme_Object *s)
  1263. {
  1264. return do_char_string_to_byte_string(s, 0, SCHEME_CHAR_STRLEN_VAL(s), 0);
  1265. }
  1266. Scheme_Object *scheme_char_string_to_byte_string_locale(Scheme_Object *s)
  1267. {
  1268. return do_char_string_to_byte_string_locale("s->s", s, 0, SCHEME_CHAR_STRLEN_VAL(s), '?');
  1269. }
  1270. static Scheme_Object *do_chars_to_bytes(const char *who, int mode,
  1271. int argc, Scheme_Object *argv[])
  1272. {
  1273. intptr_t istart, ifinish;
  1274. int permc;
  1275. if (!SCHEME_CHAR_STRINGP(argv[0]))
  1276. scheme_wrong_contract(who, "string?", 0, argc, argv);
  1277. if ((argc < 2) || SCHEME_FALSEP(argv[1]))
  1278. permc = -1;
  1279. else {
  1280. if (!SCHEME_BYTEP(argv[1]))
  1281. scheme_wrong_contract(who, "(or/c byte? #f)", 1, argc, argv);
  1282. permc = SCHEME_INT_VAL(argv[1]);
  1283. }
  1284. scheme_get_substring_indices(who, argv[0], argc, argv,
  1285. 2, 3, &istart, &ifinish);
  1286. if (mode == 1)
  1287. return do_char_string_to_byte_string_locale(who, argv[0], istart, ifinish, permc);
  1288. else if (mode == 0)
  1289. return do_char_string_to_byte_string(argv[0], istart, ifinish, 0);
  1290. else {
  1291. /* Latin-1 */
  1292. mzchar *us;
  1293. unsigned char *s;
  1294. intptr_t i, len;
  1295. len = ifinish - istart;
  1296. us = SCHEME_CHAR_STR_VAL(argv[0]);
  1297. s = (unsigned char *)scheme_malloc_atomic(len + 1);
  1298. for (i = istart; i < ifinish; i++) {
  1299. if (us[i] < 256)
  1300. s[i - istart] = us[i];
  1301. else if (permc >= 0) {
  1302. s[i - istart] = permc;
  1303. } else {
  1304. scheme_contract_error(who,
  1305. "string cannot be encoded in Latin-1",
  1306. "string", 1, argv[0],
  1307. NULL);
  1308. }
  1309. }
  1310. s[len] = 0;
  1311. return scheme_make_sized_byte_string((char *)s, len, 0);
  1312. }
  1313. }
  1314. static Scheme_Object *char_string_to_byte_string(int argc, Scheme_Object *argv[])
  1315. {
  1316. return do_chars_to_bytes("string->bytes/utf-8", 0, argc, argv);
  1317. }
  1318. static Scheme_Object *char_string_to_byte_string_locale(int argc, Scheme_Object *argv[])
  1319. {
  1320. return do_chars_to_bytes("string->bytes/locale", 1, argc, argv);
  1321. }
  1322. static Scheme_Object *char_string_to_byte_string_latin1(int argc, Scheme_Object *argv[])
  1323. {
  1324. return do_chars_to_bytes("string->bytes/latin-1", 2, argc, argv);
  1325. }
  1326. /************************* Other *************************/
  1327. static Scheme_Object *char_string_utf8_length (int argc, Scheme_Object *argv[])
  1328. {
  1329. intptr_t istart, ifinish, len;
  1330. if (!SCHEME_CHAR_STRINGP(argv[0]))
  1331. scheme_wrong_contract("string-utf-8-length", "string?", 0, argc, argv);
  1332. scheme_get_substring_indices("string-utf-8-length", argv[0], argc, argv,
  1333. 1, 2, &istart, &ifinish);
  1334. len = scheme_utf8_encode(SCHEME_CHAR_STR_VAL(argv[0]), istart, ifinish,
  1335. NULL, 0, 0);
  1336. return scheme_make_integer(len);
  1337. }
  1338. static Scheme_Object *
  1339. byte_string_utf8_length (int argc, Scheme_Object *argv[])
  1340. {
  1341. int len, perm;
  1342. intptr_t istart, ifinish;
  1343. char *chars;
  1344. if (!SCHEME_BYTE_STRINGP(argv[0]))
  1345. scheme_wrong_contract("bytes-utf-8-length", "string?", 0, argc, argv);
  1346. chars = SCHEME_BYTE_STR_VAL(argv[0]);
  1347. if ((argc > 1) && !SCHEME_FALSEP(argv[1])) {
  1348. if (!SCHEME_CHARP(argv[1]))
  1349. scheme_wrong_contract("bytes-utf-8-length", "(or/c char? #f)", 1, argc, argv);
  1350. perm = 1;
  1351. } else
  1352. perm = 0;
  1353. scheme_get_substring_indices("bytes-utf-8-length", argv[0], argc, argv,
  1354. 2, 3,
  1355. &istart, &ifinish);
  1356. len = scheme_utf8_decode((unsigned char *)chars, istart, ifinish,
  1357. NULL, 0, -1,
  1358. NULL, 0, perm);
  1359. if (len < 0)
  1360. return scheme_false;
  1361. else
  1362. return scheme_make_integer(len);
  1363. }
  1364. static Scheme_Object *
  1365. byte_string_utf8_index(int argc, Scheme_Object *argv[])
  1366. {
  1367. intptr_t istart, ifinish, pos = -1, opos, ipos;
  1368. int result, perm;
  1369. char *chars;
  1370. if (!SCHEME_BYTE_STRINGP(argv[0]))
  1371. scheme_wrong_contract("bytes-utf-8-index", "bytes?", 0, argc, argv);
  1372. chars = SCHEME_BYTE_STR_VAL(argv[0]);
  1373. if (SCHEME_INTP(argv[1])) {
  1374. pos = SCHEME_INT_VAL(argv[1]);
  1375. } else if (SCHEME_BIGNUMP(argv[1])) {
  1376. if (SCHEME_BIGPOS(argv[1]))
  1377. pos = 0x7FFFFFFF;
  1378. }
  1379. if (pos < 0) {
  1380. scheme_wrong_contract("bytes-utf-8-index", "exact-nonnegative-integer?", 1, argc, argv);
  1381. }
  1382. if ((argc > 2) && !SCHEME_FALSEP(argv[2])) {
  1383. if (!SCHEME_CHARP(argv[2]))
  1384. scheme_wrong_contract("bytes-utf-8-index", "(or/c char? #f)", 1, argc, argv);
  1385. perm = 1;
  1386. } else
  1387. perm = 0;
  1388. scheme_get_substring_indices("bytes-utf-8-index", argv[0], argc, argv,
  1389. 3, 4,
  1390. &istart, &ifinish);
  1391. result = utf8_decode_x((unsigned char *)chars, istart, ifinish,
  1392. NULL, 0, pos,
  1393. &ipos, &opos,
  1394. 0, 0, NULL, 0, perm ? 1 : 0);
  1395. if (((result < 0) && (result != -3))
  1396. || ((ipos == ifinish) && (opos <= pos)))
  1397. return scheme_false;
  1398. else
  1399. return scheme_make_integer(ipos);
  1400. }
  1401. static Scheme_Object *
  1402. byte_string_utf8_ref(int argc, Scheme_Object *argv[])
  1403. {
  1404. intptr_t istart, ifinish, pos = -1, opos, ipos;
  1405. char *chars;
  1406. unsigned int us[1];
  1407. Scheme_Object *perm;
  1408. if (!SCHEME_BYTE_STRINGP(argv[0]))
  1409. scheme_wrong_contract("bytes-utf-8-ref", "bytes?", 0, argc, argv);
  1410. chars = SCHEME_BYTE_STR_VAL(argv[0]);
  1411. if (SCHEME_INTP(argv[1])) {
  1412. pos = SCHEME_INT_VAL(argv[1]);
  1413. } else if (SCHEME_BIGNUMP(argv[1])) {
  1414. if (SCHEME_BIGPOS(argv[1]))
  1415. pos = 0x7FFFFFFF;
  1416. }
  1417. if (pos < 0) {
  1418. scheme_wrong_contract("bytes-utf-8-ref", "exact-nonnegative-integer?", 1, argc, argv);
  1419. }
  1420. if ((argc > 2) && !SCHEME_FALSEP(argv[2])) {
  1421. if (!SCHEME_CHARP(argv[2]))
  1422. scheme_wrong_contract("bytes-utf-8-ref", "(or/c char? #f)", 1, argc, argv);
  1423. perm = argv[2];
  1424. } else
  1425. perm = 0;
  1426. scheme_get_substring_indices("bytes-utf-8-ref", argv[0], argc, argv,
  1427. 3, 4,
  1428. &istart, &ifinish);
  1429. if (pos > 0) {
  1430. utf8_decode_x((unsigned char *)chars, istart, ifinish,
  1431. NULL, 0, pos,
  1432. &ipos, &opos,
  1433. 0, 0, NULL, 0, perm ? 1 : 0);
  1434. if (opos < pos)
  1435. return scheme_false;
  1436. istart = ipos;
  1437. }
  1438. utf8_decode_x((unsigned char *)chars, istart, ifinish,
  1439. us, 0, 1,
  1440. &ipos, &opos,
  1441. 0, 0, NULL, 0, perm ? 0xFFFF : 0);
  1442. if (opos < 1)
  1443. return scheme_false;
  1444. else if (us[0] == 0xFFFF)
  1445. return perm;
  1446. else
  1447. return scheme_make_character(us[0]);
  1448. }
  1449. /********************************************************************/
  1450. /* format */
  1451. /********************************************************************/
  1452. void scheme_do_format(const char *procname, Scheme_Object *port,
  1453. const mzchar *format, int flen,
  1454. int fpos, int offset, int argc, Scheme_Object **argv)
  1455. {
  1456. int i, start, end;
  1457. int used = offset;
  1458. int num_err = 0, char_err = 0, end_ok = 0;
  1459. Scheme_Object *a[2];
  1460. if (!format) {
  1461. if (!SCHEME_CHAR_STRINGP(argv[fpos])) {
  1462. scheme_wrong_contract(procname, "string?", fpos, argc, argv);
  1463. return;
  1464. }
  1465. format = SCHEME_CHAR_STR_VAL(argv[fpos]);
  1466. flen = SCHEME_CHAR_STRTAG_VAL(argv[fpos]);
  1467. } else if (flen == -1)
  1468. flen = strlen((char *)format);
  1469. /* Check string first: */
  1470. end = flen - 1;
  1471. for (i = 0; i < end; i++) {
  1472. if (format[i] == '~') {
  1473. i++;
  1474. if (scheme_isspace(format[i])) {
  1475. /* skip spaces... */
  1476. } else switch (format[i]) {
  1477. case '~':
  1478. if (i == end)
  1479. end_ok = 1;
  1480. break;
  1481. case '%':
  1482. case 'n':
  1483. case 'N':
  1484. break;
  1485. case 'a':
  1486. case 'A':
  1487. case 's':
  1488. case 'S':
  1489. case 'v':
  1490. case 'V':
  1491. case 'e':
  1492. case 'E':
  1493. used++;
  1494. break;
  1495. case '.':
  1496. switch (format[i+1]) {
  1497. case 'a':
  1498. case 'A':
  1499. case 's':
  1500. case 'S':
  1501. case 'v':
  1502. case 'V':
  1503. break;
  1504. default:
  1505. scheme_contract_error(procname,
  1506. "ill-formed pattern string",
  1507. "explanation", 0, "tag `~.' not followed by `a', `s', or `v'",
  1508. "pattern string", 1, argv[fpos],
  1509. NULL);
  1510. break;
  1511. }
  1512. used++;
  1513. break;
  1514. case 'x':
  1515. case 'X':
  1516. case 'o':
  1517. case 'O':
  1518. case 'b':
  1519. case 'B':
  1520. if (!num_err && !char_err && (used < argc)) {
  1521. Scheme_Object *o = argv[used];
  1522. if (!SCHEME_EXACT_REALP(o)
  1523. && (!SCHEME_COMPLEXP(o)
  1524. || !SCHEME_EXACT_REALP(scheme_complex_real_part(o))))
  1525. num_err = used + 1;
  1526. }
  1527. used++;
  1528. break;
  1529. case 'c':
  1530. case 'C':
  1531. if (!num_err && !char_err && (used < argc)) {
  1532. if (!SCHEME_CHARP(argv[used]))
  1533. char_err = used + 1;
  1534. }
  1535. used++;
  1536. break;
  1537. default:
  1538. {
  1539. char buffer[64];
  1540. sprintf(buffer, "tag `~%c' not allowed", format[i]);
  1541. scheme_contract_error(procname,
  1542. "ill-formed pattern string",
  1543. "explanation", 0, buffer,
  1544. "pattern string", 1, argv[fpos],
  1545. NULL);
  1546. return;
  1547. }
  1548. }
  1549. }
  1550. }
  1551. if ((format[end] == '~') && !end_ok) {
  1552. scheme_contract_error(procname,
  1553. "ill-formed pattern string",
  1554. "explanation", 0, "cannot end in `~'",
  1555. "pattern string", 1, argv[fpos],
  1556. NULL);
  1557. return;
  1558. }
  1559. if (used != argc) {
  1560. char *args;
  1561. intptr_t alen;
  1562. args = scheme_make_args_string("", -1, argc, argv, &alen);
  1563. if (used > argc) {
  1564. scheme_raise_exn(MZEXN_FAIL_CONTRACT,
  1565. "%s: format string requires %d arguments, given %d%t",
  1566. procname, used - offset, argc - offset, args, alen);
  1567. } else {
  1568. scheme_raise_exn(MZEXN_FAIL_CONTRACT,
  1569. "%s: format string requires %d arguments, given %d%t",
  1570. procname, used - offset, argc - offset, args, alen);
  1571. }
  1572. return;
  1573. }
  1574. if (num_err || char_err) {
  1575. int pos = (num_err ? num_err : char_err) - 1;
  1576. char *args, *bstr;
  1577. intptr_t alen;
  1578. intptr_t blen;
  1579. char *type = (num_err ? "exact-number" : "character");
  1580. Scheme_Object *bad = argv[pos];
  1581. args = scheme_make_args_string("other ", pos, argc, argv, &alen);
  1582. bstr = scheme_make_provided_string(bad, 1, &blen);
  1583. scheme_raise_exn(MZEXN_FAIL_CONTRACT,
  1584. "%s: format string requires argument of type <%s>, given %t%t",
  1585. procname, type,
  1586. bstr, blen,
  1587. args, alen);
  1588. return;
  1589. }
  1590. for (used = offset, i = start = 0; i < flen; i++) {
  1591. if (format[i] == '~') {
  1592. if (start < i) {
  1593. (void)scheme_put_char_string(procname, port, format, start, i - start);
  1594. }
  1595. i++;
  1596. if (scheme_isspace(format[i])) {
  1597. /* skip spaces (at most one newline) */
  1598. do {
  1599. if ((format[i] == '\n') || (format[i] == '\r')) {
  1600. /* got one */
  1601. if ((format[i] == '\r') && (format[i + 1] == '\n'))
  1602. i++; /* Windows-style CR-NL */
  1603. i++;
  1604. while (portable_isspace(format[i])
  1605. && !((format[i] == '\n') || (format[i] == '\r'))) {
  1606. i++;
  1607. }
  1608. break;
  1609. } else
  1610. i++;
  1611. } while (scheme_isspace(format[i]));
  1612. --i; /* back up over something */
  1613. } else switch (format[i]) {
  1614. case '~':
  1615. scheme_write_byte_string("~", 1, port);
  1616. break;
  1617. case '%':
  1618. case 'n':
  1619. case 'N':
  1620. scheme_write_byte_string("\n", 1, port);
  1621. break;
  1622. case 'c':
  1623. case 'C':
  1624. case 'a':
  1625. case 'A':
  1626. a[0] = argv[used++];
  1627. a[1] = port;
  1628. _scheme_apply(scheme_display_proc, 2, a);
  1629. break;
  1630. case 's':
  1631. case 'S':
  1632. a[0] = argv[used++];
  1633. a[1] = port;
  1634. _scheme_apply(scheme_write_proc, 2, a);
  1635. break;
  1636. case 'v':
  1637. case 'V':
  1638. a[0] = argv[used++];
  1639. a[1] = port;
  1640. _scheme_apply(scheme_print_proc, 2, a);
  1641. break;
  1642. case 'e':
  1643. case 'E':
  1644. {
  1645. intptr_t len;
  1646. char *s;
  1647. s = scheme_make_provided_string(argv[used++], 0, &len);
  1648. scheme_write_byte_string(s, len, port);
  1649. }
  1650. break;
  1651. case '.':
  1652. {
  1653. intptr_t len;
  1654. char *s;
  1655. len = scheme_get_print_width();
  1656. i++;
  1657. switch (format[i]) {
  1658. case 'a':
  1659. case 'A':
  1660. s = scheme_display_to_string_w_max(argv[used++], &len, len);
  1661. break;
  1662. case 's':
  1663. case 'S':
  1664. s = scheme_write_to_string_w_max(argv[used++], &len, len);
  1665. break;
  1666. case 'v':
  1667. case 'V':
  1668. s = scheme_print_to_string_w_max(argv[used++], &len, len);
  1669. break;
  1670. default:
  1671. s = "???";
  1672. len = 3;
  1673. }
  1674. scheme_write_byte_string(s, len, port);
  1675. }
  1676. break;
  1677. case 'x':
  1678. case 'X':
  1679. case 'o':
  1680. case 'O':
  1681. case 'b':
  1682. case 'B':
  1683. {
  1684. char *s;
  1685. int radix;
  1686. switch(format[i]) {
  1687. case 'x':
  1688. case 'X':
  1689. radix = 16;
  1690. break;
  1691. case 'o':
  1692. case 'O':
  1693. radix = 8;
  1694. break;
  1695. default:
  1696. case 'b':
  1697. case 'B':
  1698. radix = 2;
  1699. break;
  1700. }
  1701. s = scheme_number_to_string(radix, argv[used++]);
  1702. scheme_write_byte_string(s, strlen(s), port);
  1703. }
  1704. break;
  1705. }
  1706. SCHEME_USE_FUEL(1);
  1707. start = i + 1;
  1708. }
  1709. }
  1710. SCHEME_USE_FUEL(flen);
  1711. if (start < i) {
  1712. (void)scheme_put_char_string(procname, port, format, start, i - start);
  1713. }
  1714. }
  1715. char *scheme_format(mzchar *format, int flen, int argc, Scheme_Object **argv, intptr_t *rlen)
  1716. {
  1717. Scheme_Object *port;
  1718. port = scheme_make_byte_string_output_port();
  1719. scheme_do_format("format", port, format, flen, 0, 0, argc, argv);
  1720. return scheme_get_sized_byte_string_output(port, rlen);
  1721. }
  1722. void scheme_printf(mzchar *format, int flen, int argc, Scheme_Object **argv)
  1723. {
  1724. scheme_do_format("printf", scheme_get_param(scheme_current_config(), MZCONFIG_OUTPUT_PORT),
  1725. format, flen, 0, 0, argc, argv);
  1726. }
  1727. char *scheme_format_utf8(char *format, int flen, int argc, Scheme_Object **argv, intptr_t *rlen)
  1728. {
  1729. mzchar *s;
  1730. intptr_t srlen;
  1731. if (flen == -1)
  1732. flen = strlen(format);
  1733. s = scheme_utf8_decode_to_buffer_len((unsigned char *)format, flen, NULL, 0, &srlen);
  1734. if (s)
  1735. return scheme_format(s, srlen, argc, argv, rlen);
  1736. else
  1737. return "";
  1738. }
  1739. void scheme_printf_utf8(char *format, int flen, int argc, Scheme_Object **argv)
  1740. {
  1741. mzchar *s;
  1742. intptr_t srlen;
  1743. if (flen == -1)
  1744. flen = strlen(format);
  1745. s = scheme_utf8_decode_to_buffer_len((unsigned char *)format, flen, NULL, 0, &srlen);
  1746. if (s)
  1747. scheme_printf(s, srlen, argc, argv);
  1748. }
  1749. static Scheme_Object *
  1750. format(int argc, Scheme_Object *argv[])
  1751. {
  1752. Scheme_Object *port;
  1753. char *s;
  1754. intptr_t len;
  1755. port = scheme_make_byte_string_output_port();
  1756. scheme_do_format("format", port, NULL, 0, 0, 1, argc, argv);
  1757. s = scheme_get_sized_byte_string_output(port, &len);
  1758. return scheme_make_sized_utf8_string(s, len);
  1759. }
  1760. #ifdef INSTRUMENT_PRIMITIVES
  1761. extern int g_print_prims;
  1762. #endif
  1763. static Scheme_Object *
  1764. sch_printf(int argc, Scheme_Object *argv[])
  1765. {
  1766. scheme_do_format("printf", scheme_get_param(scheme_current_config(), MZCONFIG_OUTPUT_PORT),
  1767. NULL, 0, 0, 1, argc, argv);
  1768. return scheme_void;
  1769. }
  1770. static Scheme_Object *
  1771. sch_eprintf(int argc, Scheme_Object *argv[])
  1772. {
  1773. scheme_do_format("eprintf", scheme_get_param(scheme_current_config(), MZCONFIG_ERROR_PORT),
  1774. NULL, 0, 0, 1, argc, argv);
  1775. return scheme_void;
  1776. }
  1777. static Scheme_Object *
  1778. sch_fprintf(int argc, Scheme_Object *argv[])
  1779. {
  1780. if (!SCHEME_OUTPUT_PORTP(argv[0]))
  1781. scheme_wrong_contract("fprintf", "output-port?", 0, argc, argv);
  1782. scheme_do_format("fprintf", argv[0], NULL, 0, 1, 2, argc, argv);
  1783. return scheme_void;
  1784. }
  1785. /********************************************************************/
  1786. /* misc */
  1787. /********************************************************************/
  1788. static Scheme_Object *
  1789. version(int argc, Scheme_Object *argv[])
  1790. {
  1791. return vers_str;
  1792. }
  1793. static Scheme_Object *
  1794. banner(int argc, Scheme_Object *argv[])
  1795. {
  1796. return banner_str;
  1797. }
  1798. char *scheme_version(void)
  1799. {
  1800. return MZSCHEME_VERSION;
  1801. }
  1802. #ifdef MZ_PRECISE_GC
  1803. /* don't print " [3m]", which is the default: */
  1804. # define VERSION_SUFFIX ""
  1805. #else
  1806. # ifdef USE_SENORA_GC
  1807. # define VERSION_SUFFIX " [cgc~]"
  1808. # else
  1809. # define VERSION_SUFFIX " [cgc]"
  1810. # endif
  1811. #endif
  1812. char *scheme_banner(void)
  1813. {
  1814. if (embedding_banner)
  1815. return embedding_banner;
  1816. else
  1817. return ("Welcome to Racket"
  1818. " v" MZSCHEME_VERSION VERSION_SUFFIX
  1819. ".\n");
  1820. }
  1821. void scheme_set_banner(char *s)
  1822. {
  1823. embedding_banner = s;
  1824. }
  1825. int scheme_byte_string_has_null(Scheme_Object *o)
  1826. {
  1827. const char *s = SCHEME_BYTE_STR_VAL(o);
  1828. int i = SCHEME_BYTE_STRTAG_VAL(o);
  1829. while (i--) {
  1830. if (!s[i])
  1831. return 1;
  1832. }
  1833. return 0;
  1834. }
  1835. int scheme_any_string_has_null(Scheme_Object *o)
  1836. {
  1837. if (SCHEME_BYTE_STRINGP(o))
  1838. return scheme_byte_string_has_null(o);
  1839. else {
  1840. const mzchar *s = SCHEME_CHAR_STR_VAL(o);
  1841. int i = SCHEME_CHAR_STRTAG_VAL(o);
  1842. while (i--) {
  1843. if (!s[i])
  1844. return 1;
  1845. }
  1846. return 0;
  1847. }
  1848. }
  1849. /***********************************************************************/
  1850. /* Environment Variables */
  1851. /***********************************************************************/
  1852. #ifdef OS_X
  1853. # include <crt_externs.h>
  1854. # define GET_ENVIRON_ARRAY *_NSGetEnviron()
  1855. #endif
  1856. #if !defined(DOS_FILE_SYSTEM) && !defined(GET_ENVIRON_ARRAY)
  1857. extern char **environ;
  1858. # define GET_ENVIRON_ARRAY environ
  1859. #endif
  1860. #define SCHEME_ENVVARS_TABLE(ev) ((Scheme_Hash_Tree *)SCHEME_PTR_VAL(ev))
  1861. Scheme_Object *scheme_make_environment_variables(Scheme_Hash_Tree *ht)
  1862. {
  1863. Scheme_Object *ev;
  1864. ev = scheme_alloc_small_object();
  1865. ev->type = scheme_environment_variables_type;
  1866. SCHEME_PTR_VAL(ev) = (Scheme_Object *)ht;
  1867. return ev;
  1868. }
  1869. static Scheme_Object *env_p(int argc, Scheme_Object *argv[])
  1870. {
  1871. return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type)
  1872. ? scheme_true
  1873. : scheme_false);
  1874. }
  1875. static Scheme_Object *current_environment_variables(int argc, Scheme_Object *argv[])
  1876. {
  1877. Scheme_Object *v;
  1878. v = scheme_param_config("current-environment-variables",
  1879. scheme_make_integer(MZCONFIG_CURRENT_ENV_VARS),
  1880. argc, argv,
  1881. -1, env_p, "environment-variables?", 0);
  1882. return v;
  1883. }
  1884. #if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
  1885. static char* clone_str_with_gc(const char* buffer) {
  1886. int length;
  1887. char *newbuffer;
  1888. length = strlen(buffer);
  1889. newbuffer = scheme_malloc_atomic(length+1);
  1890. memcpy(newbuffer, buffer, length+1);
  1891. return newbuffer;
  1892. }
  1893. #endif
  1894. static void create_putenv_str_table_if_needed() {
  1895. if (!putenv_str_table) {
  1896. putenv_str_table = scheme_make_hash_table(SCHEME_hash_string);
  1897. }
  1898. }
  1899. #ifndef DOS_FILE_SYSTEM
  1900. static void putenv_str_table_put_name(const char *name, char *value) {
  1901. #if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
  1902. void *original_gc;
  1903. const char *name_copy;
  1904. original_gc = GC_switch_to_master_gc();
  1905. scheme_start_atomic();
  1906. name_copy = clone_str_with_gc(name);
  1907. create_putenv_str_table_if_needed();
  1908. scheme_hash_set(putenv_str_table, (Scheme_Object *)name_copy, (Scheme_Object *)value);
  1909. scheme_end_atomic_no_swap();
  1910. GC_switch_back_from_master(original_gc);
  1911. #else
  1912. create_putenv_str_table_if_needed();
  1913. scheme_hash_set(putenv_str_table, (Scheme_Object *)name, (Scheme_Object *)value);
  1914. #endif
  1915. }
  1916. #endif
  1917. #if defined(MZ_PRECISE_GC)
  1918. static Scheme_Object *putenv_str_table_get(const char *name) {
  1919. #if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
  1920. void *original_gc;
  1921. Scheme_Object *value;
  1922. original_gc = GC_switch_to_master_gc();
  1923. scheme_start_atomic();
  1924. create_putenv_str_table_if_needed();
  1925. value = scheme_hash_get(putenv_str_table, (Scheme_Object *)name);
  1926. scheme_end_atomic_no_swap();
  1927. GC_switch_back_from_master(original_gc);
  1928. return value;
  1929. #else
  1930. create_putenv_str_table_if_needed();
  1931. return scheme_hash_get(putenv_str_table, (Scheme_Object *)name);
  1932. #endif
  1933. }
  1934. #endif
  1935. static int sch_bool_getenv(const char* name);
  1936. void
  1937. scheme_init_getenv(void)
  1938. {
  1939. if (sch_bool_getenv("PLTNOMZJIT")) {
  1940. scheme_set_startup_use_jit(0);
  1941. }
  1942. }
  1943. #ifdef DOS_FILE_SYSTEM
  1944. # include <windows.h>
  1945. static char *dos_win_getenv(const char *name) {
  1946. int value_size;
  1947. value_size = GetEnvironmentVariableW(WIDE_PATH(name), NULL, 0);
  1948. if (value_size) {
  1949. wchar_t *value;
  1950. int got;
  1951. value = scheme_malloc_atomic(sizeof(wchar_t) * value_size);
  1952. got = GetEnvironmentVariableW(WIDE_PATH(name), value, value_size);
  1953. if (got < value_size)
  1954. value[got] = 0;
  1955. return NARROW_PATH(value);
  1956. }
  1957. return NULL;
  1958. }
  1959. #endif
  1960. static int sch_bool_getenv(const char* name)
  1961. {
  1962. int rc = 0;
  1963. #ifdef DOS_FILE_SYSTEM
  1964. if (GetEnvironmentVariable(name, NULL, 0)) rc = 1;
  1965. #else
  1966. if (getenv(name)) rc = 1;
  1967. #endif
  1968. return rc;
  1969. }
  1970. int byte_string_ok_name(Scheme_Object *o)
  1971. {
  1972. const char *s = SCHEME_BYTE_STR_VAL(o);
  1973. int i = SCHEME_BYTE_STRTAG_VAL(o);
  1974. #ifdef DOS_FILE_SYSTEM
  1975. if (!i) return 0;
  1976. #endif
  1977. while (i--) {
  1978. if (!s[i] || s[i] == '=')
  1979. return 0;
  1980. }
  1981. return 1;
  1982. }
  1983. static Scheme_Object *normalize_env_case(Scheme_Object *bs)
  1984. {
  1985. #ifdef DOS_FILE_SYSTEM
  1986. bs = scheme_byte_string_to_char_string(bs);
  1987. bs = string_locale_downcase(1, &bs);
  1988. bs = scheme_char_string_to_byte_string(bs);
  1989. #endif
  1990. return bs;
  1991. }
  1992. static Scheme_Object *sch_getenv(int argc, Scheme_Object *argv[])
  1993. {
  1994. char *name;
  1995. char *value;
  1996. Scheme_Object *bs, *ev, *val;
  1997. Scheme_Hash_Tree *ht;
  1998. if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
  1999. scheme_wrong_contract("environment-variables-ref", "environment-variables?", 0, argc, argv);
  2000. bs = argv[1];
  2001. if (!SCHEME_BYTE_STRINGP(bs)
  2002. || !byte_string_ok_name(bs))
  2003. scheme_wrong_contract("environment-variables-ref", "bytes-environment-variable-name?", 1, argc, argv);
  2004. ev = argv[0];
  2005. ht = SCHEME_ENVVARS_TABLE(ev);
  2006. if (!ht) {
  2007. name = SCHEME_BYTE_STR_VAL(bs);
  2008. #ifdef DOS_FILE_SYSTEM
  2009. value = dos_win_getenv(name);
  2010. #else
  2011. value = getenv(name);
  2012. #endif
  2013. return value ? scheme_make_byte_string(value) : scheme_false;
  2014. } else {
  2015. bs = normalize_env_case(bs);
  2016. val = scheme_hash_tree_get(ht, bs);
  2017. return val ? val : scheme_false;
  2018. }
  2019. }
  2020. #ifndef DOS_FILE_SYSTEM
  2021. static int sch_unix_putenv(const char *var, const char *val, const intptr_t varlen, const intptr_t vallen) {
  2022. char *buffer;
  2023. intptr_t total_length;
  2024. total_length = varlen + vallen + 2;
  2025. if (val) {
  2026. #ifdef MZ_PRECISE_GC
  2027. /* Can't put moveable string into array. */
  2028. buffer = malloc(total_length);
  2029. #else
  2030. buffer = (char *)scheme_malloc_atomic(total_length);
  2031. #endif
  2032. memcpy(buffer, var, varlen);
  2033. buffer[varlen] = '=';
  2034. memcpy(buffer + varlen + 1, val, vallen + 1);
  2035. } else {
  2036. buffer = NULL;
  2037. }
  2038. #ifdef MZ_PRECISE_GC
  2039. {
  2040. /* Free old, if in table: */
  2041. char *oldbuffer;
  2042. oldbuffer = (char *)putenv_str_table_get(var);
  2043. if (oldbuffer)
  2044. free(oldbuffer);
  2045. }
  2046. #endif
  2047. /* if precise the buffer needs to be remembered so it can be freed */
  2048. /* if not precise the buffer needs to be rooted so it doesn't get collected prematurely */
  2049. putenv_str_table_put_name(var, buffer);
  2050. if (buffer)
  2051. return putenv(buffer);
  2052. else {
  2053. /* on some platforms, unsetenv() returns void */
  2054. unsetenv(var);
  2055. return 0;
  2056. }
  2057. }
  2058. #endif
  2059. static Scheme_Object *sch_putenv(int argc, Scheme_Object *argv[])
  2060. {
  2061. Scheme_Object *varbs, *valbs, *ev;
  2062. Scheme_Hash_Tree *ht;
  2063. char *var;
  2064. char *val;
  2065. int rc = 0, errid = 0;
  2066. if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
  2067. scheme_wrong_contract("environment-variables-set!", "environment-variables?", 0, argc, argv);
  2068. varbs = argv[1];
  2069. if (!SCHEME_BYTE_STRINGP(varbs)
  2070. || !byte_string_ok_name(varbs))
  2071. scheme_wrong_contract("environment-variables-set!", "bytes-environment-variable-name?", 1, argc, argv);
  2072. valbs = argv[2];
  2073. if (!SCHEME_FALSEP(valbs)
  2074. && (!SCHEME_BYTE_STRINGP(valbs)
  2075. || scheme_byte_string_has_null(valbs)))
  2076. scheme_wrong_contract("environment-variables-set!", "(or/c bytes-no-nuls? #f)", 2, argc, argv);
  2077. if (argc > 3)
  2078. scheme_check_proc_arity("environment-variables-set!", 0, 3, argc, argv);
  2079. ev = argv[0];
  2080. ht = SCHEME_ENVVARS_TABLE(ev);
  2081. if (ht) {
  2082. varbs = normalize_env_case(varbs);
  2083. if (SCHEME_FALSEP(valbs)) {
  2084. ht = scheme_hash_tree_set(ht, varbs, NULL);
  2085. } else {
  2086. varbs = byte_string_to_immutable(1, &varbs);
  2087. valbs = byte_string_to_immutable(1, &valbs);
  2088. ht = scheme_hash_tree_set(ht, varbs, valbs);
  2089. }
  2090. SCHEME_PTR_VAL(ev) = (Scheme_Object *)ht;
  2091. return scheme_void;
  2092. } else {
  2093. var = SCHEME_BYTE_STR_VAL(varbs);
  2094. if (SCHEME_FALSEP(valbs)) {
  2095. val = NULL;
  2096. } else {
  2097. val = SCHEME_BYTE_STR_VAL(valbs);
  2098. }
  2099. #ifdef DOS_FILE_SYSTEM
  2100. rc = !SetEnvironmentVariable(var, val);
  2101. if (rc)
  2102. errid = GetLastError();
  2103. #else
  2104. rc = sch_unix_putenv(var, val, SCHEME_BYTE_STRLEN_VAL(varbs), (val ? SCHEME_BYTE_STRLEN_VAL(valbs) : 0));
  2105. errid = errno;
  2106. #endif
  2107. if (rc) {
  2108. if (argc > 3)
  2109. return _scheme_tail_apply(argv[3], 0, NULL);
  2110. else {
  2111. scheme_raise_exn(MZEXN_FAIL,
  2112. "environment-variables-set!: change failed\n"
  2113. " system error: %e",
  2114. errid);
  2115. }
  2116. }
  2117. return scheme_void;
  2118. }
  2119. }
  2120. static Scheme_Object *env_copy(int argc, Scheme_Object *argv[])
  2121. {
  2122. Scheme_Hash_Tree *ht;
  2123. if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_environment_variables_type))
  2124. scheme_wrong_contract("environment-variables-copy", "environment-variables?", 0, argc, argv);
  2125. ht = SCHEME_ENVVARS_TABLE(argv[0]);
  2126. if (ht)
  2127. return scheme_make_environment_variables(ht);
  2128. /* copy system environment variables into a hash table: */
  2129. ht = scheme_make_hash_tree(1);
  2130. #ifdef DOS_FILE_SYSTEM
  2131. {
  2132. char *p;
  2133. GC_CAN_IGNORE wchar_t *e;
  2134. int i, start, j;
  2135. Scheme_Object *var, *val;
  2136. e = GetEnvironmentStringsW();
  2137. for (i = 0; e[i]; ) {
  2138. start = i;
  2139. while (e[i]) { i++; }
  2140. p = NARROW_PATH(e XFORM_OK_PLUS start);
  2141. for (j = 0; p[j] && p[j] != '='; j++) {
  2142. }
  2143. if (j && p[j]) {
  2144. var = scheme_make_immutable_sized_byte_string(p, j, 1);
  2145. val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1);
  2146. var = normalize_env_case(var);
  2147. ht = scheme_hash_tree_set(ht, var, val);
  2148. }
  2149. i++;
  2150. }
  2151. FreeEnvironmentStringsW(e);
  2152. }
  2153. #else
  2154. {
  2155. int i, j;
  2156. char **ea, *p;
  2157. Scheme_Object *var, *val;
  2158. ea = GET_ENVIRON_ARRAY;
  2159. for (i = 0; ea[i]; i++) {
  2160. p = ea[i];
  2161. for (j = 0; p[j] && p[j] != '='; j++) {
  2162. }
  2163. if (p[j]) {
  2164. var = scheme_make_immutable_sized_byte_string(p, j, 1);
  2165. val = scheme_make_immutable_sized_byte_string(p XFORM_OK_PLUS j + 1, -1, 1);
  2166. ht = scheme_hash_tree_set(ht, var, val);
  2167. }
  2168. }
  2169. }
  2170. #endif
  2171. return scheme_make_environment_variables(ht);
  2172. }
  2173. static Scheme_Object *env_make(int argc, Scheme_Object *argv[])
  2174. {
  2175. Scheme_Hash_Tree *ht;
  2176. Scheme_Object *varbs, *valbs;
  2177. int i;
  2178. ht = scheme_make_hash_tree(1);
  2179. for (i = 0; i < argc; i += 2) {
  2180. varbs = argv[i];
  2181. if (!SCHEME_BYTE_STRINGP(varbs)
  2182. || !byte_string_ok_name(varbs))
  2183. scheme_wrong_contract("make-environment-variables", "bytes-environment-variable-name?", i, argc, argv);
  2184. if (i+1 >= argc) {
  2185. scheme_contract_error("make-environment-variables",
  2186. "key does not have a value (i.e., an odd number of arguments were provided)",
  2187. "key", 1, argv[i],
  2188. NULL);
  2189. return NULL;
  2190. }
  2191. valbs = argv[i+1];
  2192. if (!SCHEME_FALSEP(valbs)
  2193. && (!SCHEME_BYTE_STRINGP(valbs)
  2194. || scheme_byte_string_has_null(valbs)))
  2195. scheme_wrong_contract("make-environment-variables", "(or/c bytes-no-nuls? #f)", i+1, argc, argv);
  2196. varbs = normalize_env_case(varbs);
  2197. varbs = byte_string_to_immutable(1, &varbs);
  2198. valbs = byte_string_to_immutable(1, &valbs);
  2199. ht = scheme_hash_tree_set(ht, varbs, valbs);
  2200. }
  2201. return scheme_make_environment_variables(ht);
  2202. }
  2203. static Scheme_Object *sch_getenv_names(int argc, Scheme_Object *argv[])
  2204. {
  2205. Scheme_Object *ev, *r = scheme_null, *key, *val;
  2206. Scheme_Hash_Tree *ht;
  2207. int i;
  2208. ev = argv[0];
  2209. if (!SAME_TYPE(SCHEME_TYPE(ev), scheme_environment_variables_type))
  2210. scheme_wrong_contract("environment-variables-names", "environment-variables?", 0, argc, argv);
  2211. ht = SCHEME_ENVVARS_TABLE(ev);
  2212. if (!ht) {
  2213. ev = env_copy(1, argv);
  2214. ht = SCHEME_ENVVARS_TABLE(ev);
  2215. }
  2216. for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
  2217. scheme_hash_tree_index(ht, i, &key, &val);
  2218. r = scheme_make_pair(key, r);
  2219. }
  2220. return r;
  2221. }
  2222. #ifdef DOS_FILE_SYSTEM
  2223. static int wc_strlen(const wchar_t *ws)
  2224. {
  2225. int l;
  2226. for (l =0; ws[l]; l++) { }
  2227. return l;
  2228. }
  2229. #endif
  2230. void *scheme_environment_variables_to_block(Scheme_Object *ev, int *_need_free)
  2231. {
  2232. Scheme_Hash_Tree *ht;
  2233. Scheme_Object *key, *val;
  2234. ht = SCHEME_ENVVARS_TABLE(ev);
  2235. if (!ht) {
  2236. *_need_free = 0;
  2237. #ifdef DOS_FILE_SYSTEM
  2238. return NULL;
  2239. #else
  2240. return GET_ENVIRON_ARRAY;
  2241. #endif
  2242. }
  2243. *_need_free = 1;
  2244. #ifdef DOS_FILE_SYSTEM
  2245. {
  2246. int i;
  2247. int len = 0, slen;
  2248. GC_CAN_IGNORE wchar_t *r, *s;
  2249. for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
  2250. scheme_hash_tree_index(ht, i, &key, &val);
  2251. len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(key)));
  2252. len += wc_strlen(WIDE_PATH(SCHEME_BYTE_STR_VAL(val)));
  2253. len += 2;
  2254. }
  2255. r = (wchar_t *)malloc((len + 1) * sizeof(wchar_t));
  2256. len = 0;
  2257. for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
  2258. scheme_hash_tree_index(ht, i, &key, &val);
  2259. s = WIDE_PATH(SCHEME_BYTE_STR_VAL(key));
  2260. slen = wc_strlen(s);
  2261. memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t));
  2262. len += slen;
  2263. r[len++] = '=';
  2264. s = WIDE_PATH(SCHEME_BYTE_STR_VAL(val));
  2265. slen = wc_strlen(s);
  2266. memcpy(r XFORM_OK_PLUS len, s, slen * sizeof(wchar_t));
  2267. len += slen;
  2268. r[len++] = 0;
  2269. }
  2270. r[len] = 0;
  2271. return r;
  2272. }
  2273. #else
  2274. {
  2275. GC_CAN_IGNORE char **r, *s;
  2276. intptr_t i, len = 0, slen, c;
  2277. for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
  2278. scheme_hash_tree_index(ht, i, &key, &val);
  2279. len += SCHEME_BYTE_STRLEN_VAL(key);
  2280. len += SCHEME_BYTE_STRLEN_VAL(val);
  2281. len += 2;
  2282. }
  2283. r = (char **)malloc((ht->count+1) * sizeof(char*) + len);
  2284. s = (char *)(r + (ht->count+1));
  2285. c = 0;
  2286. for (i = scheme_hash_tree_next(ht, -1); i != -1; i = scheme_hash_tree_next(ht, i)) {
  2287. scheme_hash_tree_index(ht, i, &key, &val);
  2288. r[c++] = s;
  2289. slen = SCHEME_BYTE_STRLEN_VAL(key);
  2290. memcpy(s, SCHEME_BYTE_STR_VAL(key), slen);
  2291. s[slen] = '=';
  2292. s = s XFORM_OK_PLUS (slen + 1);
  2293. slen = SCHEME_BYTE_STRLEN_VAL(val);
  2294. memcpy(s, SCHEME_BYTE_STR_VAL(val), slen);
  2295. s[slen] = 0;
  2296. s = s XFORM_OK_PLUS (slen + 1);
  2297. }
  2298. r[c] = NULL;
  2299. return r;
  2300. }
  2301. #endif
  2302. }
  2303. /***********************************************************************/
  2304. /* End Environment Variables */
  2305. /***********************************************************************/
  2306. static void machine_details(char *s);
  2307. static Scheme_Object *system_type(int argc, Scheme_Object *argv[])
  2308. {
  2309. if (argc) {
  2310. if (SAME_OBJ(argv[0], link_symbol)) {
  2311. #if defined(OS_X) && !defined(XONX)
  2312. return scheme_intern_symbol("framework");
  2313. #else
  2314. # ifdef DOS_FILE_SYSTEM
  2315. return scheme_intern_symbol("dll");
  2316. # else
  2317. # ifdef MZ_USES_SHARED_LIB
  2318. return scheme_intern_symbol("shared");
  2319. # else
  2320. return scheme_intern_symbol("static");
  2321. # endif
  2322. # endif
  2323. #endif
  2324. }
  2325. if (SAME_OBJ(argv[0], machine_symbol)) {
  2326. char buff[1024];
  2327. machine_details(buff);
  2328. return scheme_make_utf8_string(buff);
  2329. }
  2330. if (SAME_OBJ(argv[0], gc_symbol)) {
  2331. #ifdef MZ_PRECISE_GC
  2332. return scheme_intern_symbol("3m");
  2333. #else
  2334. return scheme_intern_symbol("cgc");
  2335. #endif
  2336. }
  2337. if (SAME_OBJ(argv[0], so_suffix_symbol)) {
  2338. #ifdef DOS_FILE_SYSTEM
  2339. return scheme_make_byte_string(".dll");
  2340. #else
  2341. # ifdef OS_X
  2342. return scheme_make_byte_string(".dylib");
  2343. # else
  2344. # ifdef USE_CYGWIN_SO_SUFFIX
  2345. return scheme_make_byte_string(".dll");
  2346. # else
  2347. return scheme_make_byte_string(".so");
  2348. # endif
  2349. # endif
  2350. #endif
  2351. }
  2352. if (SAME_OBJ(argv[0], so_mode_symbol)) {
  2353. #ifdef USE_DLOPEN_GLOBAL_BY_DEFAULT
  2354. return scheme_intern_symbol("global");
  2355. #else
  2356. return scheme_intern_symbol("local");
  2357. #endif
  2358. }
  2359. if (SAME_OBJ(argv[0], word_symbol)) {
  2360. return scheme_make_integer(sizeof(void*)*8);
  2361. }
  2362. if (!SAME_OBJ(argv[0], os_symbol)) {
  2363. scheme_wrong_contract("system-type", "(or/c 'os 'word 'link 'machine 'gc 'so-suffix 'so-mode 'word)", 0, argc, argv);
  2364. return NULL;
  2365. }
  2366. }
  2367. return sys_symbol;
  2368. }
  2369. static Scheme_Object *system_library_subpath(int argc, Scheme_Object *argv[])
  2370. {
  2371. if (argc > 0) {
  2372. Scheme_Object *sym;
  2373. if (SCHEME_FALSEP(argv[0]))
  2374. return platform_cgc_path;
  2375. sym = scheme_intern_symbol("cgc");
  2376. if (SAME_OBJ(sym, argv[0]))
  2377. return platform_cgc_path;
  2378. sym = scheme_intern_symbol("3m");
  2379. if (SAME_OBJ(sym, argv[0]))
  2380. return platform_3m_path;
  2381. scheme_wrong_contract("system-library-subpath", "(or/c 'cgc '3m #f)", 0, argc, argv);
  2382. return NULL;
  2383. } else {
  2384. #ifdef MZ_PRECISE_GC
  2385. return platform_3m_path;
  2386. #else
  2387. return platform_cgc_path;
  2388. #endif
  2389. }
  2390. }
  2391. const char *scheme_system_library_subpath()
  2392. {
  2393. return SCHEME_PLATFORM_LIBRARY_SUBPATH;
  2394. }
  2395. /* Our own strncpy - which would be really stupid, except the one for
  2396. the implementation in Solaris 2.6 is broken (it doesn't always stop
  2397. at the null terminator). */
  2398. int scheme_strncmp(const char *a, const char *b, int len)
  2399. {
  2400. while (len-- && (*a == *b) && *a) {
  2401. a++;
  2402. b++;
  2403. }
  2404. if (len < 0)
  2405. return 0;
  2406. else
  2407. return *a - *b;
  2408. }
  2409. static Scheme_Object *ok_cmdline(int argc, Scheme_Object **argv)
  2410. {
  2411. if (SCHEME_CHAPERONE_VECTORP(argv[0])) {
  2412. Scheme_Object *vec = argv[0], *vec2, *str;
  2413. int i, size = SCHEME_VEC_SIZE(vec);
  2414. if (!size)
  2415. return vec;
  2416. for (i = 0; i < size; i++) {
  2417. if (!SCHEME_CHAR_STRINGP(SCHEME_VEC_ELS(vec)[i]))
  2418. return NULL;
  2419. }
  2420. /* Make sure vector and strings are immutable: */
  2421. vec2 = scheme_make_vector(size, NULL);
  2422. if (size)
  2423. SCHEME_SET_VECTOR_IMMUTABLE(vec2);
  2424. for (i = 0; i < size; i++) {
  2425. str = SCHEME_VEC_ELS(vec)[i];
  2426. if (!SCHEME_IMMUTABLE_CHAR_STRINGP(str)) {
  2427. str = scheme_make_sized_char_string(SCHEME_CHAR_STR_VAL(str), SCHEME_CHAR_STRLEN_VAL(str), 0);
  2428. SCHEME_SET_CHAR_STRING_IMMUTABLE(str);
  2429. }
  2430. SCHEME_VEC_ELS(vec2)[i] = str;
  2431. }
  2432. return vec2;
  2433. }
  2434. return NULL;
  2435. }
  2436. static Scheme_Object *cmdline_args(int argc, Scheme_Object *argv[])
  2437. {
  2438. return scheme_param_config("current-command-line-arguments",
  2439. scheme_make_integer(MZCONFIG_CMDLINE_ARGS),
  2440. argc, argv,
  2441. -1, ok_cmdline, "vector of strings", 1);
  2442. }
  2443. /**********************************************************************/
  2444. /* locale ops */
  2445. /**********************************************************************/
  2446. static Scheme_Object *ok_locale(int argc, Scheme_Object **argv)
  2447. {
  2448. if (SCHEME_FALSEP(argv[0]))
  2449. return argv[0];
  2450. else if (SCHEME_CHAR_STRINGP(argv[0])) {
  2451. if (SCHEME_IMMUTABLEP(argv[0]))
  2452. return argv[0];
  2453. else {
  2454. Scheme_Object *str = argv[0];
  2455. str = scheme_make_immutable_sized_char_string(SCHEME_CHAR_STR_VAL(str), SCHEME_CHAR_STRLEN_VAL(str), 1);
  2456. return str;
  2457. }
  2458. }
  2459. return NULL;
  2460. }
  2461. static Scheme_Object *current_locale(int argc, Scheme_Object *argv[])
  2462. {
  2463. Scheme_Object *v;
  2464. v = scheme_param_config("current-locale",
  2465. scheme_make_integer(MZCONFIG_LOCALE),
  2466. argc, argv,
  2467. -1, ok_locale, "#f or string", 1);
  2468. return v;
  2469. }
  2470. static Scheme_Object *locale_string_encoding(int argc, Scheme_Object *argv[])
  2471. {
  2472. reset_locale();
  2473. if (mzLOCALE_IS_UTF_8(current_locale_name) || !locale_on)
  2474. return scheme_make_utf8_string("UTF-8");
  2475. #if HAVE_CODESET
  2476. return scheme_make_utf8_string(nl_langinfo(CODESET));
  2477. #else
  2478. /* nl_langinfo doesn't work, so just make up something */
  2479. return scheme_make_utf8_string("UTF-8");
  2480. #endif
  2481. }
  2482. static Scheme_Object *system_language_country(int argc, Scheme_Object *argv[])
  2483. {
  2484. #ifdef MACOS_UNICODE_SUPPORT
  2485. /* Mac OS X */
  2486. CFLocaleRef l;
  2487. CFStringRef s;
  2488. int len;
  2489. char *r;
  2490. l = CFLocaleCopyCurrent();
  2491. s = CFLocaleGetIdentifier(l);
  2492. len = CFStringGetLength(s);
  2493. r = (char *)scheme_malloc_atomic(len * 6 + 1);
  2494. CFStringGetCString(s, r, len * 6 + 1, kCFStringEncodingUTF8);
  2495. CFRelease(l);
  2496. return scheme_make_sized_utf8_string(r, 5);
  2497. #else
  2498. # ifdef WINDOWS_UNICODE_SUPPORT
  2499. /* Windows */
  2500. LCID l;
  2501. int llen, clen;
  2502. char *lang, *country, *s;
  2503. l = GetUserDefaultLCID();
  2504. llen = GetLocaleInfo(l, LOCALE_SENGLANGUAGE, NULL, 0);
  2505. lang = (char *)scheme_malloc_atomic(llen);
  2506. GetLocaleInfo(l, LOCALE_SENGLANGUAGE, lang, llen);
  2507. if (llen)
  2508. llen -= 1; /* drop nul terminator */
  2509. clen = GetLocaleInfo(l, LOCALE_SENGCOUNTRY, NULL, 0);
  2510. country = (char *)scheme_malloc_atomic(clen);
  2511. GetLocaleInfo(l, LOCALE_SENGCOUNTRY, country, clen);
  2512. if (clen)
  2513. clen -= 1; /* drop nul terminator */
  2514. s = (char *)scheme_malloc_atomic(clen + llen + 1);
  2515. memcpy(s, lang, llen);
  2516. memcpy(s + 1 + llen, country, clen);
  2517. s[llen] = '_';
  2518. return scheme_make_sized_utf8_string(s, llen + 1 + clen);
  2519. # else
  2520. /* Unix */
  2521. char *s;
  2522. s = getenv("LC_ALL");
  2523. if (!s)
  2524. s = getenv("LC_CTYPE");
  2525. if (!s)
  2526. s = getenv("LANG");
  2527. if (s) {
  2528. /* Check that the environment variable has the form
  2529. xx_XX[.ENC] */
  2530. if ((s[0] >= 'a') && (s[0] <= 'z')
  2531. && (s[1] >= 'a') && (s[1] <= 'z')
  2532. && (s[2] == '_')
  2533. && (s[3] >= 'A') && (s[3] <= 'Z')
  2534. && (s[4] >= 'A') && (s[4] <= 'Z')
  2535. && (!s[5] || s[5] == '.')) {
  2536. /* Good */
  2537. } else
  2538. s = NULL;
  2539. }
  2540. if (!s)
  2541. s = "en_US";
  2542. return scheme_make_sized_utf8_string(s, 5);
  2543. # endif
  2544. #endif
  2545. }
  2546. #ifndef DONT_USE_LOCALE
  2547. #define ICONV_ARG_CAST /* empty */
  2548. static char *do_convert(iconv_t cd,
  2549. /* if cd == -1 and either from_e or to_e can be NULL, then
  2550. reset_locale() must have been called */
  2551. const char *from_e, const char *to_e,
  2552. /* 1 => UCS-4 -> UTF-8; 2 => UTF-8 -> UCS-4; 0 => other */
  2553. int to_from_utf8,
  2554. /* in can be NULL to output just a shift; in that case,
  2555. id should be 0, too */
  2556. char *in, int id, int iilen,
  2557. char *out, int od, int iolen,
  2558. /* if grow, then reallocate when out isn't big enough */
  2559. int grow,
  2560. /* if add_end_shift, add a shift sequence to the end;
  2561. not useful if in is already NULL to indicate a shift */
  2562. int add_end_shift,
  2563. /* extra specifies the length of a terminator,
  2564. not included in iolen or *oolen */
  2565. int extra,
  2566. /* these two report actual read/wrote sizes: */
  2567. intptr_t *oilen, intptr_t *oolen,
  2568. /* status is set to
  2569. 0 for complete,
  2570. -1 for partial input,
  2571. -2 for error,
  2572. 1 for more avail */
  2573. int *status)
  2574. {
  2575. int dip, dop, close_it = 0, mz_utf8 = 0;
  2576. size_t il, ol, r;
  2577. GC_CAN_IGNORE char *ip, *op;
  2578. /* Defaults: */
  2579. *status = -1;
  2580. if (oilen)
  2581. *oilen = 0;
  2582. *oolen = 0;
  2583. if (cd == (iconv_t)-1) {
  2584. if (!iconv_ready) init_iconv();
  2585. if (mzCHK_PROC(iconv_open)) {
  2586. if (!from_e)
  2587. from_e = mz_iconv_nl_langinfo();
  2588. if (!to_e)
  2589. to_e = mz_iconv_nl_langinfo();
  2590. cd = iconv_open(to_e, from_e);
  2591. close_it = 1;
  2592. } else if (to_from_utf8) {
  2593. /* Assume UTF-8 */
  2594. mz_utf8 = 1;
  2595. }
  2596. }
  2597. if ((cd == (iconv_t)-1) && !mz_utf8) {
  2598. if (out) {
  2599. while (extra--) {
  2600. out[extra] = 0;
  2601. }
  2602. }
  2603. return out;
  2604. }
  2605. /* The converter is ready. Allocate out space, if necessary */
  2606. if (!out) {
  2607. if (iolen <= 0)
  2608. iolen = iilen;
  2609. out = (char *)scheme_malloc_atomic(iolen + extra);
  2610. od = 0;
  2611. }
  2612. /* il and ol are the number of available chars */
  2613. il = iilen;
  2614. ol = iolen;
  2615. /* dip and dop are the number of characters read so far;
  2616. we use these and NULL out the ip and op pointers
  2617. for the sake of precise GC */
  2618. dip = 0;
  2619. dop = 0;
  2620. if (!in)
  2621. add_end_shift = 0;
  2622. while (1) {
  2623. int icerr;
  2624. if (mz_utf8) {
  2625. /* Use our UTF-8 routines as if they were iconv */
  2626. if (to_from_utf8 == 1) {
  2627. /* UCS-4 -> UTF-8 */
  2628. /* We assume that in + id and iilen are mzchar-aligned */
  2629. int opos, uid, uilen;
  2630. uid = (id + dip) >> 2;
  2631. uilen = (iilen - dip) >> 2;
  2632. opos = scheme_utf8_encode((const unsigned int *)in, uid, uilen,
  2633. NULL, 0,
  2634. 0);
  2635. if (opos <= iolen) {
  2636. opos = scheme_utf8_encode((const unsigned int *)in, uid, uilen,
  2637. (unsigned char *)out, od + dop,
  2638. 0);
  2639. dop += opos;
  2640. dip += iilen;
  2641. icerr = 0;
  2642. r = (size_t)opos;
  2643. } else {
  2644. icerr = E2BIG;
  2645. r = (size_t)-1;
  2646. }
  2647. } else {
  2648. /* UTF-8 -> UCS-4 */
  2649. /* We assume that out + od is mzchar-aligned */
  2650. intptr_t ipos, opos;
  2651. r = utf8_decode_x((unsigned char *)in, id + dip, iilen,
  2652. (unsigned int *)out, (od + dop) >> 2, iolen >> 2,
  2653. &ipos, &opos,
  2654. 0, 0, NULL, 0, 0);
  2655. opos <<= 2;
  2656. dop = (opos - od);
  2657. dip = (ipos - id);
  2658. if ((r == -1) || (r == -2)) {
  2659. r = (size_t)-1;
  2660. icerr = EILSEQ;
  2661. } else if (r == -3) {
  2662. icerr = E2BIG;
  2663. r = (size_t)-1;
  2664. } else
  2665. icerr = 0;
  2666. }
  2667. } else {
  2668. ip = in XFORM_OK_PLUS id + dip;
  2669. op = out XFORM_OK_PLUS od + dop;
  2670. r = iconv(cd, ICONV_ARG_CAST &ip, &il, &op, &ol);
  2671. dip = ip - (in XFORM_OK_PLUS id);
  2672. dop = op - (out XFORM_OK_PLUS od);
  2673. ip = op = NULL;
  2674. icerr = ICONV_errno;
  2675. }
  2676. /* Record how many chars processed, now */
  2677. if (oilen)
  2678. *oilen = dip;
  2679. *oolen = dop;
  2680. /* Got all the chars? */
  2681. if (r == (size_t)-1) {
  2682. if (icerr == E2BIG) {
  2683. if (grow) {
  2684. /* Double the string size and try again */
  2685. char *naya;
  2686. naya = (char *)scheme_malloc_atomic((iolen * 2) + extra);
  2687. memcpy(naya, out + od, *oolen);
  2688. ol += iolen;
  2689. iolen += iolen;
  2690. out = naya;
  2691. od = 0;
  2692. } else {
  2693. *status = 1;
  2694. if (close_it)
  2695. iconv_close(cd);
  2696. while (extra--) {
  2697. out[od + dop + extra] = 0;
  2698. }
  2699. return out;
  2700. }
  2701. } else {
  2702. /* Either EINVAL (premature end) or EILSEQ (bad sequence) */
  2703. if (icerr == EILSEQ)
  2704. *status = -2;
  2705. if (close_it)
  2706. iconv_close(cd);
  2707. while (extra--) {
  2708. out[od + dop + extra] = 0;
  2709. }
  2710. return out;
  2711. }
  2712. } else {
  2713. /* All done... */
  2714. if (add_end_shift) {
  2715. add_end_shift = 0;
  2716. in = NULL;
  2717. dip = 0;
  2718. id = 0;
  2719. il = 0; /* should be redundant */
  2720. oilen = NULL; /* so it doesn't get set to 0 */
  2721. } else {
  2722. *status = 0;
  2723. if (close_it)
  2724. iconv_close(cd);
  2725. while (extra--) {
  2726. out[od + dop + extra] = 0;
  2727. }
  2728. return out;
  2729. }
  2730. }
  2731. }
  2732. }
  2733. #define MZ_SC_BUF_SIZE 32
  2734. static char *string_to_from_locale(int to_bytes,
  2735. char *in, intptr_t delta, intptr_t len,
  2736. intptr_t *olen, int perm,
  2737. int *no_cvt)
  2738. /* Call this function only when iconv is available, and only when
  2739. reset_locale() has been called */
  2740. {
  2741. Scheme_Object *parts = scheme_null, *one;
  2742. char *c;
  2743. intptr_t clen, used;
  2744. int status;
  2745. iconv_t cd;
  2746. if (!iconv_ready) init_iconv();
  2747. if (to_bytes)
  2748. cd = iconv_open(mz_iconv_nl_langinfo(), MZ_UCS4_NAME);
  2749. else
  2750. cd = iconv_open(MZ_UCS4_NAME, mz_iconv_nl_langinfo());
  2751. if (cd == (iconv_t)-1) {
  2752. *no_cvt = 1;
  2753. return NULL;
  2754. }
  2755. *no_cvt = 0;
  2756. while (len) {
  2757. /* We might have conversion errors... */
  2758. c = do_convert(cd, NULL, NULL, 0,
  2759. (char *)in, (to_bytes ? 4 : 1) * delta, (to_bytes ? 4 : 1) * len,
  2760. NULL, 0, (to_bytes ? 1 : 4) * (len + 1),
  2761. 1 /* grow */, 1, (to_bytes ? 1 : 4) /* terminator size */,
  2762. &used, &clen,
  2763. &status);
  2764. if (to_bytes)
  2765. used >>= 2;
  2766. if ((perm < 0) && (used < len)) {
  2767. iconv_close(cd);
  2768. return NULL;
  2769. }
  2770. delta += used;
  2771. len -= used;
  2772. if (!len && SCHEME_NULLP(parts)) {
  2773. if (to_bytes) {
  2774. *olen = clen;
  2775. c[*olen] = 0;
  2776. } else {
  2777. *olen = (clen >> 2);
  2778. ((mzchar *)c)[*olen] = 0;
  2779. }
  2780. iconv_close(cd);
  2781. return c;
  2782. }
  2783. /* We can get here if there was some conversion error at some
  2784. point. We're building up a list of parts. */
  2785. if (to_bytes) {
  2786. one = scheme_make_sized_byte_string(c, clen, 0);
  2787. } else {
  2788. one = scheme_make_sized_char_string((mzchar *)c, clen >> 2, 0);
  2789. }
  2790. parts = scheme_make_pair(one, parts);
  2791. if (len) {
  2792. /* Conversion error, so skip one char. */
  2793. if (to_bytes) {
  2794. char bc[1];
  2795. bc[0] = perm;
  2796. one = scheme_make_sized_byte_string(bc, 1, 1);
  2797. } else {
  2798. mzchar bc[1];
  2799. bc[0] = perm;
  2800. one = scheme_make_sized_char_string(bc, 1, 1);
  2801. }
  2802. parts = scheme_make_pair(one, parts);
  2803. delta += 1;
  2804. len -= 1;
  2805. }
  2806. }
  2807. iconv_close(cd);
  2808. if (to_bytes) {
  2809. parts = append_all_byte_strings_backwards(parts);
  2810. *olen = SCHEME_BYTE_STRTAG_VAL(parts);
  2811. return SCHEME_BYTE_STR_VAL(parts);
  2812. } else {
  2813. parts = append_all_strings_backwards(parts);
  2814. *olen = SCHEME_CHAR_STRTAG_VAL(parts);
  2815. return (char *)SCHEME_CHAR_STR_VAL(parts);
  2816. }
  2817. }
  2818. static char *locale_recase(int to_up,
  2819. /* in must be null-terminated, iilen doesn't include it */
  2820. char *in, int id, int iilen,
  2821. /* iolen, in contrast, includes the terminator */
  2822. char *out, int od, int iolen,
  2823. intptr_t *oolen)
  2824. /* Assumes that reset_locale() has been called */
  2825. {
  2826. #ifdef NO_MBTOWC_FUNCTIONS
  2827. /* No wide-char functions...
  2828. The C library's toupper and tolower is supposed to be
  2829. locale-sensitive. It can't be right for characters that are
  2830. encoded in multiple bytes, but probably it will do the right
  2831. thing in common cases. */
  2832. int i;
  2833. /* First, copy "in" to "out" */
  2834. if (iilen + 1 >= iolen) {
  2835. out = (char *)scheme_malloc_atomic(iilen + 1);
  2836. od = 0;
  2837. }
  2838. memcpy(out + od, in + id, iilen);
  2839. out[od + iilen] = 0;
  2840. *oolen = iilen;
  2841. /* Re-case chars in "out" */
  2842. for (i = 0; i < iilen; i++) {
  2843. char t;
  2844. t = (to_up) ? toupper(out[od+i]) : tolower(out[od+i]);
  2845. out[od+i] = t;
  2846. }
  2847. return out;
  2848. #else
  2849. /* To change the case, convert the string to multibyte, re-case the
  2850. multibyte, then convert back. */
  2851. # define MZ_WC_BUF_SIZE 32
  2852. GC_CAN_IGNORE mbstate_t state;
  2853. size_t wl, ml;
  2854. wchar_t *wc, *ws, wcbuf[MZ_WC_BUF_SIZE], cwc;
  2855. const char *s;
  2856. unsigned int j;
  2857. /* The "n" versions are apparently not too standard: */
  2858. # define mz_mbsnrtowcs(t, f, fl, tl, s) mbsrtowcs(t, f, tl, s)
  2859. # define mz_wcsnrtombs(t, f, fl, tl, s) wcsrtombs(t, f, tl, s)
  2860. /* ----- to wide char ---- */
  2861. /* Get length */
  2862. memset(&state, 0, sizeof(mbstate_t));
  2863. s = in XFORM_OK_PLUS id;
  2864. wl = mz_mbsnrtowcs(NULL, &s, iilen, 0, &state);
  2865. s = NULL;
  2866. /* Allocate space */
  2867. if (wl < MZ_WC_BUF_SIZE) {
  2868. wc = wcbuf;
  2869. } else {
  2870. wc = (wchar_t *)scheme_malloc_atomic(sizeof(wchar_t) * (wl + 1));
  2871. }
  2872. /* Convert */
  2873. memset(&state, 0, sizeof(mbstate_t));
  2874. s = in XFORM_OK_PLUS id;
  2875. (void)mz_mbsnrtowcs(wc, &s, iilen, wl + 1, &state);
  2876. s = NULL;
  2877. wc[wl] = 0; /* just in case */
  2878. /* ---- re-case ---- */
  2879. if (to_up) {
  2880. for (j = 0; j < wl; j++) {
  2881. cwc = towupper(wc[j]);
  2882. wc[j] = cwc;
  2883. }
  2884. } else {
  2885. for (j = 0; j < wl; j++) {
  2886. cwc = towlower(wc[j]);
  2887. wc[j] = cwc;
  2888. }
  2889. }
  2890. /* ---- back to multibyte ---- */
  2891. /* Measure */
  2892. memset(&state, 0, sizeof(mbstate_t));
  2893. ws = wc;
  2894. ml = mz_wcsnrtombs(NULL, (const wchar_t **)&ws, wl, 0, &state);
  2895. ws = NULL;
  2896. /* Allocate space */
  2897. *oolen = ml;
  2898. if (ml + 1 >= (unsigned int)iolen) {
  2899. out = (char *)scheme_malloc_atomic(ml + 1);
  2900. od = 0;
  2901. }
  2902. /* Convert */
  2903. memset(&state, 0, sizeof(mbstate_t));
  2904. ws = wc;
  2905. (void)mz_wcsnrtombs(out + od, (const wchar_t **)&ws, wl, ml + 1, &state);
  2906. ws = NULL;
  2907. out[od + ml] = 0;
  2908. return out;
  2909. #endif
  2910. }
  2911. int mz_locale_strcoll(char *s1, int d1, int l1, char *s2, int d2, int l2, int cvt_case)
  2912. /* The s1 and s2 arguments are actually UCS-4.
  2913. Assumes that reset_locale() has been called. */
  2914. {
  2915. intptr_t clen1, clen2, used1, used2, origl1, origl2;
  2916. char *c1, *c2, buf1[MZ_SC_BUF_SIZE], buf2[MZ_SC_BUF_SIZE];
  2917. char case_buf1[MZ_SC_BUF_SIZE], case_buf2[MZ_SC_BUF_SIZE];
  2918. int status, got_more;
  2919. /* First, convert UCS-4 to locale-specific encoding. If some
  2920. characters don't fit into the encoding, then we'll have leftover
  2921. characters. Count unconvertable charc as greater than anything
  2922. that can be converted */
  2923. origl1 = l1;
  2924. origl2 = l2;
  2925. /* Loop to check both convertable and unconvertable parts */
  2926. while (1) {
  2927. if (!origl1 && !origl2)
  2928. return 0;
  2929. if (!origl1)
  2930. return -1;
  2931. if (!origl2)
  2932. return 1;
  2933. /* Loop to get consistent parts of the wto strings, in case
  2934. a conversion fails. */
  2935. got_more = 0;
  2936. l1 = origl1;
  2937. l2 = origl2;
  2938. while (1) {
  2939. c1 = do_convert((iconv_t)-1, MZ_UCS4_NAME, NULL, 1,
  2940. s1, d1 * 4, 4 * l1,
  2941. buf1, 0, MZ_SC_BUF_SIZE - 1,
  2942. 1 /* grow */, 0, 1 /* terminator size */,
  2943. &used1, &clen1,
  2944. &status);
  2945. c2 = do_convert((iconv_t)-1, MZ_UCS4_NAME, NULL, 1,
  2946. s2, d2 * 4, 4 * l2,
  2947. buf2, 0, MZ_SC_BUF_SIZE - 1,
  2948. 1 /* grow */, 0, 1 /* terminator size */,
  2949. &used2, &clen2,
  2950. &status);
  2951. if ((used1 < 4 * l1) || (used2 < 4 * l2)) {
  2952. if (got_more) {
  2953. /* Something went wrong. We've already tried to
  2954. even out the parts that work. Let's give up
  2955. on the first characters */
  2956. clen1 = clen2 = 0;
  2957. break;
  2958. } else if (used1 == used2) {
  2959. /* Not everything, but both ended at the same point */
  2960. break;
  2961. } else {
  2962. /* Pick the smallest */
  2963. if (used2 < used1) {
  2964. used1 = used2;
  2965. got_more = 1;
  2966. } else
  2967. got_more = 2;
  2968. l2 = (used1 >> 2);
  2969. l1 = (used1 >> 2);
  2970. if (!l1) {
  2971. /* Nothing to get this time. */
  2972. clen1 = clen2 = 0;
  2973. c1 = c2 = "";
  2974. used1 = used2 = 0;
  2975. break;
  2976. }
  2977. }
  2978. } else
  2979. /* Got all that we wanted */
  2980. break;
  2981. }
  2982. if (cvt_case) {
  2983. if (clen1)
  2984. c1 = locale_recase(0, c1, 0, clen1,
  2985. case_buf1, 0, MZ_SC_BUF_SIZE - 1,
  2986. &clen1);
  2987. else
  2988. c1 = NULL;
  2989. if (clen2)
  2990. c2 = locale_recase(0, c2, 0, clen2,
  2991. case_buf2, 0, MZ_SC_BUF_SIZE - 1,
  2992. &clen2);
  2993. else
  2994. c2 = NULL;
  2995. /* There shouldn't have been conversion errors, but just in
  2996. case, care of NULL. */
  2997. if (!c1) c1 = "";
  2998. if (!c2) c2 = "";
  2999. }
  3000. /* Collate, finally. */
  3001. status = strcoll(c1, c2);
  3002. /* If one is bigger than the other, we're done. */
  3003. if (status)
  3004. return status;
  3005. /* Otherwise, is there more to check? */
  3006. origl1 -= (used1 >> 2);
  3007. origl2 -= (used2 >> 2);
  3008. d1 += (used1 >> 2);
  3009. d2 += (used2 >> 2);
  3010. if (!origl1 && !origl2)
  3011. return 0;
  3012. /* There's more. It must be that the next character wasn't
  3013. convertable in one of the encodings. */
  3014. if (got_more)
  3015. return ((got_more == 2) ? 1 : -1);
  3016. if (!origl1)
  3017. return -1;
  3018. /* Compare an unconverable character directly. No case conversions
  3019. if it's outside the locale. */
  3020. if (((unsigned int *)s1)[d1] > ((unsigned int *)s2)[d2])
  3021. return 1;
  3022. else if (((unsigned int *)s1)[d1] < ((unsigned int *)s2)[d2])
  3023. return -1;
  3024. else {
  3025. /* We've skipped one unconvertable char, and they still look the
  3026. same. Now try again. */
  3027. origl1 -= 1;
  3028. origl2 -= 1;
  3029. d1 += 1;
  3030. d2 += 1;
  3031. }
  3032. }
  3033. }
  3034. #ifdef MACOS_UNICODE_SUPPORT
  3035. int mz_native_strcoll(char *s1, int d1, int l1, char *s2, int d2, int l2, int cvt_case)
  3036. /* The s1 and s2 arguments are actually UTF-16. */
  3037. {
  3038. CFStringRef str1, str2;
  3039. CFComparisonResult r;
  3040. str1 = CFStringCreateWithBytes(NULL, (unsigned char *)s1 XFORM_OK_PLUS (d1 * 2), (l1 * 2),
  3041. kCFStringEncodingUnicode, FALSE);
  3042. str2 = CFStringCreateWithBytes(NULL, (unsigned char *)s2 XFORM_OK_PLUS (d2 * 2), (l2 * 2),
  3043. kCFStringEncodingUnicode, FALSE);
  3044. r = CFStringCompare(str1, str2, (kCFCompareLocalized
  3045. | (cvt_case ? kCFCompareCaseInsensitive : 0)));
  3046. CFRelease(str1);
  3047. CFRelease(str2);
  3048. return (int)r;
  3049. }
  3050. #endif
  3051. #ifdef WINDOWS_UNICODE_SUPPORT
  3052. int mz_native_strcoll(char *s1, int d1, int l1, char *s2, int d2, int l2, int cvt_case)
  3053. /* The s1 and s2 arguments are actually UTF-16. */
  3054. {
  3055. int r;
  3056. r = CompareStringW(LOCALE_USER_DEFAULT,
  3057. ((cvt_case ? NORM_IGNORECASE : 0)
  3058. | NORM_IGNOREKANATYPE
  3059. | NORM_IGNOREWIDTH),
  3060. (wchar_t *)s1 + d1, l1, (wchar_t *)s2 + d2, l2);
  3061. return r - 2;
  3062. }
  3063. #endif
  3064. typedef int (*strcoll_proc)(char *s1, int d1, int l1, char *s2, int d2, int l2, int cvt_case);
  3065. int do_locale_comp(const char *who, const mzchar *us1, intptr_t ul1, const mzchar *us2, intptr_t ul2, int cvt_case)
  3066. {
  3067. int xl1;
  3068. int v, endres, utf16 = 0;
  3069. GC_CAN_IGNORE strcoll_proc mz_strcoll = mz_locale_strcoll;
  3070. #if defined(MACOS_UNICODE_SUPPORT) || defined(WINDOWS_UNICODE_SUPPORT)
  3071. if (current_locale_name && !*current_locale_name) {
  3072. utf16 = 1;
  3073. mz_strcoll = mz_native_strcoll;
  3074. }
  3075. #endif
  3076. if (utf16) {
  3077. us1 = (mzchar *)scheme_ucs4_to_utf16(us1, 0, ul1, NULL, 0, &ul1, 1);
  3078. us2 = (mzchar *)scheme_ucs4_to_utf16(us2, 0, ul2, NULL, 0, &ul2, 1);
  3079. ((short *)us1)[ul1] = 0;
  3080. ((short *)us2)[ul2] = 0;
  3081. }
  3082. if (ul1 > ul2) {
  3083. ul1 = ul2;
  3084. endres = 1;
  3085. } else {
  3086. if (ul2 > ul1)
  3087. endres = -1;
  3088. else
  3089. endres = 0;
  3090. }
  3091. /* Walk back through the strings looking for nul characters. If we
  3092. find one, compare the part after the null character to update
  3093. endres, then continue. Unfortunately, we do too much work if an
  3094. earlier part of the string (tested later) determines the result,
  3095. but hopefully nul characters are rare. */
  3096. xl1 = 0;
  3097. while (ul1--) {
  3098. if ((utf16 && (!(((short *)us1)[ul1]) || !(((short *)us2)[ul1])))
  3099. || (!utf16 && (!(us1[ul1]) || !(us2[ul1])))) {
  3100. if (utf16) {
  3101. if (((short *)us1)[ul1])
  3102. endres = 1;
  3103. else if (((short *)us2)[ul1])
  3104. endres = -1;
  3105. } else {
  3106. if (us1[ul1])
  3107. endres = 1;
  3108. else if (us2[ul1])
  3109. endres = -1;
  3110. }
  3111. if (xl1)
  3112. v = mz_strcoll((char *)us1, ul1 + 1, xl1, (char *)us2, ul1 + 1, xl1, cvt_case);
  3113. else
  3114. v = 0;
  3115. if (v)
  3116. endres = v;
  3117. xl1 = 0;
  3118. } else {
  3119. xl1++;
  3120. }
  3121. }
  3122. v = mz_strcoll((char *)us1, 0, xl1, (char *)us2, 0, xl1, cvt_case);
  3123. if (v)
  3124. endres = v;
  3125. return endres;
  3126. }
  3127. mzchar *do_locale_recase(int to_up, mzchar *in, int delta, int len, intptr_t *olen)
  3128. {
  3129. Scheme_Object *parts = scheme_null;
  3130. char *c, buf[MZ_SC_BUF_SIZE], case_buf[MZ_SC_BUF_SIZE];
  3131. intptr_t clen, used;
  3132. int status;
  3133. while (len) {
  3134. /* We might have conversion errors... */
  3135. c = do_convert((iconv_t)-1, MZ_UCS4_NAME, NULL, 1,
  3136. (char *)in, 4 * delta, 4 * len,
  3137. buf, 0, MZ_SC_BUF_SIZE - 1,
  3138. 1 /* grow */, 0, 1 /* terminator size */,
  3139. &used, &clen,
  3140. &status);
  3141. used >>= 2;
  3142. delta += used;
  3143. len -= used;
  3144. c = locale_recase(to_up, c, 0, clen,
  3145. case_buf, 0, MZ_SC_BUF_SIZE - 1,
  3146. &clen);
  3147. if (!c)
  3148. clen = 0;
  3149. c = do_convert((iconv_t)-1, NULL, MZ_UCS4_NAME, 2,
  3150. c, 0, clen,
  3151. NULL, 0, 0,
  3152. 1 /* grow */, 0, sizeof(mzchar) /* terminator size */,
  3153. &used, &clen,
  3154. &status);
  3155. if (!len && SCHEME_NULLP(parts)) {
  3156. *olen = (clen >> 2);
  3157. ((mzchar *)c)[*olen] = 0;
  3158. return (mzchar *)c;
  3159. }
  3160. /* We can get here if there was some conversion error at some
  3161. point. We're building up a list of parts. */
  3162. parts = scheme_make_pair(scheme_make_sized_char_string((mzchar *)c, clen >> 2, 0),
  3163. parts);
  3164. if (len) {
  3165. /* Conversion error, so skip one char. */
  3166. parts = scheme_make_pair(scheme_make_sized_offset_char_string(in, delta, 1, 1),
  3167. parts);
  3168. delta += 1;
  3169. len -= 1;
  3170. }
  3171. }
  3172. parts = append_all_strings_backwards(parts);
  3173. *olen = SCHEME_CHAR_STRTAG_VAL(parts);
  3174. return SCHEME_CHAR_STR_VAL(parts);
  3175. }
  3176. #ifdef MACOS_UNICODE_SUPPORT
  3177. mzchar *do_native_recase(int to_up, mzchar *in, int delta, int len, intptr_t *olen)
  3178. /* The in argument is actually UTF-16. */
  3179. {
  3180. CFMutableStringRef mstr;
  3181. CFStringRef str;
  3182. GC_CAN_IGNORE CFRange rng;
  3183. char *result;
  3184. str = CFStringCreateWithBytes(NULL, ((unsigned char *)in) XFORM_OK_PLUS (delta * 2), (len * 2),
  3185. kCFStringEncodingUnicode, FALSE);
  3186. mstr = CFStringCreateMutableCopy(NULL, 0, str);
  3187. CFRelease(str);
  3188. if (to_up)
  3189. CFStringUppercase(mstr, NULL);
  3190. else
  3191. CFStringLowercase(mstr, NULL);
  3192. len = CFStringGetLength(mstr);
  3193. *olen = len;
  3194. result = (char *)scheme_malloc_atomic((len + 1) * 2);
  3195. rng = CFRangeMake(0, len);
  3196. CFStringGetCharacters(mstr, rng, (UniChar *)result);
  3197. CFRelease(mstr);
  3198. ((UniChar *)result)[len] = 0;
  3199. return (mzchar *)result;
  3200. }
  3201. #endif
  3202. #ifdef WINDOWS_UNICODE_SUPPORT
  3203. mzchar *do_native_recase(int to_up, mzchar *in, int delta, int len, intptr_t *olen)
  3204. /* The in argument is actually UTF-16. */
  3205. {
  3206. char *result;
  3207. result = (char *)scheme_malloc_atomic((len + 1) * 2);
  3208. memcpy(result, ((char *)in) + (2 * delta), len * 2);
  3209. ((wchar_t*)result)[len] = 0;
  3210. if (to_up)
  3211. CharUpperBuffW((wchar_t *)result, len);
  3212. else
  3213. CharLowerBuffW((wchar_t *)result, len);
  3214. *olen = len;
  3215. return (mzchar *)result;
  3216. }
  3217. #endif
  3218. typedef mzchar *(*recase_proc)(int to_up, mzchar *in, int delta, int len, intptr_t *olen);
  3219. static Scheme_Object *mz_recase(const char *who, int to_up, mzchar *us, intptr_t ulen)
  3220. {
  3221. intptr_t ulen1;
  3222. int utf16 = 0, i, delta = 0;
  3223. mzchar *us1;
  3224. recase_proc mz_do_recase = do_locale_recase;
  3225. Scheme_Object *s, *parts = scheme_null;
  3226. reset_locale();
  3227. #if defined(MACOS_UNICODE_SUPPORT) || defined(WINDOWS_UNICODE_SUPPORT)
  3228. if (current_locale_name && !*current_locale_name) {
  3229. utf16 = 1;
  3230. mz_do_recase = do_native_recase;
  3231. }
  3232. #endif
  3233. if (utf16) {
  3234. us = (mzchar *)scheme_ucs4_to_utf16(us, 0, ulen, NULL, 0, &ulen, 1);
  3235. ((short *)us)[ulen] = 0;
  3236. }
  3237. /* If there are nulls in the string, then we have to make multiple
  3238. calls to mz_do_recase */
  3239. i = 0;
  3240. while (1) {
  3241. for (; i < ulen; i++) {
  3242. if (utf16) {
  3243. if (!((short *)us)[i])
  3244. break;
  3245. } else if (!us[i])
  3246. break;
  3247. }
  3248. us1 = mz_do_recase(to_up, us, delta, i - delta, &ulen1);
  3249. if (utf16) {
  3250. us1 = scheme_utf16_to_ucs4((unsigned short *)us1, 0, ulen1, NULL, 0, &ulen1, 1);
  3251. us1[ulen1] = 0;
  3252. }
  3253. s = scheme_make_sized_char_string((mzchar *)us1, ulen1, 0);
  3254. if (SCHEME_NULLP(parts) && (i == ulen))
  3255. return s;
  3256. parts = scheme_make_pair(s, parts);
  3257. if (i == ulen)
  3258. break;
  3259. /* upcasing and encoding a nul char is easy: */
  3260. s = scheme_make_sized_char_string((mzchar *)"\0\0\0\0", 1, 0);
  3261. parts = scheme_make_pair(s, parts);
  3262. i++;
  3263. delta = i;
  3264. if (i == ulen)
  3265. break;
  3266. }
  3267. return append_all_strings_backwards(parts);
  3268. }
  3269. #endif
  3270. static Scheme_Object *
  3271. unicode_recase(const char *who, int to_up, int argc, Scheme_Object *argv[])
  3272. {
  3273. intptr_t len;
  3274. mzchar *chars;
  3275. if (!SCHEME_CHAR_STRINGP(argv[0]))
  3276. scheme_wrong_contract(who, "string?", 0, argc, argv);
  3277. chars = SCHEME_CHAR_STR_VAL(argv[0]);
  3278. len = SCHEME_CHAR_STRTAG_VAL(argv[0]);
  3279. return mz_recase(who, to_up, chars, len);
  3280. }
  3281. static Scheme_Object *
  3282. string_locale_upcase(int argc, Scheme_Object *argv[])
  3283. {
  3284. return unicode_recase("string-locale-upcase", 1, argc, argv);
  3285. }
  3286. static Scheme_Object *
  3287. string_locale_downcase(int argc, Scheme_Object *argv[])
  3288. {
  3289. return unicode_recase("string-locale-downcase", 0, argc, argv);
  3290. }
  3291. static void reset_locale(void)
  3292. {
  3293. Scheme_Object *v;
  3294. const mzchar *name;
  3295. /* This function needs to work before threads are set up: */
  3296. if (scheme_current_thread) {
  3297. v = scheme_get_param(scheme_current_config(), MZCONFIG_LOCALE);
  3298. } else {
  3299. v = scheme_make_immutable_sized_utf8_string("", 0);
  3300. }
  3301. locale_on = SCHEME_TRUEP(v);
  3302. if (locale_on) {
  3303. name = SCHEME_CHAR_STR_VAL(v);
  3304. #ifndef DONT_USE_LOCALE
  3305. if ((current_locale_name != name)
  3306. && (!current_locale_name
  3307. || mz_char_strcmp("result-locale",
  3308. current_locale_name, scheme_char_strlen(current_locale_name),
  3309. name, SCHEME_CHAR_STRLEN_VAL(v),
  3310. 0, 1))) {
  3311. /* We only need CTYPE and COLLATE; two calls seem to be much
  3312. faster than one call with ALL */
  3313. char *n, buf[32];
  3314. n = scheme_utf8_encode_to_buffer(name, SCHEME_CHAR_STRLEN_VAL(v), buf, 32);
  3315. if (!setlocale(LC_CTYPE, n))
  3316. setlocale(LC_CTYPE, "C");
  3317. if (!setlocale(LC_COLLATE, n))
  3318. setlocale(LC_COLLATE, "C");
  3319. }
  3320. #endif
  3321. current_locale_name_ptr = (void *)name;
  3322. }
  3323. }
  3324. char *scheme_push_c_numeric_locale()
  3325. {
  3326. #ifndef DONT_USE_LOCALE
  3327. GC_CAN_IGNORE char *prev;
  3328. prev = setlocale(LC_NUMERIC, NULL);
  3329. if (!strcmp(prev, "C"))
  3330. return NULL;
  3331. else
  3332. return setlocale(LC_NUMERIC, "C");
  3333. #endif
  3334. }
  3335. void scheme_pop_c_numeric_locale(char *prev)
  3336. {
  3337. #ifndef DONT_USE_LOCALE
  3338. if (prev)
  3339. setlocale(LC_NUMERIC, prev);
  3340. #endif
  3341. }
  3342. static int find_special_casing(int ch)
  3343. {
  3344. /* Binary search */
  3345. int i, lo, hi, j;
  3346. i = NUM_SPECIAL_CASINGS >> 1;
  3347. lo = i;
  3348. hi = NUM_SPECIAL_CASINGS - i - 1;
  3349. while (1) {
  3350. if (uchar_special_casings[i * 10] == ch)
  3351. return i * 10;
  3352. if (uchar_special_casings[i * 10] > ch) {
  3353. j = i - lo;
  3354. i = j + (lo >> 1);
  3355. hi = lo - (i - j) - 1;
  3356. lo = i - j;
  3357. } else {
  3358. j = i + 1;
  3359. i = j + (hi >> 1);
  3360. lo = i - j;
  3361. hi = hi - (i - j) - 1;
  3362. }
  3363. }
  3364. }
  3365. static int is_final_sigma(int mode, mzchar *s, int d, int i, int len)
  3366. {
  3367. int j;
  3368. if (mode == 3)
  3369. return 1;
  3370. /* find a cased char before, skipping case-ignorable: */
  3371. for (j = i - 1; j >= d; j--) {
  3372. if (!scheme_iscaseignorable(s[j])) {
  3373. if (scheme_iscased(s[j]))
  3374. break;
  3375. else
  3376. return 0;
  3377. }
  3378. }
  3379. if (j < d)
  3380. return 0;
  3381. /* next non-case-ignorable must not be cased: */
  3382. for (j = i + 1; j < d + len; j++) {
  3383. if (!scheme_iscaseignorable(s[j])) {
  3384. return !scheme_iscased(s[j]);
  3385. }
  3386. }
  3387. return 1;
  3388. }
  3389. mzchar *scheme_string_recase(mzchar *s, int d, int len, int mode, int inplace, int *_len)
  3390. {
  3391. mzchar *t;
  3392. int i, extra = 0, pos, special = 0, td, prev_was_cased = 0, xmode = mode;
  3393. for (i = 0; i < len; i++) {
  3394. if (scheme_isspecialcasing(s[d+i])) {
  3395. pos = find_special_casing(s[d+i]);
  3396. if (!uchar_special_casings[pos + 9] || is_final_sigma(xmode, s, d, i, len)) {
  3397. special = 1;
  3398. extra += (uchar_special_casings[pos + 1 + (xmode << 1)] - 1);
  3399. }
  3400. }
  3401. if (mode == 2) {
  3402. if (!scheme_iscaseignorable(s[d+i]))
  3403. prev_was_cased = scheme_iscased(s[d+i]);
  3404. xmode = (prev_was_cased ? 0 : 2);
  3405. }
  3406. }
  3407. if (_len)
  3408. *_len = len + extra;
  3409. if (!extra && inplace) {
  3410. t = s;
  3411. td = d;
  3412. } else {
  3413. t = scheme_malloc_atomic(sizeof(mzchar) * (len + extra + 1));
  3414. td = 0;
  3415. }
  3416. if (!special) {
  3417. if (mode == 0) {
  3418. for (i = 0; i < len; i++) {
  3419. t[i+td] = scheme_tolower(s[i+d]);
  3420. }
  3421. } else if (mode == 1) {
  3422. for (i = 0; i < len; i++) {
  3423. t[i+td] = scheme_toupper(s[i+d]);
  3424. }
  3425. } else if (mode == 2) {
  3426. prev_was_cased = 0;
  3427. for (i = 0; i < len; i++) {
  3428. if (!prev_was_cased)
  3429. t[i+td] = scheme_totitle(s[i+d]);
  3430. else
  3431. t[i+td] = scheme_tolower(s[i+d]);
  3432. if (!scheme_iscaseignorable(s[i+d]))
  3433. prev_was_cased = scheme_iscased(s[i+d]);
  3434. }
  3435. } else /* if (mode == 3) */ {
  3436. for (i = 0; i < len; i++) {
  3437. t[i+td] = scheme_tofold(s[i+d]);
  3438. }
  3439. }
  3440. } else {
  3441. int j = 0, c;
  3442. prev_was_cased = 0;
  3443. for (i = 0; i < len; i++) {
  3444. if (mode == 0) {
  3445. t[j+td] = scheme_tolower(s[i+d]);
  3446. } else if (mode == 1) {
  3447. t[j+td] = scheme_toupper(s[i+d]);
  3448. } else if (mode == 2) {
  3449. if (!prev_was_cased) {
  3450. xmode = 2;
  3451. t[j+td] = scheme_totitle(s[i+d]);
  3452. } else {
  3453. xmode = 0;
  3454. t[j+td] = scheme_tolower(s[i+d]);
  3455. }
  3456. if (!scheme_iscaseignorable(s[i+d]))
  3457. prev_was_cased = scheme_iscased(s[i+d]);
  3458. } else /* if (mode == 3) */ {
  3459. t[j+td] = scheme_tofold(s[i+d]);
  3460. }
  3461. if (scheme_isspecialcasing(s[i+d])) {
  3462. pos = find_special_casing(s[i+d]);
  3463. if (!uchar_special_casings[pos + 9] || is_final_sigma(xmode, s, d, i, len)) {
  3464. c = uchar_special_casings[pos + 1 + (xmode << 1)];
  3465. pos = uchar_special_casings[pos + 2 + (xmode << 1)];
  3466. while (c--) {
  3467. t[(j++)+td] = uchar_special_casing_data[pos++];
  3468. }
  3469. } else
  3470. j++;
  3471. } else
  3472. j++;
  3473. }
  3474. }
  3475. t[len+extra+td] = 0;
  3476. return t;
  3477. }
  3478. static Scheme_Object *string_recase (const char *name, int argc, Scheme_Object *argv[], int mode)
  3479. {
  3480. mzchar *s;
  3481. int len;
  3482. if (!SCHEME_CHAR_STRINGP(argv[0]))
  3483. scheme_wrong_contract(name, "string?", 0, argc, argv);
  3484. s = SCHEME_CHAR_STR_VAL(argv[0]);
  3485. len = SCHEME_CHAR_STRLEN_VAL(argv[0]);
  3486. s = scheme_string_recase(s, 0, len, mode, 0, &len);
  3487. return scheme_make_sized_char_string(s, len, 0);
  3488. }
  3489. static Scheme_Object *string_upcase (int argc, Scheme_Object *argv[])
  3490. {
  3491. return string_recase("string-upcase", argc, argv, 1);
  3492. }
  3493. static Scheme_Object *string_downcase (int argc, Scheme_Object *argv[])
  3494. {
  3495. return string_recase("string-downcase", argc, argv, 0);
  3496. }
  3497. static Scheme_Object *string_titlecase (int argc, Scheme_Object *argv[])
  3498. {
  3499. return string_recase("string-titlecase", argc, argv, 2);
  3500. }
  3501. static Scheme_Object *string_foldcase (int argc, Scheme_Object *argv[])
  3502. {
  3503. return string_recase("string-foldcase", argc, argv, 3);
  3504. }
  3505. /**********************************************************************/
  3506. /* normalization */
  3507. /**********************************************************************/
  3508. #define MZ_JAMO_INITIAL_CONSONANT_START 0x1100
  3509. #define MZ_JAMO_INITIAL_CONSONANT_COUNT 19
  3510. #define MZ_JAMO_INITIAL_CONSONANT_END (MZ_JAMO_INITIAL_CONSONANT_START + MZ_JAMO_INITIAL_CONSONANT_COUNT - 1)
  3511. #define MZ_JAMO_VOWEL_START 0x1161
  3512. #define MZ_JAMO_VOWEL_COUNT 21
  3513. #define MZ_JAMO_VOWEL_END (MZ_JAMO_VOWEL_START + MZ_JAMO_VOWEL_COUNT - 1)
  3514. /* First in this range is not actually a consonant, but a placeholder for "no consonant" */
  3515. #define MZ_JAMO_TRAILING_CONSONANT_START 0x11A7
  3516. #define MZ_JAMO_TRAILING_CONSONANT_COUNT 28
  3517. #define MZ_JAMO_TRAILING_CONSONANT_END (MZ_JAMO_TRAILING_CONSONANT_START + MZ_JAMO_TRAILING_CONSONANT_COUNT - 1)
  3518. #define MZ_JAMO_SYLLABLE_START 0xAC00
  3519. #define MZ_JAMO_SYLLABLE_END (MZ_JAMO_SYLLABLE_START + 11171)
  3520. static mzchar get_composition(mzchar a, mzchar b)
  3521. {
  3522. uintptr_t key = (a << 16) | b;
  3523. int pos = (COMPOSE_TABLE_SIZE >> 1), new_pos;
  3524. int below_len = pos;
  3525. int above_len = (COMPOSE_TABLE_SIZE - pos - 1);
  3526. if (a > 0xFFFF) return 0;
  3527. /* Binary search: */
  3528. while (key != utable_compose_pairs[pos]) {
  3529. if (key > utable_compose_pairs[pos]) {
  3530. if (!above_len)
  3531. return 0;
  3532. new_pos = pos + (above_len >> 1) + 1;
  3533. below_len = (new_pos - pos - 1);
  3534. above_len = (above_len - below_len - 1);
  3535. pos = new_pos;
  3536. } else if (key < utable_compose_pairs[pos]) {
  3537. if (!below_len)
  3538. return 0;
  3539. new_pos = pos - ((below_len >> 1) + 1);
  3540. above_len = (pos - new_pos - 1);
  3541. below_len = (below_len - above_len - 1);
  3542. pos = new_pos;
  3543. }
  3544. }
  3545. return utable_compose_result[pos];
  3546. }
  3547. mzchar get_canon_decomposition(mzchar key, mzchar *b)
  3548. {
  3549. int pos = (DECOMPOSE_TABLE_SIZE >> 1), new_pos;
  3550. int below_len = pos;
  3551. int above_len = (DECOMPOSE_TABLE_SIZE - pos - 1);
  3552. /* Binary search: */
  3553. while (key != utable_decomp_keys[pos]) {
  3554. if (key > utable_decomp_keys[pos]) {
  3555. if (!above_len)
  3556. return 0;
  3557. new_pos = pos + (above_len >> 1) + 1;
  3558. below_len = (new_pos - pos - 1);
  3559. above_len = (above_len - below_len - 1);
  3560. pos = new_pos;
  3561. } else if (key < utable_decomp_keys[pos]) {
  3562. if (!below_len)
  3563. return 0;
  3564. new_pos = pos - ((below_len >> 1) + 1);
  3565. above_len = (pos - new_pos - 1);
  3566. below_len = (below_len - above_len - 1);
  3567. pos = new_pos;
  3568. }
  3569. }
  3570. pos = utable_decomp_indices[pos];
  3571. if (pos < 0) {
  3572. pos = -(pos + 1);
  3573. pos <<= 1;
  3574. *b = utable_compose_long_pairs[pos + 1];
  3575. return utable_compose_long_pairs[pos];
  3576. } else {
  3577. key = utable_compose_pairs[pos];
  3578. *b = (key & 0xFFFF);
  3579. return (key >> 16);
  3580. }
  3581. }
  3582. int get_kompat_decomposition(mzchar key, unsigned short **chars)
  3583. {
  3584. int pos = (KOMPAT_DECOMPOSE_TABLE_SIZE >> 1), new_pos;
  3585. int below_len = pos;
  3586. int above_len = (KOMPAT_DECOMPOSE_TABLE_SIZE - pos - 1);
  3587. /* Binary search: */
  3588. while (key != utable_kompat_decomp_keys[pos]) {
  3589. if (key > utable_kompat_decomp_keys[pos]) {
  3590. if (!above_len)
  3591. return 0;
  3592. new_pos = pos + (above_len >> 1) + 1;
  3593. below_len = (new_pos - pos - 1);
  3594. above_len = (above_len - below_len - 1);
  3595. pos = new_pos;
  3596. } else if (key < utable_kompat_decomp_keys[pos]) {
  3597. if (!below_len)
  3598. return 0;
  3599. new_pos = pos - ((below_len >> 1) + 1);
  3600. above_len = (pos - new_pos - 1);
  3601. below_len = (below_len - above_len - 1);
  3602. pos = new_pos;
  3603. }
  3604. }
  3605. *chars = utable_kompat_decomp_strs XFORM_OK_PLUS utable_kompat_decomp_indices[pos];
  3606. return utable_kompat_decomp_lens[pos];
  3607. }
  3608. static Scheme_Object *normalize_c(Scheme_Object *o)
  3609. /* Assumes then given string is in normal form D */
  3610. {
  3611. mzchar *s, *s2, tmp, last_c0 = 0;
  3612. int len, i, j = 0, last_c0_pos = 0, last_cc = 0;
  3613. s = SCHEME_CHAR_STR_VAL(o);
  3614. len = SCHEME_CHAR_STRLEN_VAL(o);
  3615. s2 = (mzchar *)scheme_malloc_atomic((len + 1) * sizeof(mzchar));
  3616. memcpy(s2, s, len * sizeof(mzchar));
  3617. for (i = 0; i < len; i++) {
  3618. if ((i + 1 < len)
  3619. && (s2[i] >= MZ_JAMO_INITIAL_CONSONANT_START)
  3620. && (s2[i] <= MZ_JAMO_INITIAL_CONSONANT_END)
  3621. && (s2[i+1] >= MZ_JAMO_VOWEL_START)
  3622. && (s2[i+1] <= MZ_JAMO_VOWEL_END)) {
  3623. /* Need Hangul composition */
  3624. if ((i + 2 < len)
  3625. && (s2[i+2] > MZ_JAMO_TRAILING_CONSONANT_START)
  3626. && (s2[i+2] <= MZ_JAMO_TRAILING_CONSONANT_END)) {
  3627. /* 3-char composition */
  3628. tmp = (MZ_JAMO_SYLLABLE_START
  3629. + ((s2[i] - MZ_JAMO_INITIAL_CONSONANT_START)
  3630. * MZ_JAMO_VOWEL_COUNT * MZ_JAMO_TRAILING_CONSONANT_COUNT)
  3631. + ((s2[i+1] - MZ_JAMO_VOWEL_START)
  3632. * MZ_JAMO_TRAILING_CONSONANT_COUNT)
  3633. + (s2[i+2] - MZ_JAMO_TRAILING_CONSONANT_START));
  3634. i += 2;
  3635. } else {
  3636. /* 2-char composition */
  3637. tmp = (MZ_JAMO_SYLLABLE_START
  3638. + ((s2[i] - MZ_JAMO_INITIAL_CONSONANT_START)
  3639. * MZ_JAMO_VOWEL_COUNT * MZ_JAMO_TRAILING_CONSONANT_COUNT)
  3640. + ((s2[i+1] - MZ_JAMO_VOWEL_START)
  3641. * MZ_JAMO_TRAILING_CONSONANT_COUNT));
  3642. i++;
  3643. }
  3644. last_c0 = tmp;
  3645. last_c0_pos = j;
  3646. last_cc = 0;
  3647. s2[j++] = tmp;
  3648. } else {
  3649. int cc;
  3650. cc = scheme_combining_class(s2[i]);
  3651. if (last_c0 && (cc > last_cc))
  3652. tmp = get_composition(last_c0, s2[i]);
  3653. else
  3654. tmp = 0;
  3655. if (tmp) {
  3656. /* Need to compose */
  3657. s2[last_c0_pos] = tmp;
  3658. last_c0 = tmp;
  3659. } else if (!cc) {
  3660. /* Reset last_c0... */
  3661. tmp = s2[i];
  3662. if (scheme_needs_maybe_compose(tmp)) {
  3663. last_c0 = tmp;
  3664. last_c0_pos = j;
  3665. } else {
  3666. last_c0 = 0;
  3667. }
  3668. last_cc = -1;
  3669. s2[j++] = tmp;
  3670. } else {
  3671. s2[j++] = s2[i];
  3672. last_cc = cc;
  3673. }
  3674. }
  3675. }
  3676. s2[j] = 0;
  3677. if (len - j > 16) {
  3678. s = (mzchar *)scheme_malloc_atomic((j + 1) * sizeof(mzchar));
  3679. memcpy(s, s2, (j + 1) * sizeof(mzchar));
  3680. s2 = s;
  3681. }
  3682. return scheme_make_sized_char_string(s2, j, 0);
  3683. }
  3684. static Scheme_Object *normalize_d(Scheme_Object *o, int kompat)
  3685. {
  3686. mzchar *s, tmp, *s2;
  3687. int len, i, delta, j, swapped;
  3688. s = SCHEME_CHAR_STR_VAL(o);
  3689. len = SCHEME_CHAR_STRLEN_VAL(o);
  3690. /* Run through string list to predict expansion: */
  3691. delta = 0;
  3692. for (i = 0; i < len; i++) {
  3693. if (scheme_needs_decompose(s[i])) {
  3694. int klen;
  3695. mzchar snd;
  3696. GC_CAN_IGNORE unsigned short *start;
  3697. tmp = s[i];
  3698. while (scheme_needs_decompose(tmp)) {
  3699. if (kompat)
  3700. klen = get_kompat_decomposition(tmp, &start);
  3701. else
  3702. klen = 0;
  3703. if (klen) {
  3704. delta += (klen - 1);
  3705. break;
  3706. } else {
  3707. tmp = get_canon_decomposition(tmp, &snd);
  3708. if (tmp) {
  3709. if (snd) {
  3710. delta++;
  3711. if (kompat) {
  3712. klen = get_kompat_decomposition(snd, &start);
  3713. if (klen)
  3714. delta += (klen - 1);
  3715. }
  3716. }
  3717. } else
  3718. break;
  3719. }
  3720. }
  3721. } else if ((s[i] >= MZ_JAMO_SYLLABLE_START)
  3722. && (s[i] <= MZ_JAMO_SYLLABLE_END)) {
  3723. tmp = s[i];
  3724. tmp -= MZ_JAMO_SYLLABLE_START;
  3725. if (tmp % MZ_JAMO_TRAILING_CONSONANT_COUNT)
  3726. delta += 2;
  3727. else
  3728. delta += 1;
  3729. }
  3730. }
  3731. s2 = (mzchar *)scheme_malloc_atomic((len + delta + 1) * sizeof(mzchar));
  3732. j = 0;
  3733. for (i = 0; i < len; i++) {
  3734. if (scheme_needs_decompose(s[i])) {
  3735. mzchar snd, tmp2;
  3736. int snds = 0, klen = 0, k;
  3737. GC_CAN_IGNORE unsigned short*start;
  3738. tmp = s[i];
  3739. while (scheme_needs_decompose(tmp)) {
  3740. if (kompat)
  3741. klen = get_kompat_decomposition(tmp, &start);
  3742. else
  3743. klen = 0;
  3744. if (klen) {
  3745. for (k = 0; k < klen; k++) {
  3746. s2[j++] = start[k];
  3747. }
  3748. break;
  3749. } else {
  3750. tmp2 = get_canon_decomposition(tmp, &snd);
  3751. if (tmp2) {
  3752. tmp = tmp2;
  3753. if (snd) {
  3754. if (kompat)
  3755. klen = get_kompat_decomposition(snd, &start);
  3756. else
  3757. klen = 0;
  3758. if (klen) {
  3759. snds += klen;
  3760. for (k = 0; k < klen; k++) {
  3761. s2[len + delta - snds + k] = start[k];
  3762. }
  3763. klen = 0;
  3764. } else {
  3765. snds++;
  3766. s2[len + delta - snds] = snd;
  3767. }
  3768. }
  3769. } else
  3770. break;
  3771. }
  3772. }
  3773. if (!klen)
  3774. s2[j++] = tmp;
  3775. memcpy(s2 + j, s2 + len + delta - snds, snds * sizeof(mzchar));
  3776. j += snds;
  3777. } else if ((s[i] >= MZ_JAMO_SYLLABLE_START)
  3778. && (s[i] <= MZ_JAMO_SYLLABLE_END)) {
  3779. int l, v, t;
  3780. tmp = s[i];
  3781. tmp -= MZ_JAMO_SYLLABLE_START;
  3782. l = tmp / (MZ_JAMO_VOWEL_COUNT * MZ_JAMO_TRAILING_CONSONANT_COUNT);
  3783. v = (tmp % (MZ_JAMO_VOWEL_COUNT * MZ_JAMO_TRAILING_CONSONANT_COUNT)) / MZ_JAMO_TRAILING_CONSONANT_COUNT;
  3784. t = tmp % MZ_JAMO_TRAILING_CONSONANT_COUNT;
  3785. s2[j++] = MZ_JAMO_INITIAL_CONSONANT_START + l;
  3786. s2[j++] = MZ_JAMO_VOWEL_START + v;
  3787. if (t) {
  3788. s2[j++] = MZ_JAMO_TRAILING_CONSONANT_START + t;
  3789. }
  3790. } else {
  3791. s2[j++] = s[i];
  3792. }
  3793. }
  3794. s2[j] = 0;
  3795. len += delta;
  3796. /* Reorder pass: */
  3797. do {
  3798. swapped = 0;
  3799. for (i = 0; i < len; i++) {
  3800. if ((i + 1 < len)
  3801. && scheme_combining_class(s2[i])
  3802. && scheme_combining_class(s2[i+1])
  3803. && (scheme_combining_class(s2[i+1]) < scheme_combining_class(s2[i]))) {
  3804. /* Reorder and try again: */
  3805. tmp = s2[i + 1];
  3806. s2[i + 1] = s2[i];
  3807. s2[i] = tmp;
  3808. i--;
  3809. swapped = 1;
  3810. }
  3811. }
  3812. } while (swapped);
  3813. return scheme_make_sized_char_string(s2, len, 0);
  3814. }
  3815. static Scheme_Object *do_string_normalize_c (const char *who, int argc, Scheme_Object *argv[], int kompat)
  3816. {
  3817. Scheme_Object *o;
  3818. mzchar *s, last_c0 = 0, snd;
  3819. int len, i, last_cc = 0;
  3820. o = argv[0];
  3821. if (!SCHEME_CHAR_STRINGP(o))
  3822. scheme_wrong_contract(who, "string?", 0, argc, argv);
  3823. s = SCHEME_CHAR_STR_VAL(o);
  3824. len = SCHEME_CHAR_STRLEN_VAL(o);
  3825. for (i = 0; i < len; i++) {
  3826. if (scheme_needs_decompose(s[i])
  3827. && (kompat || get_canon_decomposition(s[i], &snd))) {
  3828. /* Decomposition may expose a different composition */
  3829. break;
  3830. } else if ((i + 1 < len)
  3831. && scheme_combining_class(s[i])
  3832. && scheme_combining_class(s[i+1])
  3833. && (scheme_combining_class(s[i+1]) < scheme_combining_class(s[i]))) {
  3834. /* Need to reorder */
  3835. break;
  3836. } else if ((s[i] >= MZ_JAMO_INITIAL_CONSONANT_START)
  3837. && (s[i] <= MZ_JAMO_INITIAL_CONSONANT_END)
  3838. && (s[i+1] >= MZ_JAMO_VOWEL_START)
  3839. && (s[i+1] <= MZ_JAMO_VOWEL_END)) {
  3840. /* Need Hangul composition */
  3841. break;
  3842. } else if (last_c0
  3843. && get_composition(last_c0, s[i])
  3844. && (scheme_combining_class(s[i]) > last_cc)) {
  3845. /* Need to compose */
  3846. break;
  3847. } else {
  3848. int cc;
  3849. cc = scheme_combining_class(s[i]);
  3850. if (!cc) {
  3851. if (scheme_needs_maybe_compose(s[i]))
  3852. last_c0 = s[i];
  3853. else
  3854. last_c0 = 0;
  3855. last_cc = -1;
  3856. } else
  3857. last_cc = cc;
  3858. }
  3859. }
  3860. if (i < len) {
  3861. o = normalize_c(normalize_d(o, kompat));
  3862. }
  3863. return o;
  3864. }
  3865. static Scheme_Object *string_normalize_c (int argc, Scheme_Object *argv[])
  3866. {
  3867. return do_string_normalize_c("string-normalize-nfc", argc, argv, 0);
  3868. }
  3869. static Scheme_Object *string_normalize_kc (int argc, Scheme_Object *argv[])
  3870. {
  3871. return do_string_normalize_c("string-normalize-nfkc", argc, argv, 1);
  3872. }
  3873. static Scheme_Object *do_string_normalize_d (const char *who, int argc, Scheme_Object *argv[], int kompat)
  3874. {
  3875. Scheme_Object *o;
  3876. mzchar *s;
  3877. int len, i;
  3878. o = argv[0];
  3879. if (!SCHEME_CHAR_STRINGP(o))
  3880. scheme_wrong_contract(who, "string?", 0, argc, argv);
  3881. s = SCHEME_CHAR_STR_VAL(o);
  3882. len = SCHEME_CHAR_STRLEN_VAL(o);
  3883. for (i = len; i--; ) {
  3884. if (scheme_needs_decompose(s[i])) {
  3885. /* Need to decompose */
  3886. mzchar snd;
  3887. if (kompat || get_canon_decomposition(s[i], &snd))
  3888. break;
  3889. } else if ((i + 1 < len)
  3890. && scheme_combining_class(s[i])
  3891. && scheme_combining_class(s[i+1])
  3892. && (scheme_combining_class(s[i+1]) < scheme_combining_class(s[i]))) {
  3893. /* Need to reorder */
  3894. break;
  3895. } else if ((s[i] >= MZ_JAMO_SYLLABLE_START)
  3896. && (s[i] <= MZ_JAMO_SYLLABLE_END)) {
  3897. /* Need Hangul decomposition */
  3898. break;
  3899. }
  3900. }
  3901. if (i >= 0) {
  3902. o = normalize_d(o, kompat);
  3903. }
  3904. return o;
  3905. }
  3906. static Scheme_Object *string_normalize_d (int argc, Scheme_Object *argv[])
  3907. {
  3908. return do_string_normalize_d("string-normalize-nfd", argc, argv, 0);
  3909. }
  3910. static Scheme_Object *string_normalize_kd (int argc, Scheme_Object *argv[])
  3911. {
  3912. return do_string_normalize_d("string-normalize-nfkd", argc, argv, 1);
  3913. }
  3914. /**********************************************************************/
  3915. /* strcmps */
  3916. /**********************************************************************/
  3917. intptr_t scheme_char_strlen(const mzchar *s)
  3918. {
  3919. intptr_t i;
  3920. for (i = 0; s[i]; i++) {
  3921. }
  3922. return i;
  3923. }
  3924. static int mz_char_strcmp(const char *who, const mzchar *str1, intptr_t l1, const mzchar *str2, intptr_t l2,
  3925. int use_locale, int size_shortcut)
  3926. {
  3927. intptr_t endres;
  3928. if (size_shortcut && (l1 != l2))
  3929. return 1;
  3930. #ifndef DONT_USE_LOCALE
  3931. if (use_locale) {
  3932. reset_locale();
  3933. if (locale_on) {
  3934. return do_locale_comp(who, str1, l1, str2, l2, 0);
  3935. }
  3936. }
  3937. #endif
  3938. if (l1 > l2) {
  3939. l1 = l2;
  3940. endres = 1;
  3941. } else {
  3942. if (l2 > l1)
  3943. endres = -1;
  3944. else
  3945. endres = 0;
  3946. }
  3947. while (l1--) {
  3948. unsigned int a, b;
  3949. a = *(str1++);
  3950. b = *(str2++);
  3951. a = a - b;
  3952. if (a)
  3953. return a;
  3954. }
  3955. return endres;
  3956. }
  3957. static int mz_char_strcmp_ci(const char *who, const mzchar *str1, intptr_t l1, const mzchar *str2, intptr_t l2,
  3958. int use_locale, int size_shortcut)
  3959. {
  3960. intptr_t p1, p2, sp1, sp2, a, b;
  3961. mzchar spec1[SPECIAL_CASE_FOLD_MAX], spec2[SPECIAL_CASE_FOLD_MAX];
  3962. if (size_shortcut && (l1 != l2))
  3963. return 1;
  3964. #ifndef DONT_USE_LOCALE
  3965. if (use_locale) {
  3966. reset_locale();
  3967. if (locale_on) {
  3968. return do_locale_comp(who, str1, l1, str2, l2, 1);
  3969. }
  3970. }
  3971. #endif
  3972. p1 = sp1 = 0;
  3973. p2 = sp2 = 0;
  3974. while (((p1 < l1) || sp1) && ((p2 < l2) || sp2)) {
  3975. if (sp1) {
  3976. a = spec1[--sp1];
  3977. } else {
  3978. a = str1[p1];
  3979. if (scheme_isspecialcasing(a)) {
  3980. int pos, i;
  3981. pos = find_special_casing(a);
  3982. sp1 = uchar_special_casings[pos + 7];
  3983. pos = uchar_special_casings[pos + 8];
  3984. for (i = sp1; i--; pos++) {
  3985. spec1[i] = uchar_special_casing_data[pos];
  3986. }
  3987. a = spec1[--sp1];
  3988. } else {
  3989. a = scheme_tofold(a);
  3990. }
  3991. p1++;
  3992. }
  3993. if (sp2) {
  3994. b = spec2[--sp2];
  3995. } else {
  3996. b = str2[p2];
  3997. if (scheme_isspecialcasing(b)) {
  3998. int pos, i;
  3999. pos = find_special_casing(b);
  4000. sp2 = uchar_special_casings[pos + 7];
  4001. pos = uchar_special_casings[pos + 8];
  4002. for (i = sp2; i--; pos++) {
  4003. spec2[i] = uchar_special_casing_data[pos];
  4004. }
  4005. b = spec2[--sp2];
  4006. } else {
  4007. b = scheme_tofold(b);
  4008. }
  4009. p2++;
  4010. }
  4011. a = a - b;
  4012. if (a)
  4013. return a;
  4014. }
  4015. return ((p1 < l1) || sp1) - ((p2 < l2) || sp2);
  4016. }
  4017. static int mz_strcmp(const char *who, unsigned char *str1, intptr_t l1, unsigned char *str2, intptr_t l2)
  4018. {
  4019. intptr_t endres;
  4020. if (l1 > l2) {
  4021. l1 = l2;
  4022. endres = 1;
  4023. } else {
  4024. if (l2 > l1)
  4025. endres = -1;
  4026. else
  4027. endres = 0;
  4028. }
  4029. while (l1--) {
  4030. unsigned int a, b;
  4031. a = *(str1++);
  4032. b = *(str2++);
  4033. a = a - b;
  4034. if (a)
  4035. return a;
  4036. }
  4037. return endres;
  4038. }
  4039. /**********************************************************************/
  4040. /* byte string conversion */
  4041. /**********************************************************************/
  4042. static void close_converter(Scheme_Object *o, void *data)
  4043. {
  4044. Scheme_Converter *c = (Scheme_Converter *)o;
  4045. if (!c->closed) {
  4046. c->closed = 1;
  4047. if (c->kind == mzICONV_KIND) {
  4048. iconv_close(c->cd);
  4049. c->cd = (iconv_t)-1;
  4050. }
  4051. if (c->mref) {
  4052. scheme_remove_managed(c->mref, (Scheme_Object *)c);
  4053. c->mref = NULL;
  4054. }
  4055. }
  4056. }
  4057. Scheme_Object *scheme_open_converter(const char *from_e, const char *to_e)
  4058. {
  4059. Scheme_Converter *c;
  4060. iconv_t cd;
  4061. int kind;
  4062. int permissive;
  4063. int need_regis = 1;
  4064. Scheme_Custodian_Reference *mref;
  4065. if (!iconv_ready) init_iconv();
  4066. if (!*to_e || !*from_e)
  4067. reset_locale();
  4068. if ((!strcmp(from_e, "UTF-8")
  4069. || !strcmp(from_e, "UTF-8-permissive")
  4070. || (!*from_e && mzLOCALE_IS_UTF_8(current_locale_name)))
  4071. && (!strcmp(to_e, "UTF-8")
  4072. || (!*to_e && mzLOCALE_IS_UTF_8(current_locale_name)))) {
  4073. /* Use the built-in UTF-8<->UTF-8 converter: */
  4074. kind = mzUTF8_KIND;
  4075. if (!strcmp(from_e, "UTF-8-permissive"))
  4076. permissive = 0xFFFD;
  4077. else
  4078. permissive = 0;
  4079. cd = (iconv_t)-1;
  4080. need_regis = (*to_e && *from_e);
  4081. } else if ((!strcmp(from_e, "platform-UTF-8")
  4082. || !strcmp(from_e, "platform-UTF-8-permissive"))
  4083. && !strcmp(to_e, "platform-UTF-16")) {
  4084. kind = mzUTF8_TO_UTF16_KIND;
  4085. if (!strcmp(from_e, "platform-UTF-8-permissive"))
  4086. permissive = 0xFFFD;
  4087. else
  4088. permissive = 0;
  4089. cd = (iconv_t)-1;
  4090. need_regis = 0;
  4091. } else if (!strcmp(from_e, "platform-UTF-16")
  4092. && !strcmp(to_e, "platform-UTF-8")) {
  4093. kind = mzUTF16_TO_UTF8_KIND;
  4094. permissive = 0;
  4095. cd = (iconv_t)-1;
  4096. need_regis = 0;
  4097. } else {
  4098. if (!iconv_ready) init_iconv();
  4099. if (!mzCHK_PROC(iconv_open))
  4100. return scheme_false;
  4101. if (!*from_e || !*to_e)
  4102. reset_locale();
  4103. if (!*from_e)
  4104. from_e = mz_iconv_nl_langinfo();
  4105. if (!*to_e)
  4106. to_e = mz_iconv_nl_langinfo();
  4107. cd = iconv_open(to_e, from_e);
  4108. if (cd == (iconv_t)-1)
  4109. return scheme_false;
  4110. kind = mzICONV_KIND;
  4111. permissive = 0;
  4112. }
  4113. c = MALLOC_ONE_TAGGED(Scheme_Converter);
  4114. c->so.type = scheme_string_converter_type;
  4115. c->closed = 0;
  4116. c->kind = kind;
  4117. c->permissive = permissive;
  4118. c->cd = cd;
  4119. if (!need_regis)
  4120. mref = NULL;
  4121. else
  4122. mref = scheme_add_managed(NULL,
  4123. (Scheme_Object *)c,
  4124. close_converter,
  4125. NULL, 1);
  4126. c->mref = mref;
  4127. return (Scheme_Object *)c;
  4128. }
  4129. static Scheme_Object *byte_string_open_converter(int argc, Scheme_Object **argv)
  4130. {
  4131. Scheme_Object *s1, *s2;
  4132. char *from_e, *to_e;
  4133. if (!SCHEME_CHAR_STRINGP(argv[0]))
  4134. scheme_wrong_contract("bytes-open-converter", "bytes?", 0, argc, argv);
  4135. if (!SCHEME_CHAR_STRINGP(argv[1]))
  4136. scheme_wrong_contract("bytes-open-converter", "bytes?", 1, argc, argv);
  4137. scheme_custodian_check_available(NULL, "bytes-open-converter", "converter");
  4138. s1 = scheme_char_string_to_byte_string(argv[0]);
  4139. s2 = scheme_char_string_to_byte_string(argv[1]);
  4140. if (scheme_byte_string_has_null(s1))
  4141. return scheme_false;
  4142. if (scheme_byte_string_has_null(s2))
  4143. return scheme_false;
  4144. from_e = SCHEME_BYTE_STR_VAL(s1);
  4145. to_e = SCHEME_BYTE_STR_VAL(s2);
  4146. return scheme_open_converter(from_e, to_e);
  4147. }
  4148. static Scheme_Object *convert_one(const char *who, int opos, int argc, Scheme_Object *argv[])
  4149. {
  4150. char *r, *instr;
  4151. int status;
  4152. intptr_t amt_read, amt_wrote;
  4153. intptr_t istart, ifinish, ostart, ofinish;
  4154. Scheme_Object *a[3], *status_sym;
  4155. Scheme_Converter *c;
  4156. if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_string_converter_type))
  4157. scheme_wrong_contract(who, "bytes-converter?", 0, argc, argv);
  4158. if (opos > 1) {
  4159. if (!SCHEME_BYTE_STRINGP(argv[1]))
  4160. scheme_wrong_contract(who, "bytes?", 1, argc, argv);
  4161. scheme_get_substring_indices(who, argv[1], argc, argv, 2, 3, &istart, &ifinish);
  4162. } else {
  4163. istart = 0;
  4164. ifinish = 4; /* This is really a guess about how much space we need for a shift terminator */
  4165. }
  4166. if (argc > opos) {
  4167. if (SCHEME_TRUEP(argv[opos])) {
  4168. if (!SCHEME_MUTABLE_BYTE_STRINGP(argv[opos]))
  4169. scheme_wrong_contract(who, "(and/c bytes? (not/c immutable?))", opos, argc, argv);
  4170. r = SCHEME_BYTE_STR_VAL(argv[opos]);
  4171. scheme_get_substring_indices(who, argv[opos], argc, argv, opos + 1, opos + 2, &ostart, &ofinish);
  4172. } else {
  4173. int ip;
  4174. r = NULL;
  4175. for (ip = opos + 1; ip <= opos + 2; ip++) {
  4176. if (argc > ip) {
  4177. int ok = 0;
  4178. if (SCHEME_INTP(argv[ip]))
  4179. ok = SCHEME_INT_VAL(argv[ip]) >= 0;
  4180. else if (SCHEME_BIGNUMP(argv[ip]))
  4181. ok = SCHEME_BIGPOS(argv[ip]);
  4182. else if ((ip == opos + 2) && SCHEME_FALSEP(argv[ip]))
  4183. ok = 1;
  4184. if (!ok)
  4185. scheme_wrong_contract(who,
  4186. ((ip == opos + 2)
  4187. ? "(or/c exact-nonnegative-integer? #f)"
  4188. : "exact-nonnegative-integer?"),
  4189. ip, argc, argv);
  4190. }
  4191. }
  4192. if ((argc > opos + 2) && SCHEME_TRUEP(argv[opos + 2])) {
  4193. Scheme_Object *delta;
  4194. if (scheme_bin_lt(argv[opos + 2], argv[opos + 1])) {
  4195. scheme_contract_error(who,
  4196. "ending index is less than the starting index",
  4197. "staring index", 1, argv[opos + 1],
  4198. "ending index", 1, argv[opos + 2],
  4199. NULL);
  4200. }
  4201. delta = scheme_bin_minus(argv[opos + 2], argv[opos + 1]);
  4202. if (SCHEME_BIGNUMP(delta))
  4203. ofinish = -1;
  4204. else
  4205. ofinish = SCHEME_INT_VAL(delta);
  4206. ostart = 0;
  4207. } else {
  4208. ostart = 0;
  4209. ofinish = -1;
  4210. }
  4211. }
  4212. } else {
  4213. r = NULL;
  4214. ostart = 0;
  4215. ofinish = -1;
  4216. }
  4217. c = (Scheme_Converter *)argv[0];
  4218. if (c->closed)
  4219. scheme_contract_error(who, "converter is closed",
  4220. "converter", 1, argv[0],
  4221. NULL);
  4222. instr = ((opos > 1) ? SCHEME_BYTE_STR_VAL(argv[1]) : NULL);
  4223. if (c->kind == mzUTF16_TO_UTF8_KIND) {
  4224. if (istart & 0x1) {
  4225. /* Copy to word-align */
  4226. char *c2;
  4227. c2 = (char *)scheme_malloc_atomic(ifinish - istart);
  4228. memcpy(c2, instr XFORM_OK_PLUS istart, ifinish - istart);
  4229. ifinish = ifinish - istart;
  4230. istart = 0;
  4231. instr = c2;
  4232. }
  4233. status = utf8_encode_x((const unsigned int *)instr, istart >> 1, ifinish >> 1,
  4234. (unsigned char *)r, ostart, ofinish,
  4235. &amt_read, &amt_wrote, 1);
  4236. amt_read -= (istart >> 1);
  4237. if (amt_read) {
  4238. if (!r) {
  4239. /* Need to allocate, then do it again: */
  4240. r = (char *)scheme_malloc_atomic(amt_wrote + 1);
  4241. utf8_encode_x((const unsigned int *)instr, istart >> 1, ifinish >> 1,
  4242. (unsigned char *)r, ostart, ofinish,
  4243. NULL, NULL, 1);
  4244. r[amt_wrote] = 0;
  4245. }
  4246. amt_read <<= 1;
  4247. }
  4248. /* We might get a -1 result because the input has an odd number of
  4249. bytes, and 2nd+next-to-last bytes form an unpaired
  4250. surrogate. In that case, the transformer normally needs one
  4251. more byte: Windows is little-endian, so we need the byte to
  4252. tell whether the surrogate is paired, and for all other
  4253. platforms (where we assume that surrogates are paired), we need
  4254. the byte to generate output. Technically, on a big-endian
  4255. non-Windows machine, we could generate the first byte of UTF-8
  4256. output and keep the byte as state, but we don't. */
  4257. if (status != -1) {
  4258. if (amt_read < ((ifinish - istart) & ~0x1)) {
  4259. /* Must have run out of output space */
  4260. status = 1;
  4261. } else {
  4262. /* Read all of input --- but it wasn't really all if there
  4263. was an odd number of bytes. */
  4264. if ((ifinish - istart) & 0x1)
  4265. status = -1;
  4266. else
  4267. status = 0;
  4268. }
  4269. }
  4270. } else if (c->kind != mzICONV_KIND) {
  4271. /* UTF-8 -> UTF-{8,16} "identity" converter, but maybe permissive */
  4272. if (instr) {
  4273. intptr_t _ostart, _ofinish;
  4274. int utf16;
  4275. if (c->kind == mzUTF8_TO_UTF16_KIND) {
  4276. _ostart = ostart;
  4277. _ofinish = ofinish;
  4278. if (_ostart & 0x1)
  4279. _ostart++;
  4280. _ostart >>= 1;
  4281. if (_ofinish > 0)
  4282. _ofinish >>= 1;
  4283. utf16 = 1;
  4284. } else {
  4285. _ostart = ostart;
  4286. _ofinish = ofinish;
  4287. utf16 = 0;
  4288. }
  4289. status = utf8_decode_x((unsigned char *)instr, istart, ifinish,
  4290. (unsigned int *)r, _ostart, _ofinish,
  4291. &amt_read, &amt_wrote,
  4292. 1, utf16, NULL, 1, c->permissive);
  4293. if (utf16) {
  4294. _ostart <<= 1;
  4295. amt_wrote <<= 1;
  4296. if ((ostart & 0x1) && (amt_wrote > _ostart)) {
  4297. /* Shift down one byte: */
  4298. memmove(r XFORM_OK_PLUS ostart, r XFORM_OK_PLUS _ostart, amt_wrote - _ostart);
  4299. }
  4300. }
  4301. amt_read -= istart;
  4302. amt_wrote -= _ostart;
  4303. if (status == -3) {
  4304. /* r is not NULL; ran out of room */
  4305. status = 1;
  4306. } else {
  4307. if (amt_wrote) {
  4308. if (!r) {
  4309. /* Need to allocate, then do it again: */
  4310. r = (char *)scheme_malloc_atomic(amt_wrote + 1);
  4311. utf8_decode_x((unsigned char *)instr, istart, ifinish,
  4312. (unsigned int *)r, ostart, _ofinish,
  4313. NULL, NULL,
  4314. 1, utf16, NULL, 1, c->permissive);
  4315. r[amt_wrote] = 0;
  4316. }
  4317. } else if (!r)
  4318. r = "";
  4319. if (status > 0)
  4320. status = 0;
  4321. }
  4322. } else {
  4323. r = "";
  4324. status = 0;
  4325. amt_read = 0;
  4326. amt_wrote = 0;
  4327. }
  4328. } else {
  4329. r = do_convert(c->cd, NULL, NULL, 0,
  4330. instr, istart, ifinish-istart,
  4331. r, ostart, ofinish-ostart,
  4332. !r, /* grow? */
  4333. 0,
  4334. (r ? 0 : 1), /* terminator */
  4335. &amt_read, &amt_wrote,
  4336. &status);
  4337. }
  4338. if (status == 0) {
  4339. /* Converted all input without error */
  4340. status_sym = complete_symbol;
  4341. } else if (status == 1) {
  4342. /* Filled output, more input ready */
  4343. status_sym = continues_symbol;
  4344. } else if (status == -1) {
  4345. /* Input ends in the middle of an encoding */
  4346. status_sym = aborts_symbol;
  4347. } else {
  4348. /* Assert: status == -2 */
  4349. /* Input has error (that won't be fixed by
  4350. adding more characters */
  4351. status_sym = error_symbol;
  4352. }
  4353. if (argc <= opos) {
  4354. a[0] = scheme_make_sized_byte_string(r, amt_wrote, 0);
  4355. } else {
  4356. a[0] = scheme_make_integer(amt_wrote);
  4357. }
  4358. if (opos > 1) {
  4359. a[1] = scheme_make_integer(amt_read);
  4360. a[2] = status_sym;
  4361. return scheme_values(3, a);
  4362. } else {
  4363. a[1] = status_sym;
  4364. return scheme_values(2, a);
  4365. }
  4366. }
  4367. static Scheme_Object *byte_string_convert(int argc, Scheme_Object *argv[])
  4368. {
  4369. return convert_one("bytes-convert", 4, argc, argv);
  4370. }
  4371. static Scheme_Object *byte_string_convert_end(int argc, Scheme_Object *argv[])
  4372. {
  4373. return convert_one("bytes-convert-end", 1, argc, argv);
  4374. }
  4375. void scheme_close_converter(Scheme_Object *conv)
  4376. {
  4377. close_converter(conv, NULL);
  4378. }
  4379. static Scheme_Object *byte_string_close_converter(int argc, Scheme_Object **argv)
  4380. {
  4381. if (!SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_string_converter_type))
  4382. scheme_wrong_contract("bytes-close-converter", "bytes-converter?", 0, argc, argv);
  4383. scheme_close_converter(argv[0]);
  4384. return scheme_void;
  4385. }
  4386. static Scheme_Object *
  4387. byte_converter_p(int argc, Scheme_Object *argv[])
  4388. {
  4389. return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_string_converter_type)
  4390. ? scheme_true
  4391. : scheme_false);
  4392. }
  4393. /**********************************************************************/
  4394. /* utf8 converter */
  4395. /**********************************************************************/
  4396. static intptr_t utf8_decode_x(const unsigned char *s, intptr_t start, intptr_t end,
  4397. unsigned int *us, intptr_t dstart, intptr_t dend,
  4398. intptr_t *ipos, intptr_t *jpos,
  4399. char compact, char utf16, int *_state,
  4400. int might_continue, int permissive)
  4401. /* Results:
  4402. non-negative => translation complete, = number of produced chars
  4403. -1 => input ended in middle of encoding (only if might_continue)
  4404. -2 => encoding error (only if permissive is 0)
  4405. -3 => not enough output room
  4406. ipos & jpos are filled with ending positions (between [d]start
  4407. and [d]end) before return, unless they are NULL.
  4408. compact => UTF-8 to UTF-8 or UTF-16 --- the latter if utf16
  4409. for Windows for utf16, decode extended UTF-8 that allows surrogates
  4410. _state provides initial state and is filled with ending state;
  4411. when it's not NULL, the us must be NULL
  4412. might_continue => allows -1 result without consuming characters
  4413. permissive is non-zero => use permissive as value for bad byte
  4414. sequences. When generating UTF-8, this must be an ASCII character
  4415. or U+FFFD. */
  4416. {
  4417. intptr_t i, j, oki;
  4418. int failmode = -3, state;
  4419. int init_doki;
  4420. int nextbits, v;
  4421. unsigned int sc;
  4422. # ifdef WINDOWS_UNICODE_SUPPORT
  4423. int pending_surrogate = 0;
  4424. # endif
  4425. if (_state) {
  4426. state = (*_state) & 0x7;
  4427. init_doki = (((*_state) >> 3) & 0x7);
  4428. nextbits = ((((*_state) >> 6) & 0xF) << 2);
  4429. /* Need v to detect 0xD800 through 0xDFFF
  4430. Note that we have 22 bits to work with, which is
  4431. is enough to detect > 0x10FFFF */
  4432. v = ((*_state) >> 10);
  4433. } else {
  4434. state = 0;
  4435. init_doki = 0;
  4436. nextbits = 0;
  4437. v = 0;
  4438. }
  4439. /* In non-permissive mode, a negative result means ill-formed input.
  4440. Permissive mode accepts anything and tries to convert it. In
  4441. that case, the strategy for illegal sequences is to convert
  4442. anything bad to the given "permissive" value. */
  4443. if (end < 0)
  4444. end = strlen((char *)s);
  4445. if (dend < 0)
  4446. dend = 0x7FFFFFFF;
  4447. # define ENCFAIL i = oki; failmode = -2; break
  4448. oki = start;
  4449. j = dstart;
  4450. i = start;
  4451. if (j < dend) {
  4452. while (i < end) {
  4453. sc = s[i];
  4454. if (sc < 0x80) {
  4455. if (state) {
  4456. /* In a sequence, but didn't continue */
  4457. state = 0;
  4458. nextbits = 0;
  4459. if (permissive) {
  4460. v = permissive;
  4461. i = oki;
  4462. j += init_doki;
  4463. } else {
  4464. ENCFAIL;
  4465. }
  4466. } else {
  4467. v = sc;
  4468. }
  4469. } else if ((sc & 0xC0) == 0x80) {
  4470. /* Continues a sequence ... */
  4471. if (state) {
  4472. /* ... and we're in one ... */
  4473. if (!nextbits || (sc & nextbits)) {
  4474. /* and we have required bits. */
  4475. v = (v << 6) + (sc & 0x3F);
  4476. nextbits = 0;
  4477. --state;
  4478. if (state) {
  4479. i++;
  4480. continue;
  4481. }
  4482. /* We finished. One last check: */
  4483. if ((((v >= 0xD800) && (v <= 0xDFFF))
  4484. || (v > 0x10FFFF))
  4485. # ifdef WINDOWS_UNICODE_SUPPORT
  4486. && (!utf16
  4487. /* If UTF-16 for Windows, just apply upper-limit check */
  4488. || (v > 0x10FFFF))
  4489. # endif
  4490. ) {
  4491. /* UTF-16 surrogates or other illegal code units */
  4492. if (permissive) {
  4493. v = permissive;
  4494. j += init_doki;
  4495. i = oki;
  4496. } else {
  4497. ENCFAIL;
  4498. }
  4499. }
  4500. } else {
  4501. /* ... but we're missing required bits. */
  4502. state = 0;
  4503. nextbits = 0;
  4504. if (permissive) {
  4505. v = permissive;
  4506. j += init_doki;
  4507. i = oki;
  4508. } else {
  4509. ENCFAIL;
  4510. }
  4511. }
  4512. } else {
  4513. /* ... but we're not in one */
  4514. if (permissive) {
  4515. v = permissive;
  4516. } else {
  4517. ENCFAIL;
  4518. }
  4519. }
  4520. } else if (state) {
  4521. /* bad: already in a sequence */
  4522. state = 0;
  4523. if (permissive) {
  4524. v = permissive;
  4525. i = oki;
  4526. j += init_doki;
  4527. } else {
  4528. ENCFAIL;
  4529. }
  4530. } else {
  4531. if ((sc & 0xE0) == 0xC0) {
  4532. if (sc & 0x1E) {
  4533. state = 1;
  4534. v = (sc & 0x1F);
  4535. i++;
  4536. continue;
  4537. }
  4538. /* else too small */
  4539. } else if ((sc & 0xF0) == 0xE0) {
  4540. state = 2;
  4541. v = (sc & 0xF);
  4542. if (!v)
  4543. nextbits = 0x20;
  4544. i++;
  4545. continue;
  4546. } else if ((sc & 0xF8) == 0xF0) {
  4547. v = (sc & 0x7);
  4548. if (v <= 4) {
  4549. state = 3;
  4550. if (!v)
  4551. nextbits = 0x30;
  4552. i++;
  4553. continue;
  4554. }
  4555. /* Else will be larger than 0x10FFFF, so fail */
  4556. }
  4557. /* Too small, or 0xFF or 0xFe, or start of a 5- or 6-byte sequence */
  4558. if (permissive) {
  4559. v = permissive;
  4560. } else {
  4561. ENCFAIL;
  4562. }
  4563. }
  4564. /* If we get here, we're supposed to output v */
  4565. if (compact) {
  4566. if (utf16) {
  4567. if (v > 0xFFFF) {
  4568. # ifdef WINDOWS_UNICODE_SUPPORT
  4569. if (pending_surrogate) {
  4570. if (us)
  4571. ((unsigned short *)us)[j] = pending_surrogate;
  4572. j++; /* Accept previously written unpaired surrogate */
  4573. pending_surrogate = 0;
  4574. }
  4575. # endif
  4576. if (j + 1 >= dend)
  4577. break;
  4578. if (us) {
  4579. v -= 0x10000;
  4580. ((unsigned short *)us)[j] = 0xD800 | ((v >> 10) & 0x3FF);
  4581. ((unsigned short *)us)[j+1] = 0xDC00 | (v & 0x3FF);
  4582. }
  4583. j++;
  4584. } else {
  4585. # ifdef WINDOWS_UNICODE_SUPPORT
  4586. /* We allow a surrogate by itself, but don't allow
  4587. a 0xDC00 after a 0xD800, otherwise multiple encodings can
  4588. map to the same thing. */
  4589. if ((v >= 0xD800) && (v <= 0xDFFF)) {
  4590. if (pending_surrogate && ((v & 0xDC00) == 0xDC00)) {
  4591. /* This looks like a surrogate pair, so disallow it. */
  4592. if (permissive) {
  4593. /* We need to fill in 6 permissive substitutions,
  4594. one for each input byte. If we can't put all 6,
  4595. then don't use any input. */
  4596. if (j + 5 >= dend) {
  4597. break;
  4598. } else {
  4599. int p;
  4600. if (us) {
  4601. for (p = 0; p < 5; p++) {
  4602. if (j + p >= dend)
  4603. break;
  4604. ((unsigned short *)us)[j+p] = permissive;
  4605. }
  4606. }
  4607. j += 5;
  4608. v = permissive;
  4609. }
  4610. } else {
  4611. ENCFAIL;
  4612. }
  4613. pending_surrogate = 0;
  4614. } else {
  4615. if (pending_surrogate) {
  4616. if (us)
  4617. ((unsigned short *)us)[j] = pending_surrogate;
  4618. j++; /* Accept previousy written unpaired surrogate */
  4619. pending_surrogate = 0;
  4620. if (j >= dend)
  4621. break;
  4622. }
  4623. if ((v & 0xDC00) == 0xD800)
  4624. pending_surrogate = v;
  4625. else
  4626. pending_surrogate = 0;
  4627. }
  4628. } else {
  4629. if (pending_surrogate) {
  4630. if (us)
  4631. ((unsigned short *)us)[j] = pending_surrogate;
  4632. j++; /* Accept previousy written unpaired surrogate */
  4633. pending_surrogate = 0;
  4634. if (j >= dend)
  4635. break;
  4636. }
  4637. }
  4638. if (pending_surrogate)
  4639. --j; /* don't accept unpaired surrogate, yet */
  4640. else if (us)
  4641. ((unsigned short *)us)[j] = v;
  4642. # else
  4643. if (us)
  4644. ((unsigned short *)us)[j] = v;
  4645. # endif
  4646. }
  4647. } else {
  4648. intptr_t delta;
  4649. delta = (i - oki);
  4650. if (delta) {
  4651. if (j + delta + 1 < dend) {
  4652. if (us)
  4653. memcpy(((char *)us) + j, s + oki, delta + 1);
  4654. j += delta;
  4655. } else
  4656. break;
  4657. } else if (v == 0xFFFD) {
  4658. if (j + 3 < dend) {
  4659. if (us) {
  4660. ((unsigned char *)us)[j] = 0xEF;
  4661. ((unsigned char *)us)[j+1] = 0xBF;
  4662. ((unsigned char *)us)[j+2] = 0xBD;
  4663. }
  4664. j += 2;
  4665. } else
  4666. break;
  4667. } else if (us) {
  4668. ((unsigned char *)us)[j] = v;
  4669. }
  4670. }
  4671. } else if (us) {
  4672. us[j] = v;
  4673. }
  4674. j++;
  4675. i++;
  4676. oki = i;
  4677. init_doki = 0;
  4678. if (j >= dend)
  4679. break;
  4680. }
  4681. }
  4682. if (_state) {
  4683. if (!state)
  4684. *_state = 0;
  4685. else
  4686. *_state = (state
  4687. | (((end - oki) + init_doki) << 3)
  4688. | ((nextbits >> 2) << 6)
  4689. | (v << 10));
  4690. } else if (state) {
  4691. if (might_continue || !permissive) {
  4692. failmode = -1;
  4693. i = end - 1; /* to ensure that failmode is returned */
  4694. } else if (permissive) {
  4695. for (i = oki; i < end; i++) {
  4696. if (j < dend) {
  4697. if (us) {
  4698. if (compact) {
  4699. if (utf16)
  4700. ((unsigned short *)us)[j] = permissive;
  4701. else
  4702. ((unsigned char *)us)[j] = permissive;
  4703. } else
  4704. us[j] = permissive;
  4705. }
  4706. j++;
  4707. } else
  4708. break;
  4709. }
  4710. oki = i;
  4711. }
  4712. }
  4713. # ifdef WINDOWS_UNICODE_SUPPORT
  4714. if (pending_surrogate)
  4715. oki -= 3;
  4716. #endif
  4717. if (ipos)
  4718. *ipos = oki;
  4719. if (jpos)
  4720. *jpos = j;
  4721. if (i < end)
  4722. return failmode;
  4723. # ifdef WINDOWS_UNICODE_SUPPORT
  4724. if (pending_surrogate) {
  4725. /* input must have ended right after surrogate */
  4726. return -1;
  4727. }
  4728. #endif
  4729. return j - dstart;
  4730. }
  4731. intptr_t scheme_utf8_decode(const unsigned char *s, intptr_t start, intptr_t end,
  4732. unsigned int *us, intptr_t dstart, intptr_t dend,
  4733. intptr_t *ipos, char utf16, int permissive)
  4734. {
  4735. return utf8_decode_x(s, start, end, us, dstart, dend,
  4736. ipos, NULL, utf16, utf16, NULL, 0, permissive);
  4737. }
  4738. intptr_t scheme_utf8_decode_as_prefix(const unsigned char *s, intptr_t start, intptr_t end,
  4739. unsigned int *us, intptr_t dstart, intptr_t dend,
  4740. intptr_t *ipos, char utf16, int permissive)
  4741. /* Always returns number of read characters, not error codes. */
  4742. {
  4743. intptr_t opos;
  4744. utf8_decode_x(s, start, end, us, dstart, dend,
  4745. ipos, &opos, utf16, utf16, NULL, 1, permissive);
  4746. return opos - dstart;
  4747. }
  4748. intptr_t scheme_utf8_decode_all(const unsigned char *s, intptr_t len, unsigned int *us, int permissive)
  4749. {
  4750. return utf8_decode_x(s, 0, len, us, 0, -1, NULL, NULL, 0, 0, NULL, 0, permissive);
  4751. }
  4752. intptr_t scheme_utf8_decode_prefix(const unsigned char *s, intptr_t len, unsigned int *us, int permissive)
  4753. /* us != NULL */
  4754. {
  4755. {
  4756. /* Try fast path (all ASCII) */
  4757. intptr_t i;
  4758. for (i = 0; i < len; i++) {
  4759. if (s[i] < 128)
  4760. us[i] = s[i];
  4761. else
  4762. break;
  4763. }
  4764. if (i == len)
  4765. return len;
  4766. }
  4767. return utf8_decode_x(s, 0, len, us, 0, -1, NULL, NULL, 0, 0, NULL, 1, permissive);
  4768. }
  4769. mzchar *scheme_utf8_decode_to_buffer_len(const unsigned char *s, intptr_t len,
  4770. mzchar *buf, intptr_t blen, intptr_t *_ulen)
  4771. {
  4772. intptr_t ulen;
  4773. ulen = utf8_decode_x(s, 0, len, NULL, 0, -1,
  4774. NULL, NULL, 0, 0,
  4775. NULL, 0, 0);
  4776. if (ulen < 0)
  4777. return NULL;
  4778. if (ulen + 1 > blen) {
  4779. buf = (mzchar *)scheme_malloc_atomic((ulen + 1) * sizeof(mzchar));
  4780. }
  4781. utf8_decode_x(s, 0, len, buf, 0, -1,
  4782. NULL, NULL, 0, 0,
  4783. NULL, 0, 0);
  4784. buf[ulen] = 0;
  4785. *_ulen = ulen;
  4786. return buf;
  4787. }
  4788. mzchar *scheme_utf8_decode_to_buffer(const unsigned char *s, intptr_t len,
  4789. mzchar *buf, intptr_t blen)
  4790. {
  4791. intptr_t ulen;
  4792. return scheme_utf8_decode_to_buffer_len(s, len, buf, blen, &ulen);
  4793. }
  4794. intptr_t scheme_utf8_decode_count(const unsigned char *s, intptr_t start, intptr_t end,
  4795. int *_state, int might_continue, int permissive)
  4796. {
  4797. intptr_t pos = 0;
  4798. if (!_state || !*_state) {
  4799. /* Try fast path (all ASCII): */
  4800. intptr_t i;
  4801. for (i = start; i < end; i++) {
  4802. if (s[i] > 127)
  4803. break;
  4804. }
  4805. if (i == end)
  4806. return end - start;
  4807. }
  4808. utf8_decode_x(s, start, end,
  4809. NULL, 0, -1,
  4810. NULL, &pos,
  4811. 0, 0, _state,
  4812. might_continue, permissive);
  4813. return pos;
  4814. }
  4815. static intptr_t utf8_encode_x(const unsigned int *us, intptr_t start, intptr_t end,
  4816. unsigned char *s, intptr_t dstart, intptr_t dend,
  4817. intptr_t *_ipos, intptr_t *_opos, char utf16)
  4818. /* Results:
  4819. -1 => input ended in the middle of an encoding - only when utf16 and _opos
  4820. non-negative => reports number of bytes/code-units produced */
  4821. {
  4822. intptr_t i, j, done = start;
  4823. if (dend < 0)
  4824. dend = 0x7FFFFFFF;
  4825. if (!s) {
  4826. unsigned int wc;
  4827. j = 0;
  4828. for (i = start; i < end; i++) {
  4829. if (utf16) {
  4830. wc = ((unsigned short *)us)[i];
  4831. if ((wc & 0xF800) == 0xD800) {
  4832. /* Unparse surrogates. We assume that the surrogates are
  4833. well formed, unless this is Windows or if we're at the
  4834. end and _opos is 0. */
  4835. # ifdef WINDOWS_UNICODE_SUPPORT
  4836. # define UNPAIRED_MASK 0xFC00
  4837. # else
  4838. # define UNPAIRED_MASK 0xF800
  4839. # endif
  4840. if (((i + 1) == end) && ((wc & UNPAIRED_MASK) == 0xD800) && _opos) {
  4841. /* Ended in the middle of a surrogate pair */
  4842. *_opos = j;
  4843. if (_ipos)
  4844. *_ipos = i;
  4845. return -1;
  4846. }
  4847. # ifdef WINDOWS_UNICODE_SUPPORT
  4848. if ((wc & 0xFC00) != 0xD800) {
  4849. /* Count as one */
  4850. } else if ((i + 1 >= end)
  4851. || (((((unsigned short *)us)[i+1]) & 0xFC00) != 0xDC00)) {
  4852. } else
  4853. # endif
  4854. {
  4855. i++;
  4856. wc = ((wc & 0x3FF) << 10) + ((((unsigned short *)us)[i]) & 0x3FF);
  4857. wc += 0x10000;
  4858. }
  4859. }
  4860. } else {
  4861. wc = us[i];
  4862. }
  4863. if (wc < 0x80) {
  4864. j += 1;
  4865. } else if (wc < 0x800) {
  4866. j += 2;
  4867. } else if (wc < 0x10000) {
  4868. j += 3;
  4869. } else if (wc < 0x200000) {
  4870. j += 4;
  4871. } else if (wc < 0x4000000) {
  4872. j += 5;
  4873. } else {
  4874. j += 6;
  4875. }
  4876. }
  4877. if (_ipos)
  4878. *_ipos = i;
  4879. if (_opos)
  4880. *_opos = j + dstart;
  4881. return j;
  4882. } else {
  4883. unsigned int wc;
  4884. j = dstart;
  4885. for (i = start; i < end; i++) {
  4886. if (utf16) {
  4887. wc = ((unsigned short *)us)[i];
  4888. if ((wc & 0xF800) == 0xD800) {
  4889. /* Unparse surrogates. We assume that the surrogates are
  4890. well formed on non-Windows platforms, but when _opos,
  4891. we detect ending in the middle of an surrogate pair. */
  4892. if (((i + 1) == end) && ((wc & UNPAIRED_MASK) == 0xD800) && _opos) {
  4893. /* Ended in the middle of a surrogate pair */
  4894. *_opos = j;
  4895. if (_ipos)
  4896. *_ipos = i;
  4897. return -1;
  4898. }
  4899. # ifdef WINDOWS_UNICODE_SUPPORT
  4900. if ((wc & 0xFC00) != 0xD800) {
  4901. /* Let the misplaced surrogate through */
  4902. } else if ((i + 1 >= end)
  4903. || (((((unsigned short *)us)[i+1]) & 0xFC00) != 0xDC00)) {
  4904. /* Let the misplaced surrogate through */
  4905. } else
  4906. # endif
  4907. {
  4908. i++;
  4909. wc = ((wc & 0x3FF) << 10) + ((((unsigned short *)us)[i]) & 0x3FF);
  4910. wc += 0x10000;
  4911. }
  4912. }
  4913. } else {
  4914. wc = us[i];
  4915. }
  4916. if (wc < 0x80) {
  4917. if (j + 1 > dend)
  4918. break;
  4919. s[j++] = wc;
  4920. } else if (wc < 0x800) {
  4921. if (j + 2 > dend)
  4922. break;
  4923. s[j++] = 0xC0 | ((wc & 0x7C0) >> 6);
  4924. s[j++] = 0x80 | (wc & 0x3F);
  4925. } else if (wc < 0x10000) {
  4926. if (j + 3 > dend)
  4927. break;
  4928. s[j++] = 0xE0 | ((wc & 0xF000) >> 12);
  4929. s[j++] = 0x80 | ((wc & 0x0FC0) >> 6);
  4930. s[j++] = 0x80 | (wc & 0x3F);
  4931. } else if (wc < 0x200000) {
  4932. if (j + 4 > dend)
  4933. break;
  4934. s[j++] = 0xF0 | ((wc & 0x1C0000) >> 18);
  4935. s[j++] = 0x80 | ((wc & 0x03F000) >> 12);
  4936. s[j++] = 0x80 | ((wc & 0x000FC0) >> 6);
  4937. s[j++] = 0x80 | (wc & 0x3F);
  4938. } else if (wc < 0x4000000) {
  4939. if (j + 5 > dend)
  4940. break;
  4941. s[j++] = 0xF8 | ((wc & 0x3000000) >> 24);
  4942. s[j++] = 0x80 | ((wc & 0x0FC0000) >> 18);
  4943. s[j++] = 0x80 | ((wc & 0x003F000) >> 12);
  4944. s[j++] = 0x80 | ((wc & 0x0000FC0) >> 6);
  4945. s[j++] = 0x80 | (wc & 0x3F);
  4946. } else {
  4947. if (j + 6 > dend)
  4948. break;
  4949. s[j++] = 0xFC | ((wc & 0x40000000) >> 30);
  4950. s[j++] = 0x80 | ((wc & 0x3F000000) >> 24);
  4951. s[j++] = 0x80 | ((wc & 0x00FC0000) >> 18);
  4952. s[j++] = 0x80 | ((wc & 0x0003F000) >> 12);
  4953. s[j++] = 0x80 | ((wc & 0x00000FC0) >> 6);
  4954. s[j++] = 0x80 | (wc & 0x3F);
  4955. }
  4956. done = i;
  4957. }
  4958. if (_ipos)
  4959. *_ipos = done;
  4960. if (_opos)
  4961. *_opos = j;
  4962. return j - dstart;
  4963. }
  4964. }
  4965. intptr_t scheme_utf8_encode(const unsigned int *us, intptr_t start, intptr_t end,
  4966. unsigned char *s, intptr_t dstart,
  4967. char utf16)
  4968. {
  4969. return utf8_encode_x(us, start, end,
  4970. s, dstart, -1,
  4971. NULL, NULL, utf16);
  4972. }
  4973. intptr_t scheme_utf8_encode_all(const unsigned int *us, intptr_t len, unsigned char *s)
  4974. {
  4975. return utf8_encode_x(us, 0, len, s, 0, -1, NULL, NULL, 0 /* utf16 */);
  4976. }
  4977. char *scheme_utf8_encode_to_buffer_len(const mzchar *s, intptr_t len,
  4978. char *buf, intptr_t blen,
  4979. intptr_t *_slen)
  4980. {
  4981. intptr_t slen;
  4982. /* ASCII with len < blen is a common case: */
  4983. if (len < blen) {
  4984. for (slen = 0; slen < len; slen++) {
  4985. if (s[slen] > 127)
  4986. break;
  4987. else
  4988. buf[slen] = s[slen];
  4989. }
  4990. if (slen == len) {
  4991. buf[slen] = 0;
  4992. *_slen = slen;
  4993. return buf;
  4994. }
  4995. }
  4996. slen = utf8_encode_x(s, 0, len, NULL, 0, -1, NULL, NULL, 0);
  4997. if (slen + 1 > blen) {
  4998. buf = (char *)scheme_malloc_atomic(slen + 1);
  4999. }
  5000. utf8_encode_x(s, 0, len, (unsigned char *)buf, 0, -1, NULL, NULL, 0);
  5001. buf[slen] = 0;
  5002. *_slen = slen;
  5003. return buf;
  5004. }
  5005. char *scheme_utf8_encode_to_buffer(const mzchar *s, intptr_t len,
  5006. char *buf, intptr_t blen)
  5007. {
  5008. intptr_t slen;
  5009. return scheme_utf8_encode_to_buffer_len(s, len, buf, blen, &slen);
  5010. }
  5011. unsigned short *scheme_ucs4_to_utf16(const mzchar *text, intptr_t start, intptr_t end,
  5012. unsigned short *buf, intptr_t bufsize,
  5013. intptr_t *ulen, intptr_t term_size)
  5014. {
  5015. mzchar v;
  5016. intptr_t extra, i, j;
  5017. unsigned short *utf16;
  5018. /* Count characters that fall outside UCS-2: */
  5019. for (i = start, extra = 0; i < end; i++) {
  5020. if (text[i] > 0xFFFF)
  5021. extra++;
  5022. }
  5023. if ((end - start) + extra + term_size < bufsize)
  5024. utf16 = buf;
  5025. else
  5026. utf16 = (unsigned short *)scheme_malloc_atomic(sizeof(unsigned short) * ((end - start) + extra + term_size));
  5027. for (i = start, j = 0; i < end; i++) {
  5028. v = text[i];
  5029. if (v > 0xFFFF) {
  5030. v -= 0x10000;
  5031. utf16[j++] = 0xD800 | ((v >> 10) & 0x3FF);
  5032. utf16[j++] = 0xDC00 | (v & 0x3FF);
  5033. } else
  5034. utf16[j++] = v;
  5035. }
  5036. *ulen = j;
  5037. return utf16;
  5038. }
  5039. mzchar *scheme_utf16_to_ucs4(const unsigned short *text, intptr_t start, intptr_t end,
  5040. mzchar *buf, intptr_t bufsize,
  5041. intptr_t *ulen, intptr_t term_size)
  5042. {
  5043. int wc;
  5044. intptr_t i, j;
  5045. for (i = start, j = 0; i < end; i++) {
  5046. wc = text[i];
  5047. if ((wc & 0xF800) == 0xD800) {
  5048. i++;
  5049. }
  5050. j++;
  5051. }
  5052. if (j + term_size >= bufsize)
  5053. buf = (mzchar *)scheme_malloc_atomic((j + term_size) * sizeof(mzchar));
  5054. for (i = start, j = 0; i < end; i++) {
  5055. wc = text[i];
  5056. if ((wc & 0xF800) == 0xD800) {
  5057. i++;
  5058. wc = ((wc & 0x3FF) << 10) + ((((unsigned short *)text)[i]) & 0x3FF);
  5059. wc += 0x10000;
  5060. }
  5061. buf[j++] = wc;
  5062. }
  5063. *ulen = j;
  5064. return buf;
  5065. }
  5066. /**********************************************************************/
  5067. /* machine type details */
  5068. /**********************************************************************/
  5069. /**************************** MacOS ***********************************/
  5070. #if defined(MACINTOSH_EVENTS) && !defined(OS_X)
  5071. # include <Gestalt.h>
  5072. extern intptr_t scheme_this_ip(void);
  5073. static void machine_details(char *s)
  5074. {
  5075. OSErr err;
  5076. intptr_t lng;
  5077. char sysvers[30];
  5078. char machine_name[256];
  5079. err = Gestalt(gestaltSystemVersion, &lng);
  5080. if (err != noErr) {
  5081. strcpy(sysvers, "<unknown system>");
  5082. } else {
  5083. int i;
  5084. sprintf(sysvers, "%X.%X",
  5085. (lng >> 8) & 0xff,
  5086. lng & 0xff);
  5087. /* remove trailing zeros, put dot before something else */
  5088. i = strlen(sysvers);
  5089. if (i > 1) {
  5090. if (sysvers[i-1] != '.') {
  5091. if (sysvers[i-1] == '0') {
  5092. sysvers[i-1] = 0;
  5093. i--;
  5094. } else {
  5095. sysvers[i] = sysvers[i-1];
  5096. sysvers[i-1] = '.';
  5097. i++;
  5098. sysvers[i] = 0;
  5099. }
  5100. }
  5101. }
  5102. }
  5103. err = Gestalt(gestaltMachineType, &lng);
  5104. if (err != noErr) {
  5105. strcpy(machine_name, "<unknown machine>");
  5106. } else {
  5107. Str255 machine_name_pascal;
  5108. GetIndString(machine_name_pascal, kMachineNameStrID, lng);
  5109. CopyPascalStringToC(machine_name_pascal, machine_name);
  5110. }
  5111. lng = scheme_this_ip();
  5112. sprintf(s, "%s %s %d.%d.%d.%d", sysvers, machine_name,
  5113. ((unsigned char *)&lng)[0],
  5114. ((unsigned char *)&lng)[1],
  5115. ((unsigned char *)&lng)[2],
  5116. ((unsigned char *)&lng)[3]);
  5117. }
  5118. #endif
  5119. /*************************** Windows **********************************/
  5120. #ifdef DOS_FILE_SYSTEM
  5121. # include <windows.h>
  5122. void machine_details(char *buff)
  5123. {
  5124. OSVERSIONINFO info;
  5125. BOOL hasInfo;
  5126. char *p;
  5127. info.dwOSVersionInfoSize = sizeof(info);
  5128. GetVersionEx(&info);
  5129. hasInfo = FALSE;
  5130. p = info.szCSDVersion;
  5131. while (p < info.szCSDVersion + sizeof(info.szCSDVersion) &&
  5132. *p) {
  5133. if (*p != ' ') {
  5134. hasInfo = TRUE;
  5135. break;
  5136. }
  5137. p = p XFORM_OK_PLUS 1;
  5138. }
  5139. sprintf(buff,"Windows %s %ld.%ld (Build %ld)%s%s",
  5140. (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) ?
  5141. "9x" :
  5142. (info.dwPlatformId == VER_PLATFORM_WIN32_NT) ?
  5143. "NT" : "Unknown platform",
  5144. info.dwMajorVersion,info.dwMinorVersion,
  5145. (info.dwPlatformId == VER_PLATFORM_WIN32_NT) ?
  5146. info.dwBuildNumber :
  5147. info.dwBuildNumber & 0xFFFF,
  5148. hasInfo ? " " : "",hasInfo ? info.szCSDVersion : "");
  5149. }
  5150. #endif
  5151. /***************************** OSKit **********************************/
  5152. #ifdef USE_OSKIT_CONSOLE
  5153. void machine_details(char *buff)
  5154. {
  5155. strcpy(buff, "OSKit");
  5156. }
  5157. #endif
  5158. /***************************** Unix ***********************************/
  5159. #if (!defined(MACINTOSH_EVENTS) || defined(OS_X)) && !defined(DOS_FILE_SYSTEM) && !defined(USE_OSKIT_CONSOLE)
  5160. READ_ONLY static char *uname_locations[] = { "/bin/uname",
  5161. "/usr/bin/uname",
  5162. /* The above should cover everything, but
  5163. just in case... */
  5164. "/sbin/uname",
  5165. "/usr/sbin/uname",
  5166. "/usr/local/bin/uname",
  5167. "/usr/local/uname",
  5168. NULL };
  5169. static int try_subproc(Scheme_Object *subprocess_proc, char *prog)
  5170. {
  5171. Scheme_Object *a[5];
  5172. mz_jmp_buf * volatile savebuf, newbuf;
  5173. savebuf = scheme_current_thread->error_buf;
  5174. scheme_current_thread->error_buf = &newbuf;
  5175. if (!scheme_setjmp(newbuf)) {
  5176. a[0] = scheme_false;
  5177. a[1] = scheme_false;
  5178. a[2] = scheme_false;
  5179. a[3] = scheme_make_locale_string(prog);
  5180. a[4] = scheme_make_locale_string("-a");
  5181. _scheme_apply_multi(subprocess_proc, 5, a);
  5182. scheme_current_thread->error_buf = savebuf;
  5183. return 1;
  5184. } else {
  5185. scheme_clear_escape();
  5186. scheme_current_thread->error_buf = savebuf;
  5187. return 0;
  5188. }
  5189. }
  5190. void machine_details(char *buff)
  5191. {
  5192. Scheme_Object *subprocess_proc;
  5193. int i;
  5194. subprocess_proc = scheme_builtin_value("subprocess");
  5195. for (i = 0; uname_locations[i]; i++) {
  5196. if (scheme_file_exists(uname_locations[i])) {
  5197. /* Try running it. */
  5198. if (try_subproc(subprocess_proc, uname_locations[i])) {
  5199. Scheme_Object *sout, *sin, *serr;
  5200. intptr_t c;
  5201. sout = scheme_current_thread->ku.multiple.array[1];
  5202. sin = scheme_current_thread->ku.multiple.array[2];
  5203. serr = scheme_current_thread->ku.multiple.array[3];
  5204. scheme_close_output_port(sin);
  5205. scheme_close_input_port(serr);
  5206. /* Read result: */
  5207. strcpy(buff, "<unknown machine>");
  5208. c = scheme_get_bytes(sout, 1023, buff, 0);
  5209. buff[c] = 0;
  5210. scheme_close_input_port(sout);
  5211. /* Remove trailing whitespace (especially newlines) */
  5212. while (c && portable_isspace(((unsigned char *)buff)[c - 1])) {
  5213. buff[--c] = 0;
  5214. }
  5215. return;
  5216. }
  5217. }
  5218. }
  5219. strcpy(buff, "<unknown machine>");
  5220. }
  5221. #endif
  5222. /**********************************************************************/
  5223. /* Precise GC */
  5224. /**********************************************************************/
  5225. #ifdef MZ_PRECISE_GC
  5226. START_XFORM_SKIP;
  5227. #include "mzmark_string.inc"
  5228. static void register_traversers(void)
  5229. {
  5230. GC_REG_TRAV(scheme_string_converter_type, mark_string_convert);
  5231. }
  5232. END_XFORM_SKIP;
  5233. #endif