1#ifndef lint 2static char *rcsid = "$Id: util.c,v 1.1 2003/06/04 00:27:08 marka Exp $"; 3#endif 4 5/* 6 * Copyright (c) 2000,2002 Japan Network Information Center. 7 * All rights reserved. 8 * 9 * By using this file, you agree to the terms and conditions set forth bellow. 10 * 11 * LICENSE TERMS AND CONDITIONS 12 * 13 * The following License Terms and Conditions apply, unless a different 14 * license is obtained from Japan Network Information Center ("JPNIC"), 15 * a Japanese association, Kokusai-Kougyou-Kanda Bldg 6F, 2-3-4 Uchi-Kanda, 16 * Chiyoda-ku, Tokyo 101-0047, Japan. 17 * 18 * 1. Use, Modification and Redistribution (including distribution of any 19 * modified or derived work) in source and/or binary forms is permitted 20 * under this License Terms and Conditions. 21 * 22 * 2. Redistribution of source code must retain the copyright notices as they 23 * appear in each source code file, this License Terms and Conditions. 24 * 25 * 3. Redistribution in binary form must reproduce the Copyright Notice, 26 * this License Terms and Conditions, in the documentation and/or other 27 * materials provided with the distribution. For the purposes of binary 28 * distribution the "Copyright Notice" refers to the following language: 29 * "Copyright (c) 2000-2002 Japan Network Information Center. All rights reserved." 30 * 31 * 4. The name of JPNIC may not be used to endorse or promote products 32 * derived from this Software without specific prior written approval of 33 * JPNIC. 34 * 35 * 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC 36 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 38 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JPNIC BE LIABLE 39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 40 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 41 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 42 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 43 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 44 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 45 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 46 */ 47 48#include <config.h> 49 50#include <stdio.h> 51#include <stddef.h> 52#include <stdlib.h> 53#include <stdarg.h> 54#include <string.h> 55#include <ctype.h> 56#include <errno.h> 57 58#include <idn/resconf.h> 59#include <idn/converter.h> 60#include <idn/res.h> 61#include <idn/utf8.h> 62 63#include "util.h" 64#include "selectiveencode.h" 65 66extern int line_number; 67 68idn_result_t 69selective_encode(idn_resconf_t conf, idn_action_t actions, 70 char *from, char *to, int tolen) 71{ 72 for (;;) { 73 int len; 74 char *region_start, *region_end; 75 idn_result_t r; 76 char save; 77 78 /* 79 * Find the region that needs conversion. 80 */ 81 r = idn_selectiveencode_findregion(from, ®ion_start, 82 ®ion_end); 83 if (r == idn_notfound) { 84 /* 85 * Not found. Just copy the whole thing. 86 */ 87 if (tolen <= strlen(from)) 88 return (idn_buffer_overflow); 89 (void)strcpy(to, from); 90 return (idn_success); 91 } else if (r != idn_success) { 92 /* This should not happen.. */ 93 errormsg("internal error at line %d: %s\n", 94 line_number, idn_result_tostring(r)); 95 return (r); 96 } 97 98 /* 99 * We have found a region to convert. 100 * First, copy the prefix part verbatim. 101 */ 102 len = region_start - from; 103 if (tolen < len) { 104 errormsg("internal buffer overflow at line %d\n", 105 line_number); 106 return (idn_buffer_overflow); 107 } 108 (void)memcpy(to, from, len); 109 to += len; 110 tolen -= len; 111 112 /* 113 * Terminate the region with NUL. 114 */ 115 save = *region_end; 116 *region_end = '\0'; 117 118 /* 119 * Encode the region. 120 */ 121 r = idn_res_encodename(conf, actions, region_start, to, tolen); 122 123 /* 124 * Restore character. 125 */ 126 *region_end = save; 127 128 if (r != idn_success) 129 return (r); 130 131 len = strlen(to); 132 to += len; 133 tolen -= len; 134 135 from = region_end; 136 } 137} 138 139idn_result_t 140selective_decode(idn_resconf_t conf, idn_action_t actions, 141 char *from, char *to, int tolen) 142{ 143 char *domain_name; 144 char *ignored_chunk; 145 char save; 146 int len; 147 idn_result_t r; 148 149 /* 150 * While `*from' points to a character in a string which may be 151 * a domain name, `domain_name' refers to the beginning of the 152 * domain name. 153 */ 154 domain_name = NULL; 155 156 /* 157 * We ignore chunks matching to the regular expression: 158 * [\-\.][0-9A-Za-z\-\.]* 159 * 160 * While `*from' points to a character in such a chunk, 161 * `ignored_chunk' refers to the beginning of the chunk. 162 */ 163 ignored_chunk = NULL; 164 165 for (;;) { 166 if (*from == '-') { 167 /* 168 * We don't recognize `.-' as a part of domain name. 169 */ 170 if (domain_name != NULL) { 171 if (*(from - 1) == '.') { 172 ignored_chunk = domain_name; 173 domain_name = NULL; 174 } 175 } else if (ignored_chunk == NULL) { 176 ignored_chunk = from; 177 } 178 179 } else if (*from == '.') { 180 /* 181 * We don't recognize `-.' nor `..' as a part of 182 * domain name. 183 */ 184 if (domain_name != NULL) { 185 if (*(from - 1) == '-' || *(from - 1) == '.') { 186 ignored_chunk = domain_name; 187 domain_name = NULL; 188 } 189 } else if (ignored_chunk == NULL) { 190 ignored_chunk = from; 191 } 192 193 } else if (('a' <= *from && *from <= 'z') || 194 ('A' <= *from && *from <= 'Z') || 195 ('0' <= *from && *from <= '9')) { 196 if (ignored_chunk == NULL && domain_name == NULL) 197 domain_name = from; 198 199 } else { 200 if (ignored_chunk != NULL) { 201 /* 202 * `from' reaches the end of the ignored chunk. 203 * Copy the chunk to `to'. 204 */ 205 len = from - ignored_chunk; 206 if (tolen < len) 207 return (idn_buffer_overflow); 208 (void)memcpy(to, ignored_chunk, len); 209 to += len; 210 tolen -= len; 211 212 } else if (domain_name != NULL) { 213 /* 214 * `from' reaches the end of the domain name. 215 * Decode the domain name, and copy the result 216 * to `to'. 217 */ 218 save = *from; 219 *from = '\0'; 220 r = idn_res_decodename(conf, actions, 221 domain_name, to, tolen); 222 *from = save; 223 224 if (r == idn_success) { 225 len = strlen(to); 226 } else if (r == idn_invalid_encoding) { 227 len = from - domain_name; 228 if (tolen < len) 229 return (idn_buffer_overflow); 230 (void)memcpy(to, domain_name, len); 231 } else { 232 return (r); 233 } 234 to += len; 235 tolen -= len; 236 } 237 238 /* 239 * Copy a character `*from' to `to'. 240 */ 241 if (tolen < 1) 242 return (idn_buffer_overflow); 243 *to = *from; 244 to++; 245 tolen--; 246 247 domain_name = NULL; 248 ignored_chunk = NULL; 249 250 if (*from == '\0') 251 break; 252 } 253 254 from++; 255 } 256 257 return (idn_success); 258} 259 260void 261set_defaults(idn_resconf_t conf) { 262 idn_result_t r; 263 264 if ((r = idn_resconf_setdefaults(conf)) != idn_success) { 265 errormsg("error setting default configuration: %s\n", 266 idn_result_tostring(r)); 267 exit(1); 268 } 269} 270 271void 272load_conf_file(idn_resconf_t conf, const char *file) { 273 idn_result_t r; 274 275 if ((r = idn_resconf_loadfile(conf, file)) != idn_success) { 276 errormsg("error reading configuration file: %s\n", 277 idn_result_tostring(r)); 278 exit(1); 279 } 280} 281 282void 283set_encoding_alias(const char *encoding_alias) { 284 idn_result_t r; 285 286 if ((r = idn_converter_resetalias()) != idn_success) { 287 errormsg("cannot reset alias information: %s\n", 288 idn_result_tostring(r)); 289 exit(1); 290 } 291 292 if ((r = idn_converter_aliasfile(encoding_alias)) != idn_success) { 293 errormsg("cannot read alias file %s: %s\n", 294 encoding_alias, idn_result_tostring(r)); 295 exit(1); 296 } 297} 298 299void 300set_localcode(idn_resconf_t conf, const char *code) { 301 idn_result_t r; 302 303 r = idn_resconf_setlocalconvertername(conf, code, 304 IDN_CONVERTER_RTCHECK); 305 if (r != idn_success) { 306 errormsg("cannot create converter for codeset %s: %s\n", 307 code, idn_result_tostring(r)); 308 exit(1); 309 } 310} 311 312void 313set_idncode(idn_resconf_t conf, const char *code) { 314 idn_result_t r; 315 316 r = idn_resconf_setidnconvertername(conf, code, 317 IDN_CONVERTER_RTCHECK); 318 if (r != idn_success) { 319 errormsg("cannot create converter for codeset %s: %s\n", 320 code, idn_result_tostring(r)); 321 exit(1); 322 } 323} 324 325void 326set_delimitermapper(idn_resconf_t conf, unsigned long *delimiters, 327 int ndelimiters) { 328 idn_result_t r; 329 330 r = idn_resconf_addalldelimitermapucs(conf, delimiters, ndelimiters); 331 if (r != idn_success) { 332 errormsg("cannot add delimiter: %s\n", 333 idn_result_tostring(r)); 334 exit(1); 335 } 336} 337 338void 339set_localmapper(idn_resconf_t conf, char **mappers, int nmappers) { 340 idn_result_t r; 341 342 /* Add mapping. */ 343 r = idn_resconf_addalllocalmapselectornames(conf, 344 IDN_MAPSELECTOR_DEFAULTTLD, 345 (const char **)mappers, 346 nmappers); 347 if (r != idn_success) { 348 errormsg("cannot add local map: %s\n", 349 idn_result_tostring(r)); 350 exit(1); 351 } 352} 353 354void 355set_nameprep(idn_resconf_t conf, char *version) { 356 idn_result_t r; 357 358 r = idn_resconf_setnameprepversion(conf, version); 359 if (r != idn_success) { 360 errormsg("error setting nameprep %s: %s\n", 361 version, idn_result_tostring(r)); 362 exit(1); 363 } 364} 365 366void 367set_mapper(idn_resconf_t conf, char **mappers, int nmappers) { 368 idn_result_t r; 369 370 /* Configure mapper. */ 371 r = idn_resconf_addallmappernames(conf, (const char **)mappers, 372 nmappers); 373 if (r != idn_success) { 374 errormsg("cannot add nameprep map: %s\n", 375 idn_result_tostring(r)); 376 exit(1); 377 } 378} 379 380void 381set_normalizer(idn_resconf_t conf, char **normalizers, int nnormalizer) { 382 idn_result_t r; 383 384 r = idn_resconf_addallnormalizernames(conf, 385 (const char **)normalizers, 386 nnormalizer); 387 if (r != idn_success) { 388 errormsg("cannot add normalizer: %s\n", 389 idn_result_tostring(r)); 390 exit(1); 391 } 392} 393 394void 395set_prohibit_checkers(idn_resconf_t conf, char **prohibits, int nprohibits) { 396 idn_result_t r; 397 398 r = idn_resconf_addallprohibitcheckernames(conf, 399 (const char **)prohibits, 400 nprohibits); 401 if (r != idn_success) { 402 errormsg("cannot add prohibit checker: %s\n", 403 idn_result_tostring(r)); 404 exit(1); 405 } 406} 407 408void 409set_unassigned_checkers(idn_resconf_t conf, char **unassigns, int nunassigns) { 410 idn_result_t r; 411 412 r = idn_resconf_addallunassignedcheckernames(conf, 413 (const char **)unassigns, 414 nunassigns); 415 if (r != idn_success) { 416 errormsg("cannot add unassigned checker: %s\n", 417 idn_result_tostring(r)); 418 exit(1); 419 } 420} 421 422void 423errormsg(const char *fmt, ...) { 424 va_list args; 425 426 va_start(args, fmt); 427 vfprintf(stderr, fmt, args); 428 va_end(args); 429} 430 431 432/* 433 * Dynamic Stirng Buffer Utility 434 */ 435 436void 437strbuf_init(idnconv_strbuf_t *buf) { 438 /* 439 * Initialize the given string buffer. 440 * Caller must allocate the structure (idnconv_strbuf_t) 441 * as an automatic variable or by malloc(). 442 */ 443 buf->str = buf->local_buf; 444 buf->str[0] = '\0'; 445 buf->size = sizeof(buf->local_buf); 446} 447 448void 449strbuf_reset(idnconv_strbuf_t *buf) { 450 /* 451 * Reset the given string buffer. 452 * Free memory allocated by this utility, and 453 * re-initialize. 454 */ 455 if (buf->str != NULL && buf->str != buf->local_buf) { 456 free(buf->str); 457 } 458 strbuf_init(buf); 459} 460 461char * 462strbuf_get(idnconv_strbuf_t *buf) { 463 /* 464 * Get the pointer of the buffer. 465 */ 466 return (buf->str); 467} 468 469size_t 470strbuf_size(idnconv_strbuf_t *buf) { 471 /* 472 * Get the allocated size of the buffer. 473 */ 474 return (buf->size); 475} 476 477char * 478strbuf_copy(idnconv_strbuf_t *buf, const char *str) { 479 /* 480 * Copy STR to BUF. 481 */ 482 size_t len = strlen(str); 483 484 if (strbuf_alloc(buf, len + 1) == NULL) 485 return (NULL); 486 strcpy(buf->str, str); 487 return (buf->str); 488} 489 490char * 491strbuf_append(idnconv_strbuf_t *buf, const char *str) { 492 /* 493 * Append STR to the end of BUF. 494 */ 495 size_t len1 = strlen(buf->str); 496 size_t len2 = strlen(str); 497 char *p; 498#define MARGIN 50 499 500 p = strbuf_alloc(buf, len1 + len2 + 1 + MARGIN); 501 if (p != NULL) 502 strcpy(buf->str + len1, str); 503 return (p); 504} 505 506char * 507strbuf_alloc(idnconv_strbuf_t *buf, size_t size) { 508 /* 509 * Reallocate the buffer of BUF if needed 510 * so that BUF can hold SIZE bytes of data at least. 511 */ 512 char *p; 513 514 if (buf->size >= size) 515 return (buf->str); 516 if (buf->str == buf->local_buf) { 517 if ((p = malloc(size)) == NULL) 518 return (NULL); 519 memcpy(p, buf->local_buf, sizeof(buf->local_buf)); 520 } else { 521 if ((p = realloc(buf->str, size)) == NULL) 522 return (NULL); 523 } 524 buf->str = p; 525 buf->size = size; 526 return (buf->str); 527} 528 529char * 530strbuf_double(idnconv_strbuf_t *buf) { 531 /* 532 * Double the size of the buffer of BUF. 533 */ 534 return (strbuf_alloc(buf, buf->size * 2)); 535} 536 537char * 538strbuf_getline(idnconv_strbuf_t *buf, FILE *fp) { 539 /* 540 * Read a line from FP. 541 */ 542 char s[256]; 543 544 buf->str[0] = '\0'; 545 while (fgets(s, sizeof(s), fp) != NULL) { 546 if (strbuf_append(buf, s) == NULL) 547 return (NULL); 548 if (strlen(s) < sizeof(s) - 1 || s[sizeof(s) - 2] == '\n') 549 return (buf->str); 550 } 551 if (buf->str[0] != '\0') 552 return (buf->str); 553 return (NULL); 554} 555