utils.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599
  1. /*
  2. * Utility routines
  3. *
  4. * Copyright 1998,2000 Bertho A. Stultiens
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include "config.h"
  21. #include "wine/port.h"
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <stdarg.h>
  25. #include <string.h>
  26. #include <assert.h>
  27. #include <ctype.h>
  28. #include "wmctypes.h"
  29. #include "winnls.h"
  30. #include "utils.h"
  31. #include "wmc.h"
  32. #define SUPPRESS_YACC_ERROR_MESSAGE
  33. static void generic_msg(const char *s, const char *t, va_list ap)
  34. {
  35. fprintf(stderr, "%s:%d:%d: %s: ", input_name ? input_name : "stdin", line_number, char_number, t);
  36. vfprintf(stderr, s, ap);
  37. }
  38. /*
  39. * The yyerror routine should not exit because we use the error-token
  40. * to determine the syntactic error in the source. However, YACC
  41. * uses the same routine to print an error just before the error
  42. * token is reduced.
  43. * The extra routine 'xyyerror' is used to exit after giving a real
  44. * message.
  45. */
  46. int mcy_error(const char *s, ...)
  47. {
  48. #ifndef SUPPRESS_YACC_ERROR_MESSAGE
  49. va_list ap;
  50. va_start(ap, s);
  51. generic_msg(s, "Yacc error", ap);
  52. va_end(ap);
  53. #endif
  54. return 1;
  55. }
  56. int xyyerror(const char *s, ...)
  57. {
  58. va_list ap;
  59. va_start(ap, s);
  60. generic_msg(s, "Error", ap);
  61. va_end(ap);
  62. exit(1);
  63. return 1;
  64. }
  65. int mcy_warning(const char *s, ...)
  66. {
  67. va_list ap;
  68. va_start(ap, s);
  69. generic_msg(s, "Warning", ap);
  70. va_end(ap);
  71. return 0;
  72. }
  73. void internal_error(const char *file, int line, const char *s, ...)
  74. {
  75. va_list ap;
  76. va_start(ap, s);
  77. fprintf(stderr, "Internal error (please report) %s %d: ", file, line);
  78. vfprintf(stderr, s, ap);
  79. va_end(ap);
  80. exit(3);
  81. }
  82. void fatal_perror( const char *msg, ... )
  83. {
  84. va_list valist;
  85. va_start( valist, msg );
  86. fprintf(stderr, "Error: ");
  87. vfprintf( stderr, msg, valist );
  88. perror( " " );
  89. va_end( valist );
  90. exit(2);
  91. }
  92. void error(const char *s, ...)
  93. {
  94. va_list ap;
  95. va_start(ap, s);
  96. fprintf(stderr, "Error: ");
  97. vfprintf(stderr, s, ap);
  98. va_end(ap);
  99. exit(2);
  100. }
  101. void warning(const char *s, ...)
  102. {
  103. va_list ap;
  104. va_start(ap, s);
  105. fprintf(stderr, "Warning: ");
  106. vfprintf(stderr, s, ap);
  107. va_end(ap);
  108. }
  109. char *dup_basename(const char *name, const char *ext)
  110. {
  111. int namelen;
  112. int extlen = strlen(ext);
  113. char *base;
  114. char *slash;
  115. if(!name)
  116. name = "wmc.tab";
  117. slash = strrchr(name, '/');
  118. if (slash)
  119. name = slash + 1;
  120. namelen = strlen(name);
  121. /* +4 for later extension and +1 for '\0' */
  122. base = xmalloc(namelen +4 +1);
  123. strcpy(base, name);
  124. if(!strcasecmp(name + namelen-extlen, ext))
  125. {
  126. base[namelen - extlen] = '\0';
  127. }
  128. return base;
  129. }
  130. void *xmalloc(size_t size)
  131. {
  132. void *res;
  133. assert(size > 0);
  134. res = malloc(size);
  135. if(res == NULL)
  136. {
  137. error("Virtual memory exhausted.\n");
  138. }
  139. memset(res, 0x55, size);
  140. return res;
  141. }
  142. void *xrealloc(void *p, size_t size)
  143. {
  144. void *res;
  145. assert(size > 0);
  146. res = realloc(p, size);
  147. if(res == NULL)
  148. {
  149. error("Virtual memory exhausted.\n");
  150. }
  151. return res;
  152. }
  153. char *xstrdup(const char *str)
  154. {
  155. char *s;
  156. assert(str != NULL);
  157. s = xmalloc(strlen(str)+1);
  158. return strcpy(s, str);
  159. }
  160. char *strmake( const char* fmt, ... )
  161. {
  162. int n;
  163. size_t size = 100;
  164. va_list ap;
  165. for (;;)
  166. {
  167. char *p = xmalloc( size );
  168. va_start( ap, fmt );
  169. n = vsnprintf( p, size, fmt, ap );
  170. va_end( ap );
  171. if (n == -1) size *= 2;
  172. else if ((size_t)n >= size) size = n + 1;
  173. else return p;
  174. free( p );
  175. }
  176. }
  177. int strendswith( const char *str, const char *end )
  178. {
  179. int l = strlen(str);
  180. int m = strlen(end);
  181. return l >= m && !strcmp( str + l - m, end );
  182. }
  183. int unistrlen(const WCHAR *s)
  184. {
  185. int n;
  186. for(n = 0; *s; n++, s++)
  187. ;
  188. return n;
  189. }
  190. WCHAR *unistrcpy(WCHAR *dst, const WCHAR *src)
  191. {
  192. WCHAR *t = dst;
  193. while(*src)
  194. *t++ = *src++;
  195. *t = 0;
  196. return dst;
  197. }
  198. WCHAR *xunistrdup(const WCHAR * str)
  199. {
  200. WCHAR *s;
  201. assert(str != NULL);
  202. s = xmalloc((unistrlen(str)+1) * sizeof(WCHAR));
  203. return unistrcpy(s, str);
  204. }
  205. int unistricmp(const WCHAR *s1, const WCHAR *s2)
  206. {
  207. int i;
  208. int once = 0;
  209. static const char warn[] = "Don't know the uppercase equivalent of non ascii characters;"
  210. "comparison might yield wrong results";
  211. while(*s1 && *s2)
  212. {
  213. if((*s1 & 0xffff) > 0x7f || (*s2 & 0xffff) > 0x7f)
  214. {
  215. if(!once)
  216. {
  217. once++;
  218. mcy_warning(warn);
  219. }
  220. i = *s1++ - *s2++;
  221. }
  222. else
  223. i = toupper(*s1++) - toupper(*s2++);
  224. if(i)
  225. return i;
  226. }
  227. if((*s1 & 0xffff) > 0x7f || (*s2 & 0xffff) > 0x7f)
  228. {
  229. if(!once)
  230. mcy_warning(warn);
  231. return *s1 - *s2;
  232. }
  233. else
  234. return toupper(*s1) - toupper(*s2);
  235. }
  236. int unistrcmp(const WCHAR *s1, const WCHAR *s2)
  237. {
  238. int i;
  239. while(*s1 && *s2)
  240. {
  241. i = *s1++ - *s2++;
  242. if(i)
  243. return i;
  244. }
  245. return *s1 - *s2;
  246. }
  247. WCHAR *utf8_to_unicode( const char *src, int srclen, int *dstlen )
  248. {
  249. static const char utf8_length[128] =
  250. {
  251. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80-0x8f */
  252. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x90-0x9f */
  253. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0-0xaf */
  254. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb0-0xbf */
  255. 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xc0-0xcf */
  256. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0xd0-0xdf */
  257. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, /* 0xe0-0xef */
  258. 3,3,3,3,3,0,0,0,0,0,0,0,0,0,0,0 /* 0xf0-0xff */
  259. };
  260. static const unsigned char utf8_mask[4] = { 0x7f, 0x1f, 0x0f, 0x07 };
  261. const char *srcend = src + srclen;
  262. int len, res;
  263. WCHAR *ret, *dst;
  264. dst = ret = xmalloc( (srclen + 1) * sizeof(WCHAR) );
  265. while (src < srcend)
  266. {
  267. unsigned char ch = *src++;
  268. if (ch < 0x80) /* special fast case for 7-bit ASCII */
  269. {
  270. *dst++ = ch;
  271. continue;
  272. }
  273. len = utf8_length[ch - 0x80];
  274. if (len && src + len <= srcend)
  275. {
  276. res = ch & utf8_mask[len];
  277. switch (len)
  278. {
  279. case 3:
  280. if ((ch = *src ^ 0x80) >= 0x40) break;
  281. res = (res << 6) | ch;
  282. src++;
  283. if (res < 0x10) break;
  284. case 2:
  285. if ((ch = *src ^ 0x80) >= 0x40) break;
  286. res = (res << 6) | ch;
  287. if (res >= 0x110000 >> 6) break;
  288. src++;
  289. if (res < 0x20) break;
  290. if (res >= 0xd800 >> 6 && res <= 0xdfff >> 6) break;
  291. case 1:
  292. if ((ch = *src ^ 0x80) >= 0x40) break;
  293. res = (res << 6) | ch;
  294. src++;
  295. if (res < 0x80) break;
  296. if (res <= 0xffff) *dst++ = res;
  297. else
  298. {
  299. res -= 0x10000;
  300. *dst++ = 0xd800 | (res >> 10);
  301. *dst++ = 0xdc00 | (res & 0x3ff);
  302. }
  303. continue;
  304. }
  305. }
  306. *dst++ = 0xfffd;
  307. }
  308. *dst = 0;
  309. *dstlen = dst - ret;
  310. return ret;
  311. }
  312. char *unicode_to_utf8( const WCHAR *src, int srclen, int *dstlen )
  313. {
  314. char *ret, *dst;
  315. dst = ret = xmalloc( srclen * 3 + 1 );
  316. for ( ; srclen; srclen--, src++)
  317. {
  318. unsigned int ch = *src;
  319. if (ch < 0x80) /* 0x00-0x7f: 1 byte */
  320. {
  321. *dst++ = ch;
  322. continue;
  323. }
  324. if (ch < 0x800) /* 0x80-0x7ff: 2 bytes */
  325. {
  326. dst[1] = 0x80 | (ch & 0x3f);
  327. ch >>= 6;
  328. dst[0] = 0xc0 | ch;
  329. dst += 2;
  330. continue;
  331. }
  332. if (ch >= 0xd800 && ch <= 0xdbff && srclen > 1 && src[1] >= 0xdc00 && src[1] <= 0xdfff)
  333. {
  334. /* 0x10000-0x10ffff: 4 bytes */
  335. ch = 0x10000 + ((ch & 0x3ff) << 10) + (src[1] & 0x3ff);
  336. dst[3] = 0x80 | (ch & 0x3f);
  337. ch >>= 6;
  338. dst[2] = 0x80 | (ch & 0x3f);
  339. ch >>= 6;
  340. dst[1] = 0x80 | (ch & 0x3f);
  341. ch >>= 6;
  342. dst[0] = 0xf0 | ch;
  343. dst += 4;
  344. src++;
  345. srclen--;
  346. continue;
  347. }
  348. if (ch >= 0xd800 && ch <= 0xdfff) ch = 0xfffd; /* invalid surrogate pair */
  349. /* 0x800-0xffff: 3 bytes */
  350. dst[2] = 0x80 | (ch & 0x3f);
  351. ch >>= 6;
  352. dst[1] = 0x80 | (ch & 0x3f);
  353. ch >>= 6;
  354. dst[0] = 0xe0 | ch;
  355. dst += 3;
  356. }
  357. *dst = 0;
  358. *dstlen = dst - ret;
  359. return ret;
  360. }
  361. #ifdef _WIN32
  362. int is_valid_codepage(int id)
  363. {
  364. return IsValidCodePage( id );
  365. }
  366. WCHAR *codepage_to_unicode( int codepage, const char *src, int srclen, int *dstlen )
  367. {
  368. WCHAR *dst = xmalloc( (srclen + 1) * sizeof(WCHAR) );
  369. DWORD ret = MultiByteToWideChar( codepage, MB_ERR_INVALID_CHARS, src, srclen, dst, srclen );
  370. if (!ret) return NULL;
  371. dst[ret] = 0;
  372. *dstlen = ret;
  373. return dst;
  374. }
  375. #else /* _WIN32 */
  376. struct nls_info
  377. {
  378. unsigned short codepage;
  379. unsigned short unidef;
  380. unsigned short trans_unidef;
  381. unsigned short *cp2uni;
  382. unsigned short *dbcs_offsets;
  383. };
  384. static struct nls_info nlsinfo[128];
  385. static void init_nls_info( struct nls_info *info, unsigned short *ptr )
  386. {
  387. unsigned short hdr_size = ptr[0];
  388. info->codepage = ptr[1];
  389. info->unidef = ptr[4];
  390. info->trans_unidef = ptr[6];
  391. ptr += hdr_size;
  392. info->cp2uni = ++ptr;
  393. ptr += 256;
  394. if (*ptr++) ptr += 256; /* glyph table */
  395. info->dbcs_offsets = *ptr ? ptr + 1 : NULL;
  396. }
  397. static const struct nls_info *get_nls_info( unsigned int codepage )
  398. {
  399. struct stat st;
  400. unsigned short *data;
  401. char *path;
  402. unsigned int i;
  403. int fd;
  404. for (i = 0; i < ARRAY_SIZE(nlsinfo) && nlsinfo[i].codepage; i++)
  405. if (nlsinfo[i].codepage == codepage) return &nlsinfo[i];
  406. assert( i < ARRAY_SIZE(nlsinfo) );
  407. for (i = 0; nlsdirs[i]; i++)
  408. {
  409. path = strmake( "%s/c_%03u.nls", nlsdirs[i], codepage );
  410. if ((fd = open( path, O_RDONLY )) != -1) break;
  411. free( path );
  412. }
  413. if (!nlsdirs[i]) return NULL;
  414. fstat( fd, &st );
  415. data = xmalloc( st.st_size );
  416. if (read( fd, data, st.st_size ) != st.st_size) error( "failed to load %s\n", path );
  417. close( fd );
  418. free( path );
  419. init_nls_info( &nlsinfo[i], data );
  420. return &nlsinfo[i];
  421. }
  422. int is_valid_codepage(int cp)
  423. {
  424. return cp == CP_UTF8 || get_nls_info( cp );
  425. }
  426. WCHAR *codepage_to_unicode( int codepage, const char *src, int srclen, int *dstlen )
  427. {
  428. const struct nls_info *info = get_nls_info( codepage );
  429. unsigned int i;
  430. WCHAR dbch, *dst = xmalloc( (srclen + 1) * sizeof(WCHAR) );
  431. if (!info) error( "codepage %u not supported\n", codepage );
  432. if (info->dbcs_offsets)
  433. {
  434. for (i = 0; srclen; i++, srclen--, src++)
  435. {
  436. unsigned short off = info->dbcs_offsets[(unsigned char)*src];
  437. if (off)
  438. {
  439. if (srclen == 1) return NULL;
  440. dbch = (src[0] << 8) | (unsigned char)src[1];
  441. src++;
  442. srclen--;
  443. dst[i] = info->dbcs_offsets[off + (unsigned char)*src];
  444. if (dst[i] == info->unidef && dbch != info->trans_unidef) return NULL;
  445. }
  446. else
  447. {
  448. dst[i] = info->cp2uni[(unsigned char)*src];
  449. if (dst[i] == info->unidef && *src != info->trans_unidef) return NULL;
  450. }
  451. }
  452. }
  453. else
  454. {
  455. for (i = 0; i < srclen; i++)
  456. {
  457. dst[i] = info->cp2uni[(unsigned char)src[i]];
  458. if (dst[i] == info->unidef && src[i] != info->trans_unidef) return NULL;
  459. }
  460. }
  461. dst[i] = 0;
  462. *dstlen = i;
  463. return dst;
  464. }
  465. #endif /* _WIN32 */
  466. /*******************************************************************
  467. * buffer management
  468. *
  469. * Function for writing to a memory buffer.
  470. */
  471. int byte_swapped = 0;
  472. unsigned char *output_buffer;
  473. size_t output_buffer_pos;
  474. size_t output_buffer_size;
  475. static void check_output_buffer_space( size_t size )
  476. {
  477. if (output_buffer_pos + size >= output_buffer_size)
  478. {
  479. output_buffer_size = max( output_buffer_size * 2, output_buffer_pos + size );
  480. output_buffer = xrealloc( output_buffer, output_buffer_size );
  481. }
  482. }
  483. void init_output_buffer(void)
  484. {
  485. output_buffer_size = 1024;
  486. output_buffer_pos = 0;
  487. output_buffer = xmalloc( output_buffer_size );
  488. }
  489. void flush_output_buffer( const char *name )
  490. {
  491. int fd = open( name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666 );
  492. if (fd == -1) error( "Error creating %s\n", name );
  493. if (write( fd, output_buffer, output_buffer_pos ) != output_buffer_pos)
  494. error( "Error writing to %s\n", name );
  495. close( fd );
  496. free( output_buffer );
  497. }
  498. void put_data( const void *data, size_t size )
  499. {
  500. check_output_buffer_space( size );
  501. memcpy( output_buffer + output_buffer_pos, data, size );
  502. output_buffer_pos += size;
  503. }
  504. void put_byte( unsigned char val )
  505. {
  506. check_output_buffer_space( 1 );
  507. output_buffer[output_buffer_pos++] = val;
  508. }
  509. void put_word( unsigned short val )
  510. {
  511. if (byte_swapped) val = (val << 8) | (val >> 8);
  512. put_data( &val, sizeof(val) );
  513. }
  514. void put_dword( unsigned int val )
  515. {
  516. if (byte_swapped)
  517. val = ((val << 24) | ((val << 8) & 0x00ff0000) | ((val >> 8) & 0x0000ff00) | (val >> 24));
  518. put_data( &val, sizeof(val) );
  519. }
  520. void align_output( unsigned int align )
  521. {
  522. size_t size = align - (output_buffer_pos % align);
  523. if (size == align) return;
  524. check_output_buffer_space( size );
  525. memset( output_buffer + output_buffer_pos, 0, size );
  526. output_buffer_pos += size;
  527. }