indep.c (14563B)
1 /* $Id$ */ 2 #include "fm.h" 3 #include <stdio.h> 4 #ifndef __MINGW32_VERSION 5 #include <pwd.h> 6 #endif /* __MINGW32_VERSION */ 7 #include <sys/param.h> 8 #include <sys/types.h> 9 #include <stdlib.h> 10 #include "indep.h" 11 #include "Str.h" 12 #include <gc.h> 13 #include "myctype.h" 14 #include "entity.h" 15 16 unsigned char QUOTE_MAP[0x100] = { 17 /* NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI */ 18 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 19 /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */ 20 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 21 /* SPC ! " # $ % & ' ( ) * + , - . / */ 22 24, 72, 76, 40, 8, 40, 41, 72, 72, 72, 72, 40, 72, 8, 0, 64, 23 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */ 24 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 72, 74, 72, 75, 40, 25 /* @ A B C D E F G H I J K L M N O */ 26 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27 /* P Q R S T U V W X Y Z [ \ ] ^ _ */ 28 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 0, 29 /* ` a b c d e f g h i j k l m n o */ 30 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 31 /* p q r s t u v w x y z { | } ~ DEL */ 32 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 72, 72, 72, 72, 24, 33 34 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 35 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 36 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 37 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 38 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 39 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 40 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 41 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 42 }; 43 44 char *HTML_QUOTE_MAP[] = { 45 NULL, 46 "&", 47 "<", 48 ">", 49 """, 50 NULL, 51 NULL, 52 NULL, 53 }; 54 55 clen_t 56 strtoclen(const char *s) 57 { 58 #ifdef HAVE_STRTOLL 59 return strtoll(s, NULL, 10); 60 #elif defined(HAVE_STRTOQ) 61 return strtoq(s, NULL, 10); 62 #elif defined(HAVE_ATOLL) 63 return atoll(s); 64 #elif defined(HAVE_ATOQ) 65 return atoq(s); 66 #else 67 return atoi(s); 68 #endif 69 } 70 71 #ifndef HAVE_BCOPY 72 void 73 bcopy(const void *src, void *dest, int len) 74 { 75 int i; 76 if (src == dest) 77 return; 78 if (src < dest) { 79 for (i = len - 1; i >= 0; i--) 80 ((char *)dest)[i] = ((const char *)src)[i]; 81 } 82 else { /* src > dest */ 83 for (i = 0; i < len; i++) 84 ((char *)dest)[i] = ((const char *)src)[i]; 85 } 86 } 87 88 void 89 bzero(void *ptr, int len) 90 { 91 int i; 92 char *p = ptr; 93 for (i = 0; i < len; i++) 94 *(p++) = 0; 95 } 96 #endif /* not HAVE_BCOPY */ 97 98 char * 99 allocStr(const char *s, int len) 100 { 101 char *ptr; 102 103 if (s == NULL) 104 return NULL; 105 if (len < 0) 106 len = strlen(s); 107 ptr = NewAtom_N(char, len + 1); 108 if (ptr == NULL) { 109 fprintf(stderr, "fm: Can't allocate string. Give me more memory!\n"); 110 exit(-1); 111 } 112 bcopy(s, ptr, len); 113 ptr[len] = '\0'; 114 return ptr; 115 } 116 117 int 118 strCmp(const void *s1, const void *s2) 119 { 120 return strcmp(*(const char **)s1, *(const char **)s2); 121 } 122 123 char * 124 currentdir() 125 { 126 char *path; 127 #ifdef HAVE_GETCWD 128 #ifdef MAXPATHLEN 129 path = NewAtom_N(char, MAXPATHLEN); 130 getcwd(path, MAXPATHLEN); 131 #else 132 path = getcwd(NULL, 0); 133 #endif 134 #else /* not HAVE_GETCWD */ 135 #ifdef HAVE_GETWD 136 path = NewAtom_N(char, 1024); 137 getwd(path); 138 #else /* not HAVE_GETWD */ 139 FILE *f; 140 char *p; 141 path = NewAtom_N(char, 1024); 142 f = popen("pwd", "r"); 143 fgets(path, 1024, f); 144 pclose(f); 145 for (p = path; *p; p++) 146 if (*p == '\n') { 147 *p = '\0'; 148 break; 149 } 150 #endif /* not HAVE_GETWD */ 151 #endif /* not HAVE_GETCWD */ 152 return path; 153 } 154 155 char * 156 cleanupName(char *name) 157 { 158 char *buf, *p, *q; 159 160 buf = allocStr(name, -1); 161 p = buf; 162 q = name; 163 while (*q != '\0') { 164 if (strncmp(p, "/../", 4) == 0) { /* foo/bar/../FOO */ 165 if (p - 2 == buf && strncmp(p - 2, "..", 2) == 0) { 166 /* ../../ */ 167 p += 3; 168 q += 3; 169 } 170 else if (p - 3 >= buf && strncmp(p - 3, "/..", 3) == 0) { 171 /* ../../../ */ 172 p += 3; 173 q += 3; 174 } 175 else { 176 while (p != buf && *--p != '/') ; /* ->foo/FOO */ 177 *p = '\0'; 178 q += 3; 179 strcat(buf, q); 180 } 181 } 182 else if (strcmp(p, "/..") == 0) { /* foo/bar/.. */ 183 if (p - 2 == buf && strncmp(p - 2, "..", 2) == 0) { 184 /* ../.. */ 185 } 186 else if (p - 3 >= buf && strncmp(p - 3, "/..", 3) == 0) { 187 /* ../../.. */ 188 } 189 else { 190 while (p != buf && *--p != '/') ; /* ->foo/ */ 191 *++p = '\0'; 192 } 193 break; 194 } 195 else if (strncmp(p, "/./", 3) == 0) { /* foo/./bar */ 196 *p = '\0'; /* -> foo/bar */ 197 q += 2; 198 strcat(buf, q); 199 } 200 else if (strcmp(p, "/.") == 0) { /* foo/. */ 201 *++p = '\0'; /* -> foo/ */ 202 break; 203 } 204 else if (strncmp(p, "//", 2) == 0) { /* foo//bar */ 205 /* -> foo/bar */ 206 *p = '\0'; 207 q++; 208 strcat(buf, q); 209 } 210 else { 211 p++; 212 q++; 213 } 214 } 215 return buf; 216 } 217 218 char * 219 expandPath(char *name) 220 { 221 char *p; 222 struct passwd *passent, *getpwnam(const char *); 223 Str extpath = NULL; 224 225 if (name == NULL) 226 return NULL; 227 p = name; 228 if (*p == '~') { 229 p++; 230 #ifndef __MINGW32_VERSION 231 if (IS_ALPHA(*p)) { 232 char *q = strchr(p, '/'); 233 if (q) { /* ~user/dir... */ 234 passent = getpwnam(allocStr(p, q - p)); 235 p = q; 236 } 237 else { /* ~user */ 238 passent = getpwnam(p); 239 p = ""; 240 } 241 if (!passent) 242 goto rest; 243 extpath = Strnew_charp(passent->pw_dir); 244 } else 245 #endif /* __MINGW32_VERSION */ 246 if (*p == '/' || *p == '\0') { /* ~/dir... or ~ */ 247 extpath = Strnew_charp(getenv("HOME")); 248 } 249 else 250 goto rest; 251 if (Strcmp_charp(extpath, "/") == 0 && *p == '/') 252 p++; 253 Strcat_charp(extpath, p); 254 return extpath->ptr; 255 } 256 rest: 257 return name; 258 } 259 260 #ifndef HAVE_STRCHR 261 char * 262 strchr(const char *s, int c) 263 { 264 while (*s) { 265 if ((unsigned char)*s == c) 266 return (char *)s; 267 s++; 268 } 269 return NULL; 270 } 271 #endif /* not HAVE_STRCHR */ 272 273 #ifndef HAVE_STRCASECMP 274 int 275 strcasecmp(const char *s1, const char *s2) 276 { 277 int x; 278 while (*s1) { 279 x = TOLOWER(*s1) - TOLOWER(*s2); 280 if (x != 0) 281 return x; 282 s1++; 283 s2++; 284 } 285 return -TOLOWER(*s2); 286 } 287 288 int 289 strncasecmp(const char *s1, const char *s2, size_t n) 290 { 291 int x; 292 while (*s1 && n) { 293 x = TOLOWER(*s1) - TOLOWER(*s2); 294 if (x != 0) 295 return x; 296 s1++; 297 s2++; 298 n--; 299 } 300 return n ? -TOLOWER(*s2) : 0; 301 } 302 #endif /* not HAVE_STRCASECMP */ 303 304 #ifndef HAVE_STRCASESTR 305 /* string search using the simplest algorithm */ 306 char * 307 strcasestr(const char *s1, const char *s2) 308 { 309 int len1, len2; 310 if (s2 == NULL) 311 return (char *)s1; 312 if (*s2 == '\0') 313 return (char *)s1; 314 len1 = strlen(s1); 315 len2 = strlen(s2); 316 while (*s1 && len1 >= len2) { 317 if (strncasecmp(s1, s2, len2) == 0) 318 return (char *)s1; 319 s1++; 320 len1--; 321 } 322 return 0; 323 } 324 #endif 325 326 static int 327 strcasematch(char *s1, char *s2) 328 { 329 int x; 330 while (*s1) { 331 if (*s2 == '\0') 332 return 1; 333 x = TOLOWER(*s1) - TOLOWER(*s2); 334 if (x != 0) 335 break; 336 s1++; 337 s2++; 338 } 339 return (*s2 == '\0'); 340 } 341 342 /* search multiple strings */ 343 int 344 strcasemstr(char *str, char *srch[], char **ret_ptr) 345 { 346 int i; 347 while (*str) { 348 for (i = 0; srch[i]; i++) { 349 if (strcasematch(str, srch[i])) { 350 if (ret_ptr) 351 *ret_ptr = str; 352 return i; 353 } 354 } 355 str++; 356 } 357 return -1; 358 } 359 360 char * 361 remove_space(char *str) 362 { 363 char *p, *q; 364 365 for (p = str; *p && IS_SPACE(*p); p++) ; 366 for (q = p; *q; q++) ; 367 for (; q > p && IS_SPACE(*(q - 1)); q--) ; 368 if (*q != '\0') 369 return Strnew_charp_n(p, q - p)->ptr; 370 return p; 371 } 372 373 int 374 non_null(char *s) 375 { 376 if (s == NULL) 377 return FALSE; 378 while (*s) { 379 if (!IS_SPACE(*s)) 380 return TRUE; 381 s++; 382 } 383 return FALSE; 384 } 385 386 void 387 cleanup_line(Str s, int mode) 388 { 389 if (s->length >= 2 && 390 s->ptr[s->length - 2] == '\r' && s->ptr[s->length - 1] == '\n') { 391 Strshrink(s, 2); 392 Strcat_char(s, '\n'); 393 } 394 else if (Strlastchar(s) == '\r') 395 s->ptr[s->length - 1] = '\n'; 396 else if (Strlastchar(s) != '\n') 397 Strcat_char(s, '\n'); 398 if (mode != PAGER_MODE) { 399 int i; 400 for (i = 0; i < s->length; i++) { 401 if (s->ptr[i] == '\0') 402 s->ptr[i] = ' '; 403 } 404 } 405 } 406 407 int 408 getescapechar(char **str) 409 { 410 int dummy = -1; 411 char *p = *str, *q; 412 int strict_entity = TRUE; 413 414 if (*p == '&') 415 p++; 416 if (*p == '#') { 417 p++; 418 if (*p == 'x' || *p == 'X') { 419 p++; 420 if (!IS_XDIGIT(*p)) { 421 *str = p; 422 return -1; 423 } 424 for (dummy = GET_MYCDIGIT(*p), p++; IS_XDIGIT(*p); p++) 425 dummy = dummy * 0x10 + GET_MYCDIGIT(*p); 426 if (*p == ';') 427 p++; 428 *str = p; 429 return dummy; 430 } 431 else { 432 if (!IS_DIGIT(*p)) { 433 *str = p; 434 return -1; 435 } 436 for (dummy = GET_MYCDIGIT(*p), p++; IS_DIGIT(*p); p++) 437 dummy = dummy * 10 + GET_MYCDIGIT(*p); 438 if (*p == ';') 439 p++; 440 *str = p; 441 return dummy; 442 } 443 } 444 if (!IS_ALPHA(*p)) { 445 *str = p; 446 return -1; 447 } 448 q = p; 449 for (p++; IS_ALNUM(*p); p++) ; 450 q = allocStr(q, p - q); 451 if (strcasestr("lt gt amp quot nbsp", q) && *p != '=') { 452 /* a character entity MUST be terminated with ";". However, 453 * there's MANY web pages which uses < , > or something 454 * like them as <, >, etc. Therefore, we treat the most 455 * popular character entities (including &#xxxx;) without 456 * the last ";" as character entities. If the trailing character 457 * is "=", it must be a part of query in an URL. So <=, >=, etc. 458 * are not regarded as character entities. 459 */ 460 strict_entity = FALSE; 461 } 462 if (*p == ';') 463 p++; 464 else if (strict_entity) { 465 *str = p; 466 return -1; 467 } 468 *str = p; 469 return getHash_si(&entity, q, -1); 470 } 471 472 char * 473 getescapecmd(char **s) 474 { 475 char *save = *s; 476 Str tmp; 477 int ch = getescapechar(s); 478 479 if (ch >= 0) 480 return conv_entity(ch); 481 482 if (*save != '&') 483 tmp = Strnew_charp("&"); 484 else 485 tmp = Strnew(); 486 Strcat_charp_n(tmp, save, *s - save); 487 return tmp->ptr; 488 } 489 490 char * 491 html_quote(char *str) 492 { 493 Str tmp = NULL; 494 char *p, *q; 495 496 for (p = str; *p; p++) { 497 q = html_quote_char(*p); 498 if (q) { 499 if (tmp == NULL) 500 tmp = Strnew_charp_n(str, (int)(p - str)); 501 Strcat_charp(tmp, q); 502 } 503 else { 504 if (tmp) 505 Strcat_char(tmp, *p); 506 } 507 } 508 if (tmp) 509 return tmp->ptr; 510 return str; 511 } 512 513 char * 514 html_unquote(char *str) 515 { 516 Str tmp = NULL; 517 char *p, *q; 518 519 for (p = str; *p;) { 520 if (*p == '&') { 521 if (tmp == NULL) 522 tmp = Strnew_charp_n(str, (int)(p - str)); 523 q = getescapecmd(&p); 524 Strcat_charp(tmp, q); 525 } 526 else { 527 if (tmp) 528 Strcat_char(tmp, *p); 529 p++; 530 } 531 } 532 533 if (tmp) 534 return tmp->ptr; 535 return str; 536 } 537 538 static char xdigit[0x10] = "0123456789ABCDEF"; 539 540 #define url_unquote_char(pstr) \ 541 ((IS_XDIGIT((*(pstr))[1]) && IS_XDIGIT((*(pstr))[2])) ? \ 542 (*(pstr) += 3, (GET_MYCDIGIT((*(pstr))[-2]) << 4) | GET_MYCDIGIT((*(pstr))[-1])) : \ 543 -1) 544 545 char * 546 url_quote(char *str) 547 { 548 Str tmp = NULL; 549 char *p; 550 551 for (p = str; *p; p++) { 552 if (is_url_quote(*p)) { 553 if (tmp == NULL) 554 tmp = Strnew_charp_n(str, (int)(p - str)); 555 Strcat_char(tmp, '%'); 556 Strcat_char(tmp, xdigit[((unsigned char)*p >> 4) & 0xF]); 557 Strcat_char(tmp, xdigit[(unsigned char)*p & 0xF]); 558 } 559 else { 560 if (tmp) 561 Strcat_char(tmp, *p); 562 } 563 } 564 if (tmp) 565 return tmp->ptr; 566 return str; 567 } 568 569 char * 570 file_quote(char *str) 571 { 572 Str tmp = NULL; 573 char *p; 574 char buf[4]; 575 576 for (p = str; *p; p++) { 577 if (is_file_quote(*p)) { 578 if (tmp == NULL) 579 tmp = Strnew_charp_n(str, (int)(p - str)); 580 sprintf(buf, "%%%02X", (unsigned char)*p); 581 Strcat_charp(tmp, buf); 582 } 583 else { 584 if (tmp) 585 Strcat_char(tmp, *p); 586 } 587 } 588 if (tmp) 589 return tmp->ptr; 590 return str; 591 } 592 593 char * 594 file_unquote(char *str) 595 { 596 Str tmp = NULL; 597 char *p, *q; 598 int c; 599 600 for (p = str; *p;) { 601 if (*p == '%') { 602 q = p; 603 c = url_unquote_char(&q); 604 if (c >= 0) { 605 if (tmp == NULL) 606 tmp = Strnew_charp_n(str, (int)(p - str)); 607 if (c != '\0' && c != '\n' && c != '\r') 608 Strcat_char(tmp, (char)c); 609 p = q; 610 continue; 611 } 612 } 613 if (tmp) 614 Strcat_char(tmp, *p); 615 p++; 616 } 617 if (tmp) 618 return tmp->ptr; 619 return str; 620 } 621 622 Str 623 Str_form_quote(Str x) 624 { 625 Str tmp = NULL; 626 char *p = x->ptr, *ep = x->ptr + x->length; 627 char buf[4]; 628 629 for (; p < ep; p++) { 630 if (*p == ' ') { 631 if (tmp == NULL) 632 tmp = Strnew_charp_n(x->ptr, (int)(p - x->ptr)); 633 Strcat_char(tmp, '+'); 634 } 635 else if (is_url_unsafe(*p)) { 636 if (tmp == NULL) 637 tmp = Strnew_charp_n(x->ptr, (int)(p - x->ptr)); 638 sprintf(buf, "%%%02X", (unsigned char)*p); 639 Strcat_charp(tmp, buf); 640 } 641 else { 642 if (tmp) 643 Strcat_char(tmp, *p); 644 } 645 } 646 if (tmp) 647 return tmp; 648 return x; 649 } 650 651 652 Str 653 Str_url_unquote(Str x, int is_form, int safe) 654 { 655 Str tmp = NULL; 656 char *p = x->ptr, *ep = x->ptr + x->length, *q; 657 int c; 658 659 for (; p < ep;) { 660 if (is_form && *p == '+') { 661 if (tmp == NULL) 662 tmp = Strnew_charp_n(x->ptr, (int)(p - x->ptr)); 663 Strcat_char(tmp, ' '); 664 p++; 665 continue; 666 } 667 else if (*p == '%') { 668 q = p; 669 c = url_unquote_char(&q); 670 if (c >= 0 && (!safe || !IS_ASCII(c) || !is_file_quote(c))) { 671 if (tmp == NULL) 672 tmp = Strnew_charp_n(x->ptr, (int)(p - x->ptr)); 673 Strcat_char(tmp, (char)c); 674 p = q; 675 continue; 676 } 677 } 678 if (tmp) 679 Strcat_char(tmp, *p); 680 p++; 681 } 682 if (tmp) 683 return tmp; 684 return x; 685 } 686 687 char * 688 shell_quote(char *str) 689 { 690 Str tmp = NULL; 691 char *p; 692 693 for (p = str; *p; p++) { 694 if (is_shell_unsafe(*p)) { 695 if (tmp == NULL) 696 tmp = Strnew_charp_n(str, (int)(p - str)); 697 Strcat_char(tmp, '\\'); 698 Strcat_char(tmp, *p); 699 } 700 else { 701 if (tmp) 702 Strcat_char(tmp, *p); 703 } 704 } 705 if (tmp) 706 return tmp->ptr; 707 return str; 708 } 709 710 static char * 711 w3m_dir(const char *name, char *dft) 712 { 713 #ifdef USE_PATH_ENVVAR 714 char *value = getenv(name); 715 return value ? value : dft; 716 #else 717 return dft; 718 #endif 719 } 720 721 char * 722 w3m_auxbin_dir() 723 { 724 return w3m_dir("W3M_AUXBIN_DIR", AUXBIN_DIR); 725 } 726 727 char * 728 w3m_lib_dir() 729 { 730 /* FIXME: use W3M_CGIBIN_DIR? */ 731 return w3m_dir("W3M_LIB_DIR", CGIBIN_DIR); 732 } 733 734 char * 735 w3m_etc_dir() 736 { 737 return w3m_dir("W3M_ETC_DIR", ETC_DIR); 738 } 739 740 char * 741 w3m_conf_dir() 742 { 743 return w3m_dir("W3M_CONF_DIR", CONF_DIR); 744 } 745 746 char * 747 w3m_help_dir() 748 { 749 return w3m_dir("W3M_HELP_DIR", HELP_DIR); 750 } 751 /* Local Variables: */ 752 /* c-basic-offset: 4 */ 753 /* tab-width: 8 */ 754 /* End: */