"Fossies" - the Fresh Open Source Software Archive

Member "links-1.04/default.c" (27 Nov 2018, 43118 Bytes) of package /linux/www/links-1.04.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "default.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.03_vs_1.04.

    1 #include "links.h"
    2 
    3 unsigned char system_name[MAX_STR_LEN];
    4 
    5 void get_system_name()
    6 {
    7 #ifdef OS2
    8     if (!os_get_system_name(system_name))
    9         return;
   10 #endif
   11 #if defined(HAVE_SYS_UTSNAME_H) && defined(HAVE_UNAME)
   12     {
   13         struct utsname name;
   14         int rs;
   15         memset(&name, 0, sizeof name);
   16         EINTRLOOP(rs, uname(&name));
   17         if (!rs) {
   18 #ifdef OPENVMS
   19             unsigned char * volatile p;
   20 #endif
   21             unsigned char *str = init_str();
   22             int l = 0;
   23             add_to_str(&str, &l, name.sysname);
   24             add_to_str(&str, &l, " ");
   25 #ifdef OPENVMS
   26             add_to_str(&str, &l, name.version);
   27 #else
   28             add_to_str(&str, &l, name.release);
   29 #endif
   30             add_to_str(&str, &l, " ");
   31 #ifdef OPENVMS
   32             p = name.nodename + sizeof(name.nodename);
   33             if ((unsigned char *)(&name + 1) - p >= 16 && memchr(p, 0, 16))
   34                 add_to_str(&str, &l, cast_uchar p);
   35             else
   36 #endif
   37             add_to_str(&str, &l, name.machine);
   38             safe_strncpy(system_name, str, MAX_STR_LEN);
   39             mem_free(str);
   40             return;
   41         }
   42     }
   43 #endif
   44 #ifdef HAVE_POPEN
   45     if (0) {
   46         FILE *f;
   47         unsigned char *p;
   48         memset(system_name, 0, MAX_STR_LEN);
   49         ENULLLOOP(f, popen("uname -srm", "r"));
   50         if (!f) goto fail;
   51         if (fread(system_name, 1, MAX_STR_LEN - 1, f) <= 0) {
   52             pclose(f);
   53             goto fail;
   54         }
   55         pclose(f);
   56         for (p = system_name; *p; p++) if (*p < ' ') {
   57             *p = 0;
   58             break;
   59         }
   60         if (system_name[0]) return;
   61     }
   62     fail:
   63 #endif
   64     strcpy(system_name, SYSTEM_NAME);
   65 }
   66 
   67 unsigned char compiler_name[MAX_STR_LEN];
   68 
   69 static void get_compiler_name(void)
   70 {
   71 #if defined(__BORLANDC__)
   72 
   73     int w = __BORLANDC__+0;
   74     int v1 = w / 0x100;
   75     int v2 = w / 0x10 % 0x10;
   76     int v3 = w % 0x10;
   77     if (v1 == 4 && v2 < 5) v1 = 3;
   78     if (v1 == 4 && v2 == 5) v2 = 0;
   79 
   80     if (!v3) sprintf(cast_char compiler_name, "Borland C %d.%d", v1, v2);
   81     else sprintf(cast_char compiler_name, "Borland C %d.%d.%d", v1, v2, v3);
   82 
   83 #elif defined(__clang__)
   84 
   85 #if !defined(__clang_major__) || !defined(__clang_minor__)
   86     sprintf(cast_char compiler_name, "LLVM/Clang");
   87 #else
   88     int v1 = __clang_major__+0;
   89     int v2 = __clang_minor__+0;
   90 #ifdef __clang_patchlevel__
   91     int v3 = __clang_patchlevel__+0;
   92 #else
   93     int v3 = 0;
   94 #endif
   95     if (v3 > 0) sprintf(cast_char compiler_name, "LLVM/Clang %d.%d.%d", v1, v2, v3);
   96     else sprintf(cast_char compiler_name, "LLVM/Clang %d.%d", v1, v2);
   97 #endif
   98 
   99 #elif defined(__COMO_VERSION__)
  100 
  101     int w = __COMO_VERSION__+0;
  102     int v1 = w / 100;
  103     int v2 = w % 100;
  104     if (!(v2 % 10)) sprintf(cast_char compiler_name, "Comeau C %d.%d", v1, v2 / 10);
  105     else sprintf(cast_char compiler_name, "Comeau C %d.%02d", v1, v2);
  106 
  107 #elif defined(__convexc__)
  108 
  109     sprintf(cast_char compiler_name, "Convex C");
  110 
  111 #elif defined(_CRAYC)
  112 
  113 #if !defined(_RELEASE) || !defined(_RELEASE_MINOR)
  114     sprintf(cast_char compiler_name, "Cray C");
  115 #else
  116     int v1 = _RELEASE+0;
  117     int v2 = _RELEASE_MINOR+0;
  118     sprintf(cast_char compiler_name, "Cray C %d.%d", v1, v2);
  119 #endif
  120 
  121 #elif defined(__DCC__)
  122 
  123 #ifndef __VERSION_NUMBER__
  124     sprintf(cast_char compiler_name, "Diab C");
  125 #else
  126     int w = __VERSION_NUMBER__+0;
  127     int v1 = w / 1000;
  128     int v2 = w / 100 % 10;
  129     int v3 = w % 100;
  130     sprintf(cast_char compiler_name, "Diab C %d.%d.%02d", v1, v2, v3);
  131 #endif
  132 
  133 #elif defined(__DMC__)
  134 
  135     int w = __DMC__+0;
  136     int v1 = w / 0x100;
  137     int v2 = w / 0x10 % 0x10;
  138     int v3 = w % 0x10;
  139     if (!v3) sprintf(cast_char compiler_name, "Digital Mars C %d.%d", v1, v2);
  140     else sprintf(cast_char compiler_name, "Digital Mars C %d.%d.%d", v1, v2, v3);
  141 
  142 #elif defined(__DECC_VER)
  143 
  144     int w = __DECC_VER+0;
  145     int v1 = w / 10000000;
  146     int v2 = w / 100000 % 100;
  147     int v3 = w % 10000;
  148     sprintf(cast_char compiler_name, "DEC C %d.%d-%03d", v1, v2, v3);
  149 
  150 #elif defined(__ghs__)
  151 
  152 #ifndef __GHS_VERSION_NUMBER__
  153     sprintf(cast_char compiler_name, "Green Hill C");
  154 #else
  155     int w = __GHS_VERSION_NUMBER__+0;
  156     int v1 = w / 100;
  157     int v2 = w / 10 % 10;
  158     int v3 = w % 10;
  159     sprintf(cast_char compiler_name, "Green Hill C %d.%d.%d", v1, v2, v3);
  160 #endif
  161 
  162 #elif defined(__HIGHC__)
  163 
  164     sprintf(cast_char compiler_name, "MetaWare High C");
  165 
  166 #elif defined(__HP_cc)
  167 
  168     int w = __HP_cc+0;
  169     int v1 = w / 10000;
  170     int v2 = w / 100 % 100;
  171     int v3 = w % 100;
  172     if (w <= 1) sprintf(cast_char compiler_name, "HP CC");
  173     else sprintf(cast_char compiler_name, "HP CC %d.%02d.%02d", v1, v2, v3);
  174 
  175 #elif defined(__xlc__)
  176 
  177     int w = __xlc__+0;
  178     int v1 = w / 0x100;
  179     int v2 = w % 0x100;
  180     sprintf(cast_char compiler_name, "IBM XL C %X.%X", v1, v2);
  181 
  182 #elif defined(__IBMC__) && defined(__COMPILER_VER__)
  183 
  184     unsigned w = __COMPILER_VER__+0;
  185     int v0 = w / 0x10000000;
  186     int v1 = w / 0x1000000 % 0x10;
  187     int v2 = w / 0x10000 % 0x100;
  188     int v3 = w % 0x10000;
  189     unsigned char *os = !v0 ? "S/370" : v0 == 1 ? "OS/390" : v0 == 4 ? "z/OS" : "";
  190     sprintf(cast_char compiler_name, "IBM%s%s XL C %X.%0X.%X", *os ? " " : "", os, v1, v2, v3);
  191 
  192 #elif defined(__ICC)
  193 
  194     int w = __ICC+0;
  195     int v1 = w / 100;
  196     int v2 = w % 100;
  197     if (!(v2 % 10)) sprintf(cast_char compiler_name, "Intel C %d.%d", v1, v2 / 10);
  198     else sprintf(cast_char compiler_name, "Intel C %d.%02d", v1, v2);
  199 
  200 #elif defined(__LCC__)
  201 
  202     sprintf(cast_char compiler_name, "LCC");
  203 
  204 #elif defined(__NDPC__)
  205 
  206     sprintf(cast_char compiler_name, "Microway NDP C");
  207 
  208 #elif defined(_MSC_VER)
  209 
  210     int w = _MSC_VER+0;
  211     int v1 = w / 100;
  212     int v2 = w % 100;
  213     unsigned char *visual = cast_uchar "";
  214     if (v1 >= 8) {
  215         v1 -= 6;
  216         if (v1 == 2) v1 = 1;
  217         visual = cast_uchar "Visual ";
  218     }
  219     if (!(v2 % 10)) sprintf(cast_char compiler_name, "Microsoft %sC %d.%d", visual, v1, v2 / 10);
  220     else sprintf(cast_char compiler_name, "Microsoft %sC %d.%02d", visual, v1, v2);
  221 
  222 #elif defined(__MWERKS__)
  223 
  224     int w = __MWERKS__+0;
  225     int v1 = w / 0x1000;
  226     int v2 = w / 0x100 % 0x10;
  227     int v3 = w % 0x100;
  228     if (w <= 1) sprintf(cast_char compiler_name, "Metrowerks CodeWarrior");
  229     sprintf(cast_char compiler_name, "Metrowerks CodeWarrior %x.%x.%x", v1, v2, v3);
  230 
  231 #elif defined(__NWCC__)
  232 
  233     sprintf(cast_char compiler_name, "NWCC");
  234 
  235 #elif defined(__OPEN64__)
  236 
  237     unsigned char *n = cast_uchar "Open64 " __OPEN64__;
  238     if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "Open64";
  239     strcpy(cast_char compiler_name, cast_const_char n);
  240 
  241 #elif defined(__PATHSCALE__)
  242 
  243     unsigned char *n = cast_uchar "PathScale " __PATHSCALE__;
  244     if (strlen(cast_const_char n) >= sizeof(cast_char compiler_name)) n = cast_uchar "PathScale";
  245     strcpy(cast_char compiler_name, cast_const_char n);
  246 
  247 #elif defined(__PCC__)
  248 
  249     int v1 = __PCC__+0;
  250 #ifdef __PCC_MINOR__
  251     int v2 = __PCC_MINOR__+0;
  252 #else
  253     int v2 = 0;
  254 #endif
  255 #ifdef __PCC_MINORMINOR__
  256     int v3 = __PCC_MINORMINOR__+0;
  257 #else
  258     int v3 = 0;
  259 #endif
  260     sprintf(cast_char compiler_name, "PCC %d.%d.%d", v1, v2, v3);
  261 
  262 #elif defined(__PGI) || defined(__PGIC__)
  263 
  264 #if !defined(__PGIC__) || !defined(__PGIC_MINOR__)
  265     sprintf(cast_char compiler_name, "The Portland Group C");
  266 #else
  267     int v1 = __PGIC__+0;
  268     int v2 = __PGIC_MINOR__+0;
  269 #ifdef __PGIC_PATCHLEVEL__
  270     int v3 = __PGIC_PATCHLEVEL__+0;
  271 #else
  272     int v3 = 0;
  273 #endif
  274     if (v3 > 0) sprintf(cast_char compiler_name, "The Portland Group C %d.%d.%d", v1, v2, v3);
  275     else sprintf(cast_char compiler_name, "The Portland Group C %d.%d", v1, v2);
  276 #endif
  277 
  278 #elif defined(__SASC__)
  279 
  280     int w = __SASC__+0;
  281     int v1 = w / 100;
  282     int v2 = w % 100;
  283     sprintf(cast_char compiler_name, "SAS C %d.%02d", v1, v2);
  284 
  285 #elif (defined(__sgi) && defined(_COMPILER_VERSION)) || defined(_SGI_COMPILER_VERSION)
  286 
  287 #ifdef _SGI_COMPILER_VERSION
  288     int w = _SGI_COMPILER_VERSION;
  289 #else
  290     int w = _COMPILER_VERSION;
  291 #endif
  292     int v1 = w / 100;
  293     int v2 = w / 10 % 10;
  294     int v3 = w % 10;
  295     sprintf(cast_char compiler_name, "MIPSpro %d.%d.%d", v1, v2, v3);
  296 
  297 #elif defined(__SUNPRO_C)
  298 
  299     int w = __SUNPRO_C+0;
  300     int div = w >= 0x1000 ? 0x1000 : 0x100;
  301     int v2_digits = w >= 0x1000 ? 2 : 1;
  302     int v1 = w / div;
  303     int v2 = w % div / 0x10;
  304     int v3 = w % 0x10;
  305     if (!v3) sprintf(cast_char compiler_name, "Sun C %X.%0*X", v1, v2_digits, v2);
  306     else sprintf(cast_char compiler_name, "Sun C %X.%0*X.%X", v1, v2_digits, v2, v3);
  307 
  308 #elif defined(__SYSC__) && defined(__SYSC_VER__)
  309 
  310     int w = __SYSC_VER__+0;
  311     int v1 = w / 10000;
  312     int v2 = w / 100 % 100;
  313     int v3 = w % 100;
  314     sprintf(cast_char compiler_name, "Dignus Systems C %d.%02d.%02d", v1, v2, v3);
  315 
  316 #elif defined(__TenDRA__)
  317 
  318     sprintf(cast_char compiler_name, "TenDRA C");
  319 
  320 #elif defined(__TINYC__)
  321 
  322     sprintf(cast_char compiler_name, "Tiny C");
  323 
  324 #elif defined(_UCC)
  325 
  326 #if !defined(_MAJOR_REV) || !defined(_MINOR_REV)
  327     sprintf(cast_char compiler_name, "Ultimate C");
  328 #else
  329     int v1 = _MAJOR_REV+0;
  330     int v2 = _MAJOR_REV+0;
  331     sprintf(cast_char compiler_name, "Ultimate C %d.%d", v1, v2);
  332 #endif
  333 
  334 #elif defined(__USLC__)
  335 
  336     sprintf(cast_char compiler_name, "USL C");
  337 
  338 #elif defined(__VAXC)
  339 
  340     sprintf(cast_char compiler_name, "VAX C");
  341 
  342 #elif defined(__VOSC__)
  343 
  344     sprintf(cast_char compiler_name, "Stratus VOS C");
  345 
  346 #elif defined(__WATCOMC__)
  347 
  348     int w = __WATCOMC__+0;
  349     int v1 = w / 100;
  350     int v2 = w % 100;
  351     unsigned char *op = cast_uchar "";
  352     if (v1 >= 12) {
  353         v1 -= 11;
  354         op = cast_uchar "Open";
  355     }
  356     if (!(v2 % 10)) sprintf(cast_char compiler_name, "%sWatcom C %d.%d", op, v1, v2 / 10);
  357     else sprintf(cast_char compiler_name, "%sWatcom C %d.%02d", op, v1, v2);
  358 
  359 #elif defined(__GNUC__)
  360 
  361     int v1 = __GNUC__+0;
  362 #ifdef __GNUC_MINOR__
  363     int v2 = __GNUC_MINOR__+0;
  364 #else
  365     int v2 = -1;
  366 #endif
  367 #ifdef __GNUC_PATCHLEVEL__
  368     int v3 = __GNUC_PATCHLEVEL__+0;
  369 #else
  370     int v3 = 0;
  371 #endif
  372 #if defined(__llvm__)
  373     unsigned char *prefix = cast_uchar "LLVM/";
  374 #else
  375     unsigned char *prefix = cast_uchar "";
  376 #endif
  377     if (v1 == 2 && (v2 >= 90 && v2 <= 91)) sprintf(cast_char compiler_name, "%sEGCS 1.%d", prefix, v2 - 90);
  378     else if (v3 > 0 && v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d.%d", prefix, v1, v2, v3);
  379     else if (v2 >= 0) sprintf(cast_char compiler_name, "%sGNU C %d.%d", prefix, v1, v2);
  380     else sprintf(cast_char compiler_name, "%sGNU C %d", prefix, v1);
  381 
  382 #else
  383 
  384     strcpy(cast_char compiler_name, "unknown compiler");
  385 
  386 #endif
  387 }
  388 
  389 extern struct option links_options[];
  390 extern struct option html_options[];
  391 
  392 struct option *all_options[] = { links_options, html_options, NULL, };
  393 
  394 unsigned char *p_arse_options(int argc, unsigned char *argv[], struct option **opt)
  395 {
  396     unsigned char *e, *u = NULL;
  397     int i;
  398     for (i = 0; i < argc; i++) {
  399         if (strlen(argv[i]) >= MAXINT) {
  400             fprintf(stderr, "Too long parameter\n");
  401             return NULL;
  402         }
  403     }
  404     while (argc) {
  405         argv++, argc--;
  406         if (argv[-1][0] == '-') {
  407             struct option *options;
  408             struct option **op;
  409             for (op = opt; (options = *op); op++) for (i = 0; options[i].p; i++)
  410                 if (options[i].rd_cmd && options[i].cmd_name &&
  411                     !strcasecmp(options[i].cmd_name, &argv[-1][1])) {
  412                     if ((e = options[i].rd_cmd(&options[i], &argv, &argc))) {
  413                         if (e[0]) fprintf(stderr, "Error parsing option %s: %s\n", argv[-1], e);
  414                         return NULL;
  415                     }
  416                     goto found;
  417                 }
  418             uu:
  419             fprintf(stderr, "Unknown option %s\n", argv[-1]);
  420             return NULL;
  421         } else if (!u) u = argv[-1];
  422         else goto uu;
  423         found:;
  424     }
  425     if (u) return u;
  426     return "";
  427 }
  428 
  429 unsigned char *parse_options(int argc, unsigned char *argv[])
  430 {
  431     return p_arse_options(argc, argv, all_options);
  432 }
  433 
  434 unsigned char *get_token(unsigned char **line)
  435 {
  436     unsigned char *s = NULL;
  437     int l = 0;
  438     int escape = 0;
  439     int quote = 0;
  440     
  441     while (**line == ' ' || **line == 9) (*line)++;
  442     if (**line) {
  443         for (s = init_str(); **line; (*line)++) {
  444             if (escape) 
  445                 escape = 0;
  446             else if (**line == '\\') {
  447                 escape = 1; 
  448                 continue;
  449             }   
  450             else if (**line == '"') {
  451                 quote = !quote;
  452                     continue;
  453             }
  454             else if ((**line == ' ' || **line == 9) && !quote)
  455                 break;
  456             add_chr_to_str(&s, &l, **line);
  457         }
  458     }
  459     return s;
  460 }
  461 
  462 void parse_config_file(unsigned char *name, unsigned char *file, struct option **opt)
  463 {
  464     struct option *options;
  465     struct option **op;
  466     int err = 0;
  467     int line = 0;
  468     unsigned char *e;
  469     int i;
  470     unsigned char *n, *p;
  471     unsigned char *tok;
  472     int nl, pl;
  473     while (file[0]) {
  474         line++;
  475         while (file[0] && (file[0] == ' ' || file[0] == 9)) file++;
  476         n = file;
  477         while (file[0] && file[0] > ' ') file++;
  478         if (file == n) {
  479             if (file[0]) file++;
  480             continue;
  481         }
  482         nl = file - n;
  483         while (file[0] == 9 || file[0] == ' ') file++;
  484         p = file;
  485         while (file[0] && file[0] != 10 && file[0] != 13) file++;
  486         pl = file - p;
  487         if (file[0]) {
  488             if ((file[1] == 10 || file[1] == 13) && file[0] != file[1]) file++;
  489             file++;
  490         }
  491         tok = NULL;
  492         if (n[0] == '#') goto f;
  493         if (!(tok = get_token(&n))) goto f;
  494         nl = strlen(tok);
  495         for (op = opt; (options = *op); op++) 
  496                 for (i = 0; options[i].p; i++) if (options[i].cfg_name && (size_t)nl == strlen(options[i].cfg_name) && !casecmp(tok, options[i].cfg_name, nl)) {
  497                 unsigned char *o = memacpy(p, pl);
  498                 if ((e = options[i].rd_cfg(&options[i], o))) {
  499                     if (e[0]) fprintf(stderr, "Error parsing config file %s, line %d: %s\n", name, line, e), err = 1;
  500                 }
  501                 mem_free(o);
  502                 goto f;
  503             }
  504         fprintf(stderr, "Unknown option in config file %s, line %d\n", name, line);
  505         err = 1;
  506         f:
  507         if (tok) mem_free(tok);
  508     }
  509     if (err) fprintf(stderr, "\007"), sleep(3);
  510 }
  511 
  512 unsigned char *create_config_string(struct option *options)
  513 {
  514     unsigned char *s = init_str();
  515     int l = 0;
  516     int i;
  517     add_to_str(&s, &l, "# This file is automatically generated by Links -- please do not edit.");
  518     for (i = 0; options[i].p; i++) if (options[i].wr_cfg)
  519         options[i].wr_cfg(&options[i], &s, &l);
  520     add_to_str(&s, &l, NEWLINE);
  521     return s;
  522 }
  523 
  524 #define FILE_BUF    1024
  525 
  526 unsigned char cfg_buffer[FILE_BUF];
  527 
  528 unsigned char *read_config_file(unsigned char *name)
  529 {
  530     int h, r;
  531     int l = 0;
  532     unsigned char *s;
  533     int rs;
  534     EINTRLOOP(h, open(name, O_RDONLY | O_NOCTTY));
  535     if (h == -1) return NULL;
  536     set_bin(h);
  537     s = init_str();
  538     while ((r = hard_read(h, cfg_buffer, FILE_BUF)) > 0) {
  539         int i;
  540         for (i = 0; i < r; i++) if (!cfg_buffer[i]) cfg_buffer[i] = ' ';
  541         add_bytes_to_str(&s, &l, cfg_buffer, r);
  542     }
  543     if (r == -1) mem_free(s), s = NULL;
  544     EINTRLOOP(rs, close(h));
  545     return s;
  546 }
  547 
  548 int write_to_config_file(unsigned char *name, unsigned char *c)
  549 {
  550     int rr;
  551     int h, w;
  552     int count = 0;
  553     int tmp_namel;
  554     unsigned char *tmp_name;
  555     int rs, err;
  556 try_new_count:
  557     tmp_namel = 0;
  558     tmp_name = init_str();
  559     add_to_str(&tmp_name, &tmp_namel, name);
  560     for (w = tmp_namel - 1; w >= 0; w--) {
  561         if (dir_sep(tmp_name[w]))
  562             break;
  563         if (tmp_name[w] == '.') {
  564             if (w <= tmp_namel - 2) {
  565                 tmp_name[w + 2] = 0;
  566                 tmp_namel = w + 2;
  567             }
  568             break;
  569         }
  570     }
  571     add_num_to_str(&tmp_name, &tmp_namel, count);
  572     EINTRLOOP(h, open(tmp_name, O_WRONLY | O_NOCTTY | O_CREAT | O_TRUNC | O_EXCL, 0600));
  573     if (h == -1) {
  574         if (errno == EEXIST && count < MAXINT) {
  575             count++;
  576             mem_free(tmp_name);
  577             goto try_new_count;
  578         }
  579         mem_free(tmp_name);
  580         return get_error_from_errno(errno);
  581     }
  582     set_bin(h);
  583     rr = strlen(c);
  584     if (hard_write(h, c, rr) != rr) {
  585         err = errno;
  586         EINTRLOOP(rs, close(h));
  587         goto unlink_err;
  588     }
  589     EINTRLOOP(rs, close(h));
  590     if (rs) {
  591         err = errno;
  592         goto unlink_err;
  593     }
  594 #if defined(OPENVMS)
  595     /* delete all versions of the file */
  596     count = 0;
  597     do {
  598         EINTRLOOP(rs, unlink(name));
  599     } while (!rs && ++count < 65536);
  600 #elif !defined(RENAME_OVER_EXISTING_FILES)
  601     EINTRLOOP(rs, unlink(name));
  602 #endif
  603     EINTRLOOP(rs, rename(tmp_name, name));
  604     if (rs) {
  605         err = errno;
  606         goto unlink_err;
  607     }
  608     mem_free(tmp_name);
  609     return 0;
  610 
  611     unlink_err:
  612     EINTRLOOP(rs, unlink(cast_const_char tmp_name));
  613     mem_free(tmp_name);
  614     return get_error_from_errno(err);
  615 }
  616 
  617 #ifdef OPENVMS
  618 void translate_vms_to_unix(unsigned char **str)
  619 {
  620     unsigned char *n;
  621     if (!*str || strchr(cast_const_char *str, '/')) return;
  622     n = cast_uchar decc$translate_vms(cast_const_char *str);
  623     if (!n || (int)n == -1) return;
  624     mem_free(*str);
  625     *str = stracpy(n);
  626 }
  627 #endif
  628 
  629 unsigned char *get_home(int *n)
  630 {
  631     struct stat st;
  632     int rs;
  633     unsigned char *home = NULL;
  634     unsigned char *home_links;
  635     unsigned char *config_dir = stracpy(getenv("CONFIG_DIR"));
  636 
  637     if (n) *n = 1;
  638 #ifdef WIN32
  639     if (!home) {
  640         home = stracpy(getenv("APPDATA"));
  641 #ifdef HAVE_CYGWIN_CONV_PATH
  642         /*
  643          * Newer Cygwin complains about windows-style path, so
  644          * we have to convert it.
  645          */
  646         if (home) {
  647             unsigned char *new_path;
  648             ssize_t sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, NULL, 0);
  649             if (sz < 0)
  650                 goto skip_path_conv;
  651             new_path = mem_alloc(sz);
  652             sz = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, home, new_path, sz);
  653             if (sz < 0) {
  654                 mem_free(new_path);
  655                 goto skip_path_conv;
  656             }
  657             mem_free(home);
  658             home = new_path;
  659 skip_path_conv:;
  660         }
  661 #endif
  662         if (home) {
  663             EINTRLOOP(rs, stat(home, &st));
  664             if (rs || !S_ISDIR(st.st_mode)) {
  665                 mem_free(home);
  666                 home = NULL;
  667             }
  668         }
  669     }
  670 #endif
  671     if (!home) home = stracpy(getenv("HOME"));
  672 #ifdef WIN32
  673 /* When we run in Cygwin without Cygwin environment, it reports home "/".
  674    Unfortunatelly, it can't write anything to that directory */
  675     if (home && !strcmp(home, "/")) {
  676         mem_free(home);
  677         home = NULL;
  678     }
  679 #endif
  680 #ifdef OPENVMS
  681     if (!home) home = stracpy(cast_uchar "/SYS$LOGIN");
  682     translate_vms_to_unix(&home);
  683     translate_vms_to_unix(&config_dir);
  684 #endif
  685     if (!home) {
  686         int i;
  687         home = stracpy(path_to_exe);
  688         if (!home) {
  689             if (config_dir) mem_free(config_dir);
  690             return NULL;
  691         }
  692         for (i = strlen(home) - 1; i >= 0; i--) if (dir_sep(home[i])) {
  693             home[i + 1] = 0;
  694             goto br;
  695         }
  696         home[0] = 0;
  697         br:;
  698     }
  699     while (home[0] && home[1] && dir_sep(home[strlen(home) - 1])) home[strlen(home) - 1] = 0;
  700     if (home[0]) add_to_strn(&home, "/");
  701     home_links = stracpy(home);
  702     if (config_dir) {
  703         add_to_strn(&home_links, config_dir);
  704         while (home_links[0] && dir_sep(home_links[strlen(home_links) - 1])) home_links[strlen(home_links) - 1] = 0;
  705         EINTRLOOP(rs, stat(home_links, &st));
  706         if (!rs && S_ISDIR(st.st_mode)) {
  707             add_to_strn(&home_links, "/links");
  708             } else {
  709             fprintf(stderr, "CONFIG_DIR set to %s. But directory %s doesn't exist.\n\007", config_dir, home_links);
  710             sleep(3);
  711             mem_free(home_links);
  712             home_links = stracpy(home);
  713             add_to_strn(&home_links, ".links");     
  714         }
  715     } else add_to_strn(&home_links, ".links");
  716     EINTRLOOP(rs, stat(home_links, &st));
  717     if (rs) {
  718 #ifdef HAVE_MKDIR
  719         EINTRLOOP(rs, mkdir(home_links, 0700));
  720         if (!rs) goto home_creat;
  721 #ifdef OPENVMS
  722         if (errno == EEXIST) goto home_ok;
  723 #endif
  724 #endif
  725         if (config_dir) goto failed;
  726         goto first_failed;
  727     }
  728     if (S_ISDIR(st.st_mode)) goto home_ok;
  729     /* This is a Cygwin hack! Cygwin reports stat for "links" if no
  730        "links" exists and only "links.exe" does. So try to create directory
  731        anyway. */
  732 #ifdef HAVE_MKDIR
  733     EINTRLOOP(rs, mkdir(home_links, 0700));
  734     if (!rs) goto home_creat;
  735 #endif
  736     first_failed:
  737     mem_free(home_links);
  738     home_links = stracpy(home);
  739 #ifdef DOS
  740     add_to_strn(&home_links, cast_uchar "links.cfg");
  741 #else
  742     add_to_strn(&home_links, cast_uchar "links");
  743 #endif
  744     EINTRLOOP(rs, stat(home_links, &st));
  745     if (rs) {
  746 #ifdef HAVE_MKDIR
  747         EINTRLOOP(rs, mkdir(home_links, 0700));
  748         if (!rs) goto home_creat;
  749 #ifdef OPENVMS
  750         if (errno == EEXIST) goto home_ok;
  751 #endif
  752 #else
  753         mem_free(home_links);
  754         home_links = stracpy(home);
  755         goto home_ok;
  756 #endif
  757         goto failed;
  758     }
  759     if (S_ISDIR(st.st_mode)) goto home_ok;
  760 #ifdef HAVE_MKDIR
  761     EINTRLOOP(rs, mkdir(home_links, 0700));
  762     if (!rs) goto home_creat;
  763 #endif
  764     failed:
  765     mem_free(home_links);
  766     mem_free(home);
  767     if (config_dir) mem_free(config_dir);
  768     return NULL;
  769 
  770     home_ok:
  771     if (n) *n = 0;
  772     home_creat:
  773 #ifdef HAVE_CHMOD
  774     EINTRLOOP(rs, chmod(home_links, 0700));
  775 #endif
  776     add_to_strn(&home_links, "/");
  777     mem_free(home);
  778     if (config_dir) mem_free(config_dir);
  779     return home_links;
  780 }
  781 
  782 void init_home()
  783 {
  784     get_system_name();
  785     get_compiler_name();
  786     links_home = get_home(&first_use);
  787     if (!links_home) {
  788         fprintf(stderr, "Unable to find or create links config directory. Please check, that you have $HOME variable set correctly and that you have write permission to your home directory.\n\007");
  789         sleep(3);
  790         return;
  791     }
  792 }
  793 
  794 void load_config_file(unsigned char *prefix, unsigned char *name)
  795 {
  796     unsigned char *c, *config_file;
  797     config_file = stracpy(prefix);
  798     if (!config_file) return;
  799     add_to_strn(&config_file, name);
  800     if ((c = read_config_file(config_file))) goto ok;
  801     mem_free(config_file);
  802     config_file = stracpy(prefix);
  803     if (!config_file) return;
  804     add_to_strn(&config_file, ".");
  805     add_to_strn(&config_file, name);
  806     if ((c = read_config_file(config_file))) goto ok;
  807     mem_free(config_file);
  808     return;
  809     ok:
  810     parse_config_file(config_file, c, all_options);
  811     mem_free(c);
  812     mem_free(config_file);
  813 }
  814 
  815 void load_config()
  816 {
  817 #ifdef SHARED_CONFIG_DIR
  818     load_config_file(SHARED_CONFIG_DIR, "links.cfg");
  819 #endif
  820     load_config_file(links_home, "links.cfg");
  821     load_config_file(links_home, "html.cfg");
  822     load_config_file(links_home, "user.cfg");
  823 }
  824 
  825 int write_config_data(unsigned char *prefix, unsigned char *name, struct option *o, struct terminal *term)
  826 {
  827     int err;
  828     unsigned char *c, *config_file;
  829     if (!(c = create_config_string(o))) return -1;
  830     config_file = stracpy(prefix);
  831     if (!config_file) {
  832         mem_free(c);
  833         return -1;
  834     }
  835     add_to_strn(&config_file, name);
  836     if ((err = write_to_config_file(config_file, c))) {
  837         if (term) msg_box(term, NULL, TEXT_(T_CONFIG_ERROR), AL_CENTER | AL_EXTD_TEXT, TEXT_(T_UNABLE_TO_WRITE_TO_CONFIG_FILE), ": ", get_err_msg(err), NULL, NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
  838         mem_free(c);
  839         mem_free(config_file);
  840         return -1;
  841     }
  842     mem_free(c);
  843     mem_free(config_file);
  844     return 0;
  845 }
  846 
  847 void write_config(struct terminal *term)
  848 {
  849     write_config_data(links_home, "links.cfg", links_options, term);
  850 }
  851 
  852 void write_html_config(struct terminal *term)
  853 {
  854     write_config_data(links_home, "html.cfg", html_options, term);
  855 }
  856 
  857 void add_nm(struct option *o, unsigned char **s, int *l)
  858 {
  859     if (*l) add_to_str(s, l, NEWLINE);
  860     add_to_str(s, l, o->cfg_name);
  861     add_to_str(s, l, " ");
  862 }
  863 
  864 void add_quoted_to_str(unsigned char **s, int *l, unsigned char *q)
  865 {
  866     add_chr_to_str(s, l, '"');
  867     while (*q) {
  868         if (*q == '"' || *q == '\\') add_chr_to_str(s, l, '\\');
  869         add_chr_to_str(s, l, *q);
  870         q++;
  871     }
  872     add_chr_to_str(s, l, '"');
  873 }
  874 
  875 unsigned char *num_rd(struct option *o, unsigned char *c)
  876 {
  877     unsigned char *tok = get_token(&c);
  878     unsigned char *end;
  879     long l;
  880     if (!tok) return "Missing argument";
  881     l = strtolx(tok, &end);
  882     if (*end) {
  883         mem_free(tok);
  884         return "Number expected";
  885     }
  886     if (l < o->min || l > o->max) {
  887         mem_free(tok);
  888         return "Out of range";
  889     }
  890     *(int *)o->ptr = l;
  891     mem_free(tok);
  892     return NULL;
  893 }
  894 
  895 void num_wr(struct option *o, unsigned char **s, int *l)
  896 {
  897     add_nm(o, s, l);
  898     add_knum_to_str(s, l, *(int *)o->ptr);
  899 }
  900 
  901 unsigned char *str_rd(struct option *o, unsigned char *c)
  902 {
  903     unsigned char *tok = get_token(&c);
  904     unsigned char *e = NULL;
  905     if (!tok) tok = stracpy(cast_uchar "");
  906     if (strlen(tok) + 1 > (size_t)o->max) e = "String too long";
  907     else strcpy(o->ptr, tok);
  908     mem_free(tok);
  909     return e;
  910 }
  911 
  912 void str_wr(struct option *o, unsigned char **s, int *l)
  913 {
  914     add_nm(o, s, l);
  915     if (strlen(o->ptr) + 1 > (size_t)o->max) {
  916         unsigned char *s1 = init_str();
  917         int l1 = 0;
  918         add_bytes_to_str(&s1, &l1, o->ptr, o->max - 1);
  919         add_quoted_to_str(s, l, s1);
  920         mem_free(s1);
  921     }
  922     else add_quoted_to_str(s, l, o->ptr);
  923 }
  924 
  925 unsigned char *cp_rd(struct option *o, unsigned char *c)
  926 {
  927     unsigned char *tok = get_token(&c);
  928     unsigned char *e = NULL;
  929     int i;
  930     if (!tok) return "Missing argument";
  931     if ((i = get_cp_index(tok)) == -1) e = "Unknown codepage";
  932     else if (o->min == 1 && is_cp_special(i)) e = "UTF-8 can't be here";
  933     else *(int *)o->ptr = i;
  934     mem_free(tok);
  935     return e;
  936 }
  937 
  938 void cp_wr(struct option *o, unsigned char **s, int *l)
  939 {
  940     unsigned char *n = get_cp_mime_name(*(int *)o->ptr);
  941     add_nm(o, s, l);
  942     add_to_str(s, l, n);
  943 }
  944 
  945 unsigned char *lang_rd(struct option *o, unsigned char *c)
  946 {
  947     int i;
  948     unsigned char *tok = get_token(&c);
  949     if (!tok) return "Missing argument";
  950     for (i = 0; i < n_languages(); i++)
  951         if (!(strcasecmp(language_name(i), tok))) {
  952             set_language(i);
  953             mem_free(tok);
  954             return NULL;
  955         }
  956     mem_free(tok);
  957     return "Unknown language";
  958 }
  959 
  960 void lang_wr(struct option *o, unsigned char **s, int *l)
  961 {
  962     add_nm(o, s, l);
  963     add_quoted_to_str(s, l, language_name(current_language));
  964 }
  965 
  966 int getnum(unsigned char *s, int *n, int r1, int r2)
  967 {
  968     unsigned char *e;
  969     long l = strtol(s, (char **)(void *)&e, 10);
  970     if (*e || !*s) return -1;
  971     if (l < r1 || l >= r2) return -1;
  972     *n = (int)l;
  973     return 0;
  974 }
  975 
  976 unsigned char *type_rd(struct option *o, unsigned char *c)
  977 {
  978     unsigned char *err = "Error reading association specification";
  979     struct assoc neww;
  980     unsigned char *w;
  981     int n;
  982     memset(&neww, 0, sizeof(struct assoc));
  983     if (!(neww.label = get_token(&c))) goto err;
  984     if (!(neww.ct = get_token(&c))) goto err;
  985     if (!(neww.prog = get_token(&c))) goto err;
  986     if (!(w = get_token(&c))) goto err;
  987     if (getnum(w, &n, 0, 32)) goto err_f;
  988     mem_free(w);
  989     neww.cons = !!(n & 1);
  990     neww.xwin = !!(n & 2);
  991     neww.ask = !!(n & 4);
  992     if ((n & 8) || (n & 16)) neww.block = !!(n & 16);
  993     else neww.block = !neww.xwin || neww.cons;
  994     if (!(w = get_token(&c))) goto err;
  995     if (getnum(w, &neww.system, 0, 256)) goto err_f;
  996     mem_free(w);
  997     update_assoc(&neww);
  998     err = NULL;
  999     err:
 1000     if (neww.label) mem_free(neww.label);
 1001     if (neww.ct) mem_free(neww.ct);
 1002     if (neww.prog) mem_free(neww.prog);
 1003     return err;
 1004     err_f:
 1005     mem_free(w);
 1006     goto err;
 1007 }
 1008 
 1009 void type_wr(struct option *o, unsigned char **s, int *l)
 1010 {
 1011     struct assoc *a;
 1012     foreachback(a, assoc) {
 1013         add_nm(o, s, l);
 1014         add_quoted_to_str(s, l, a->label);
 1015         add_to_str(s, l, " ");
 1016         add_quoted_to_str(s, l, a->ct);
 1017         add_to_str(s, l, " ");
 1018         add_quoted_to_str(s, l, a->prog);
 1019         add_to_str(s, l, " ");
 1020         add_num_to_str(s, l, (!!a->cons) + (!!a->xwin) * 2 + (!!a->ask) * 4 + (!a->block) * 8 + (!!a->block) * 16);
 1021         add_to_str(s, l, " ");
 1022         add_num_to_str(s, l, a->system);
 1023     }
 1024 }
 1025 
 1026 unsigned char *ext_rd(struct option *o, unsigned char *c)
 1027 {
 1028     unsigned char *err = "Error reading extension specification";
 1029     struct extension neww;
 1030     memset(&neww, 0, sizeof(struct extension));
 1031     if (!(neww.ext = get_token(&c))) goto err;
 1032     if (!(neww.ct = get_token(&c))) goto err;
 1033     update_ext(&neww);
 1034     err = NULL;
 1035     err:
 1036     if (neww.ext) mem_free(neww.ext);
 1037     if (neww.ct) mem_free(neww.ct);
 1038     return err;
 1039 }
 1040 
 1041 void ext_wr(struct option *o, unsigned char **s, int *l)
 1042 {
 1043     struct extension *a;
 1044     foreachback(a, extensions) {
 1045         add_nm(o, s, l);
 1046         add_quoted_to_str(s, l, a->ext);
 1047         add_to_str(s, l, " ");
 1048         add_quoted_to_str(s, l, a->ct);
 1049     }
 1050 }
 1051 
 1052 unsigned char *prog_rd(struct option *o, unsigned char *c)
 1053 {
 1054     unsigned char *err = "Error reading program specification";
 1055     unsigned char *prog, *w;
 1056     int n;
 1057     if (!(prog = get_token(&c))) goto err_1;
 1058     if (!(w = get_token(&c))) goto err_2;
 1059     if (getnum(w, &n, 0, 256)) goto err_3;
 1060     update_prog(o->ptr, prog, n);
 1061     err = NULL;
 1062     err_3:
 1063     mem_free(w);
 1064     err_2:
 1065     mem_free(prog);
 1066     err_1:
 1067     return err;
 1068 }
 1069 
 1070 void prog_wr(struct option *o, unsigned char **s, int *l)
 1071 {
 1072     struct protocol_program *a;
 1073     foreachback(a, *(struct list_head *)o->ptr) {
 1074         if (!*a->prog) continue;
 1075         add_nm(o, s, l);
 1076         add_quoted_to_str(s, l, a->prog);
 1077         add_to_str(s, l, " ");
 1078         add_num_to_str(s, l, a->system);
 1079     }
 1080 }
 1081 
 1082 unsigned char *term_rd(struct option *o, unsigned char *c)
 1083 {
 1084     struct term_spec *ts;
 1085     unsigned char *w;
 1086     int i;
 1087     if (!(w = get_token(&c))) goto err;
 1088     if (!(ts = new_term_spec(w))) {
 1089         mem_free(w);
 1090         goto end;
 1091     }
 1092     mem_free(w);
 1093     if (!(w = get_token(&c))) goto err;
 1094     if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
 1095     ts->mode = w[0] - '0';
 1096     mem_free(w);
 1097     if (!(w = get_token(&c))) goto err;
 1098     if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
 1099     ts->m11_hack = w[0] - '0';
 1100     mem_free(w);
 1101     if (!(w = get_token(&c))) goto err;
 1102     if (strlen(w) != 1 || w[0] < '0' || w[0] > '7') goto err_f;
 1103     ts->col = (w[0] - '0') & 1;
 1104     ts->restrict_852 = !!((w[0] - '0') & 2);
 1105     ts->block_cursor = !!((w[0] - '0') & 4);
 1106     mem_free(w);
 1107     if (!(w = get_token(&c))) goto err;
 1108     if ((i = get_cp_index(w)) == -1 || is_cp_special(i)) goto err_f;
 1109     ts->charset = i;
 1110     mem_free(w);
 1111     end:
 1112     return NULL;
 1113     err_f:
 1114     mem_free(w);
 1115     err:
 1116     return "Error reading terminal specification";
 1117 }
 1118 
 1119 unsigned char *term2_rd(struct option *o, unsigned char *c)
 1120 {
 1121     struct term_spec *ts;
 1122     unsigned char *w;
 1123     int i;
 1124     if (!(w = get_token(&c))) goto err;
 1125     if (!(ts = new_term_spec(w))) {
 1126         mem_free(w);
 1127         goto end;
 1128     }
 1129     mem_free(w);
 1130     if (!(w = get_token(&c))) goto err;
 1131     if (strlen(w) != 1 || w[0] < '0' || w[0] > '4') goto err_f;
 1132     ts->mode = w[0] - '0';
 1133     mem_free(w);
 1134     if (!(w = get_token(&c))) goto err;
 1135     if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
 1136     ts->m11_hack = w[0] - '0';
 1137     mem_free(w);
 1138     if (!(w = get_token(&c))) goto err;
 1139     if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
 1140     ts->restrict_852 = w[0] - '0';
 1141     mem_free(w);
 1142     if (!(w = get_token(&c))) goto err;
 1143     if (strlen(w) != 1 || w[0] < '0' || w[0] > '1') goto err_f;
 1144     ts->col = w[0] - '0';
 1145     mem_free(w);
 1146     if (!(w = get_token(&c))) goto err;
 1147     if ((i = get_cp_index(w)) == -1 || is_cp_special(i)) goto err_f;
 1148     ts->charset = i;
 1149     mem_free(w);
 1150     end:
 1151     return NULL;
 1152     err_f:
 1153     mem_free(w);
 1154     err:
 1155     return "Error reading terminal specification";
 1156 }
 1157 
 1158 void term_wr(struct option *o, unsigned char **s, int *l)
 1159 {
 1160     struct term_spec *ts;
 1161     foreachback(ts, term_specs) {
 1162         add_nm(o, s, l);
 1163         add_quoted_to_str(s, l, ts->term);
 1164         add_to_str(s, l, " ");
 1165         add_num_to_str(s, l, ts->mode);
 1166         add_to_str(s, l, " ");
 1167         add_num_to_str(s, l, ts->m11_hack);
 1168         add_to_str(s, l, " ");
 1169         add_num_to_str(s, l, !!ts->col + !!ts->restrict_852 * 2 + !!ts->block_cursor * 4);
 1170         add_to_str(s, l, " ");
 1171         add_to_str(s, l, get_cp_mime_name(ts->charset));
 1172     }
 1173 }
 1174 
 1175 unsigned char *gen_cmd(struct option *o, unsigned char ***argv, int *argc)
 1176 {
 1177     unsigned char *e;
 1178     int l;
 1179     unsigned char *r;
 1180     if (!*argc) return "Parameter expected";
 1181     e = init_str();
 1182     l = 0;
 1183     add_quoted_to_str(&e, &l, **argv);
 1184     r = o->rd_cfg(o, e);
 1185     mem_free(e);
 1186     if (r) return r;
 1187     (*argv)++; (*argc)--;
 1188     return NULL;
 1189 }
 1190 
 1191 unsigned char *lookup_cmd(struct option *o, unsigned char ***argv, int *argc)
 1192 {
 1193     ip addr;
 1194     unsigned char *p = (unsigned char *)&addr;
 1195     if (!*argc) return "Parameter expected";
 1196     if (*argc >= 2) return "Too many parameters";
 1197     (*argv)++; (*argc)--;
 1198     if (do_real_lookup(*(*argv - 1), &addr)) {
 1199 #if defined(HAVE_GETHOSTBYNAME) && defined(HAVE_HERROR)
 1200         herror("error");
 1201 #else
 1202         fprintf(stderr, "error: host not found\n");
 1203 #endif
 1204         exit(RET_ERROR);
 1205         return "";
 1206     }
 1207     printf("%d.%d.%d.%d\n", (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
 1208     fflush(stdout);
 1209     exit(RET_OK);
 1210     return "";
 1211 }
 1212 
 1213 unsigned char *version_cmd(struct option *o, unsigned char ***argv, int *argc)
 1214 {
 1215     printf("Links " VERSION_STRING "\n");
 1216     fflush(stdout);
 1217     exit(RET_OK);
 1218     return "";
 1219 }
 1220 
 1221 unsigned char *no_connect_cmd(struct option *o, unsigned char ***argv, int *argc)
 1222 {
 1223     no_connect = 1;
 1224     return NULL;
 1225 }
 1226 
 1227 unsigned char *anonymous_cmd(struct option *o, unsigned char ***argv, int *argc)
 1228 {
 1229     anonymous = 1;
 1230     return NULL;
 1231 }
 1232 
 1233 unsigned char *force_html_cmd(struct option *o, unsigned char ***argv, int *argc)
 1234 {
 1235     force_html = 1;
 1236     return NULL;
 1237 }
 1238 
 1239 unsigned char *dump_cmd(struct option *o, unsigned char ***argv, int *argc)
 1240 {
 1241     if (dmp != o->min && dmp) return "Can't use both -dump and -source";
 1242     dmp = o->min;
 1243     no_connect = 1;
 1244     return NULL;
 1245 }
 1246 
 1247 unsigned char *printhelp_cmd(struct option *o, unsigned char ***argv, int *argc)
 1248 {
 1249 /* Changed and splited - translation is much easier.
 1250  * Print to stdout instead stderr (,,links -help | more''
 1251  * is much better than ,,links -help 2>&1 | more'').
 1252  */
 1253 fprintf(stdout, "%s%s%s%s%s%s\n", 
 1254 
 1255 ("links [options] URL\n\
 1256 Options are:\n\
 1257 \n\
 1258  -async-dns <0>/<1>\n\
 1259   Asynchronous DNS resolver on(1)/off(0).\n\
 1260 \n\
 1261  -download-utime <0>/<1>\n\
 1262   Set time of downloaded files to time from server.\n\
 1263 \n\
 1264  -max-connections <max>\n\
 1265   Maximum number of concurrent connections.\n\
 1266   (default: 10)\n\
 1267 \n"),
 1268 (" -max-connections-to-host <max>\n\
 1269   Maximum number of concurrent connection to a given host.\n\
 1270   (default: 2)\n\
 1271 \n\
 1272  -retries <retry>\n\
 1273   Number of retries.\n\
 1274   (default: 3)\n\
 1275 \n\
 1276  -receive-timeout <sec>\n\
 1277   Timeout on receive.\n\
 1278   (default: 120)\n\
 1279 \n"),
 1280 (" -unrestartable-receive-timeout <sec>\n\
 1281   Timeout on non restartable connections.\n\
 1282   (default: 600)\n\
 1283 \n\
 1284  -format-cache-size <num>\n\
 1285   Number of formatted document pages cached.\n\
 1286   (default: 5)\n\
 1287 \n\
 1288  -memory-cache-size <Kbytes>\n\
 1289   Cache memory in Kilobytes.\n\
 1290   (default: 1024)\n\
 1291 \n"),
 1292 (" -http-proxy <host:port>\n\
 1293   Host and port number of the HTTP proxy, or blank.\n\
 1294   (default: blank)\n\
 1295 \n\
 1296  -ftp-proxy <host:port>\n\
 1297   Host and port number of the FTP proxy, or blank.\n\
 1298   (default: blank)\n\
 1299 \n\
 1300  -download-dir <path>\n\
 1301   Default download directory.\n\
 1302   (default: actual dir)\n\
 1303 \n\
 1304  -http-bugs.http10 <0>/<1>\n\
 1305   \"1\" forces using only HTTP/1.0 protocol.\n\
 1306 \n\
 1307  -http-bugs.allow-blacklist <0>/<1>\n\
 1308   \"1\" defaults to using list of servers that have broken HTTP/1.1 support.\n\
 1309   When links finds such server, it will retry the request with HTTP/1.0.\n\
 1310 \n\
 1311  -http-bugs.bug-302-redirect <0>/<1>\n\
 1312   Process 302 redirect in a way that is incompatible with RFC1945 and RFC2068,\n\
 1313   but the same as Netscape and MSIE. Many pages depend on it.\n\
 1314 \n\
 1315  -http-bugs.bug-post-no-keepalive <0>/<1>\n\
 1316   No keepalive connection after post requests. For some buggy servers.\n\
 1317 \n\
 1318  -http-bugs.bug-no-accept-charset <0>/<1>\n\
 1319   Do not send Accept-Charset field of HTTP header.\n\
 1320 \n\
 1321  -ftp.anonymous-password <string>\n\
 1322   Use ftp PASV command to bypass firewalls.\n\
 1323 \n\
 1324  -ftp.fast <0>/<1>\n\
 1325   Send more ftp commands simultaneously. Faster response when\n\
 1326   browsing ftp directories, but it is incompatible with RFC\n\
 1327   and some servers don't like it.\n\
 1328 \n\
 1329  -ftp.set-iptos <0>/<1>\n\
 1330   Set IP Type-of-service to high throughput on ftp connections.\n\
 1331 \n"),
 1332 (" -html-assume-codepage <codepage>\n\
 1333   Use the given codepage when the webpage did not specify\n\
 1334   its codepage. (default: ISO 8859-1)\n\
 1335 \n\
 1336  -html-tables <0>/<1>\n\
 1337   Render tables.\n\
 1338 \n\
 1339  -html-frames <0>/<1>\n\
 1340   Render frames.\n\
 1341 \n\
 1342  -html-images <0>/<1>\n\
 1343   Display links to images.\n\
 1344 \n\
 1345  -html-numbered-links <0>/<1>\n\
 1346   Link numbering.\n\
 1347 \n\
 1348  -html-table-order <0>/<1>\n\
 1349   Walk table by rows (0) or columns (1).\n\
 1350 \n\
 1351  -html-margin <margin>\n\
 1352   Text margin.\n\
 1353 \n\
 1354  -language <language>\n\
 1355   User interface language.\n\
 1356 \n\
 1357  -anonymous\n\
 1358   Restrict links so that it can run on an anonymous account.\n\
 1359   No local file browsing. No downloads. Executing of viewers\n\
 1360   is allowed, but user can't add or modify entries in\n\
 1361   association table.\n\
 1362 \n\
 1363  -force-html\n\
 1364   Treat file as if it had an .html extension.\n\
 1365 \n\
 1366  -source\n\
 1367   Write the given HTML document in source form to stdout.\n\
 1368 \n\
 1369  -dump\n\
 1370   Write a plain-text version of the given HTML document to\n\
 1371   stdout.\n\
 1372 \n\
 1373  -width <size>\n\
 1374   Size of screen in characters, used in combination with -dump.\n\
 1375 \n\
 1376  -codepage <codepage>\n\
 1377   Character set of output of -dump.\n\
 1378 \n\
 1379  -no-connect\n\
 1380   Runs links as a separate instance - instead of connecting to\n\
 1381   existing instance.\n\
 1382 \n\
 1383  -lookup <host>\n\
 1384   Do lookup like \"host\" command.\n\
 1385 \n\
 1386  -version\n\
 1387   Prints the links version number and exit.\n\
 1388 \n\
 1389  -help\n\
 1390   Prints this help screen\n\
 1391 \n\
 1392 \n"),
 1393 ("Keys:\n\
 1394     ESC  display menu\n\
 1395     ^C   quit\n\
 1396     ^P, ^N   scroll up, down\n\
 1397     [, ]     scroll left, right\n\
 1398     up, down select link\n\
 1399     ->   follow link\n\
 1400     <-   go back\n\
 1401     g    go to url\n\
 1402     G    go to url based on current url\n\
 1403     ^R   reload\n\
 1404     /    search\n\
 1405     ?    search back\n\
 1406     n    find next\n\
 1407     N    find previous\n\
 1408     =    document info\n\
 1409     \\   document source\n\
 1410     |    HTTP header\n\
 1411     *    toggle displaying of image links\n\
 1412     d    download\n\
 1413     s    bookmarks\n\
 1414     q    quit\n"));
 1415 
 1416     fflush(stdout);
 1417     exit(RET_OK);
 1418     return "";
 1419 }
 1420 
 1421 void end_config()
 1422 {
 1423     if (links_home) mem_free(links_home);
 1424 }
 1425 
 1426 int anonymous = 0;
 1427 
 1428 unsigned char *links_home = NULL;
 1429 int first_use = 0;
 1430 int created_home = 0;
 1431 
 1432 int no_connect = 0;
 1433 int base_session = 0;
 1434 int dmp = 0;
 1435 int force_html = 0;
 1436 
 1437 int async_lookup = 1;
 1438 int download_utime = 0;
 1439 #ifdef DOS
 1440 /* DOS networking is slow with too many connections */
 1441 int max_connections = 3;
 1442 int max_connections_to_host = 2;
 1443 #else
 1444 int max_connections = 10;
 1445 int max_connections_to_host = 2;
 1446 #endif
 1447 int max_tries = 3;
 1448 int receive_timeout = 120;
 1449 int unrestartable_receive_timeout = 600;
 1450 
 1451 int screen_width = 80;
 1452 int dump_codepage = -1;
 1453 
 1454 int max_format_cache_entries = 5;
 1455 int memory_cache_size = 1048576;
 1456 
 1457 int enable_html_tables = 1;
 1458 int enable_html_frames = 1;
 1459 int display_images = 1;
 1460 
 1461 struct document_setup dds = { 0, 0, 1, 1, 0, 3, 0, 0 };
 1462 
 1463 struct rgb default_fg = { 191, 191, 191, 0 };
 1464 struct rgb default_bg = { 0, 0, 0, 0 };
 1465 struct rgb default_link = { 255, 255, 255, 0 };
 1466 struct rgb default_vlink = { 255, 255, 0, 0 };
 1467 
 1468 int default_left_margin = HTML_LEFT_MARGIN;
 1469 
 1470 unsigned char http_proxy[MAX_STR_LEN] = "";
 1471 unsigned char ftp_proxy[MAX_STR_LEN] = "";
 1472 
 1473 unsigned char download_dir[MAX_STR_LEN] = "";
 1474 
 1475 struct ftp_options ftp_options = { "somebody@host.domain", 0, 0, 1 };
 1476 
 1477 /* These are workarounds for some CGI script bugs */
 1478 struct http_bugs http_bugs = { 0, 1, 1, 0, 0 };
 1479 /*int bug_302_redirect = 0;*/
 1480     /* When got 301 or 302 from POST request, change it to GET
 1481        - this violates RFC2068, but some buggy message board scripts rely on it */
 1482 /*int bug_post_no_keepalive = 0;*/
 1483     /* No keepalive connection after POST request. Some buggy PHP databases report bad
 1484        results if GET wants to retreive data POSTed in the same connection */
 1485 
 1486 struct option links_options[] = {
 1487     { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "?" },
 1488     { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "h" },
 1489     { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "help" },
 1490     { 1, printhelp_cmd, NULL, NULL, 0, 0, NULL, NULL, "-help" },
 1491     { 1, lookup_cmd, NULL, NULL, 0, 0, NULL, NULL, "lookup" },
 1492     { 1, version_cmd, NULL, NULL, 0, 0, NULL, NULL, "version" },
 1493     { 1, no_connect_cmd, NULL, NULL, 0, 0, NULL, NULL, "no-connect" },
 1494     { 1, anonymous_cmd, NULL, NULL, 0, 0, NULL, NULL, "anonymous" },
 1495     { 1, gen_cmd, num_rd, NULL, 0, MAXINT, &base_session, NULL, "base-session" },
 1496     { 1, force_html_cmd, NULL, NULL, 0, 0, NULL, NULL, "force-html" },
 1497     { 1, dump_cmd, NULL, NULL, D_SOURCE, 0, NULL, NULL, "source" },
 1498     { 1, dump_cmd, NULL, NULL, D_DUMP, 0, NULL, NULL, "dump" },
 1499     { 1, gen_cmd, num_rd, NULL, 10, 512, &screen_width, "dump_width", "width" },
 1500     { 1, gen_cmd, cp_rd, NULL, 1, 0, &dump_codepage, "dump_codepage", "codepage" },
 1501     { 1, gen_cmd, num_rd, num_wr, 0, 1, &async_lookup, "async_dns", "async-dns" },
 1502     { 1, gen_cmd, num_rd, num_wr, 0, 1, &download_utime, "download_utime", "download-utime" },
 1503     { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections, "max_connections", "max-connections" },
 1504     { 1, gen_cmd, num_rd, num_wr, 1, 99, &max_connections_to_host, "max_connections_to_host", "max-connections-to-host" },
 1505     { 1, gen_cmd, num_rd, num_wr, 0, 16, &max_tries, "retries", "retries" },
 1506     { 1, gen_cmd, num_rd, num_wr, 1, 1800, &receive_timeout, "receive_timeout", "receive-timeout" },
 1507     { 1, gen_cmd, num_rd, num_wr, 1, 1800, &unrestartable_receive_timeout, "unrestartable_receive_timeout", "unrestartable-receive-timeout" },
 1508     { 1, gen_cmd, num_rd, num_wr, 0, 256, &max_format_cache_entries, "format_cache_size", "format-cache-size" },
 1509     { 1, gen_cmd, num_rd, num_wr, 0, MAXINT, &memory_cache_size, "memory_cache_size", "memory-cache-size" },
 1510     { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, http_proxy, "http_proxy", "http-proxy" },
 1511     { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, ftp_proxy, "ftp_proxy", "ftp-proxy" },
 1512     { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, download_dir, "download_dir", "download-dir" },
 1513     { 1, gen_cmd, lang_rd, lang_wr, 0, 0, &current_language, "language", "language" },
 1514     { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.http10, "http_bugs.http10", "http-bugs.http10" },
 1515     { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.allow_blacklist, "http_bugs.allow_blacklist", "http-bugs.allow-blacklist" },
 1516     { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_302_redirect, "http_bugs.bug_302_redirect", "http-bugs.bug-302-redirect" },
 1517     { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.bug_post_no_keepalive, "http_bugs.bug_post_no_keepalive", "http-bugs.bug-post-no-keepalive" },
 1518     { 1, gen_cmd, num_rd, num_wr, 0, 1, &http_bugs.no_accept_charset, "http_bugs.no_accept_charset", "http-bugs.bug-no-accept-charset" },
 1519     { 1, gen_cmd, str_rd, str_wr, 0, MAX_STR_LEN, ftp_options.anon_pass, "ftp.anonymous_password", "ftp.anonymous-password" },
 1520     { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.passive_ftp, "ftp.use_passive", "ftp.use-passive" },
 1521     { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.fast_ftp, "ftp.fast", "ftp.fast" },
 1522     { 1, gen_cmd, num_rd, num_wr, 0, 1, &ftp_options.set_tos, "ftp.set_iptos", "ftp.set-iptos" },
 1523     { 1, gen_cmd, cp_rd, NULL, 0, 0, &dds.assume_cp, "assume_codepage", "assume-codepage" },
 1524     { 1, NULL, term_rd, term_wr, 0, 0, NULL, "terminal", NULL },
 1525     { 1, NULL, term2_rd, NULL, 0, 0, NULL, "terminal2", NULL },
 1526     { 1, NULL, type_rd, type_wr, 0, 0, NULL, "association", NULL },
 1527     { 1, NULL, ext_rd, ext_wr, 0, 0, NULL, "extension", NULL },
 1528     { 1, NULL, prog_rd, prog_wr, 0, 0, &mailto_prog, "mailto", NULL },
 1529     { 1, NULL, prog_rd, prog_wr, 0, 0, &telnet_prog, "telnet", NULL },
 1530     { 1, NULL, prog_rd, prog_wr, 0, 0, &tn3270_prog, "tn3270", NULL },
 1531     { 1, NULL, prog_rd, prog_wr, 0, 0, &mms_prog, "mms", NULL },
 1532     { 1, NULL, bind_rd, NULL, 0, 0, NULL, "bind", NULL },
 1533     { 1, NULL, unbind_rd, NULL, 0, 0, NULL, "unbind", NULL },
 1534     { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL },
 1535 };
 1536 
 1537 struct option html_options[] = {
 1538     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.hard_assume, "html_hard_assume", "html-hard-assume" },
 1539     { 1, gen_cmd, cp_rd, cp_wr, 0, 0, &dds.assume_cp, "html_assume_codepage", "html-assume-codepage" },
 1540     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.tables, "html_tables", "html-tables" },
 1541     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.frames, "html_frames", "html-frames" },
 1542     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.images, "html_images", "html-images" },
 1543     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.num_links, "html_numbered_links", "html-numbered-links" },
 1544     { 1, gen_cmd, num_rd, num_wr, 0, 1, &dds.table_order, "html_table_order", "html-table-order" },
 1545     { 1, gen_cmd, num_rd, num_wr, 0, 9, &dds.margin, "html_margin", "html-margin" },
 1546     { 0, NULL, NULL, NULL, 0, 0, NULL, NULL, NULL },
 1547 };
 1548 
 1549 void load_url_history(void)
 1550 {
 1551     unsigned char *history_file, *hs;
 1552     unsigned char *hsp;
 1553 
 1554     if (anonymous) return;
 1555     /* Must have been called after init_home */
 1556     if (!links_home) return;
 1557     history_file = stracpy(links_home);
 1558     add_to_strn(&history_file, "links.his");
 1559     hs = read_config_file(history_file);
 1560     mem_free(history_file);
 1561     if (!hs) return;
 1562     for (hsp = hs; *hsp; ) {
 1563         unsigned char *hsl, *hsc;
 1564         for (hsl = hsp; *hsl && *hsl != 10 && *hsl != 13; hsl++) ;
 1565         hsc = memacpy(hsp, hsl - hsp);
 1566         add_to_history(&goto_url_history, hsc, 0);
 1567         mem_free(hsc);
 1568         hsp = hsl;
 1569         while (*hsp == 10 || *hsp == 13) hsp++;
 1570     }
 1571     mem_free(hs);
 1572 }
 1573 
 1574 void save_url_history(void)
 1575 {
 1576     struct history_item *hi;
 1577     unsigned char *history_file;
 1578     unsigned char *hs;
 1579     int hsl = 0;
 1580     int i = 0;
 1581     if (anonymous) return;
 1582 
 1583     /* Must have been called after init_home */
 1584     if (!links_home) return;
 1585     history_file = stracpy(links_home);
 1586     add_to_strn(&history_file, "links.his");
 1587     hs = init_str();
 1588     hsl = 0;
 1589     foreachback(hi, goto_url_history.items) {
 1590         if (!*hi->d || strchr(hi->d, 10) || strchr(hi->d, 13)) continue;
 1591         if (!url_not_saveable(hi->d) && i++ <= MAX_HISTORY_ITEMS) {
 1592             add_to_str(&hs, &hsl, hi->d);
 1593             add_to_str(&hs, &hsl, NEWLINE);
 1594         }
 1595     }
 1596     write_to_config_file(history_file, hs);
 1597     mem_free(history_file);
 1598     mem_free(hs);
 1599     return;
 1600 }
 1601