"Fossies" - the Fresh Open Source Software Archive

Member "links-1.03/os_dep.c" (23 Nov 2011, 43620 Bytes) of archive /linux/www/links-1.03.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 "os_dep.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_1.03.

    1 #include "links.h"
    2 
    3 #ifdef HAVE_SYS_IOCTL_H
    4 #include <sys/ioctl.h>
    5 #endif
    6 
    7 #if defined(HAVE_LIBGPM) && defined(HAVE_GPM_H)
    8 #define USE_GPM
    9 #endif
   10 
   11 #ifdef USE_GPM
   12 #include <gpm.h>
   13 #endif
   14 
   15 int is_safe_in_shell(unsigned char c)
   16 {
   17     return c == '@' || c == '+' || c == '-' || c == '.' || c == ',' || c == '=' || (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= 'a' && c <= 'z');
   18 }
   19 
   20 int is_safe_in_url(unsigned char c)
   21 {
   22     return is_safe_in_shell(c) || c == ':' || c == '/' || c >= 0x80;
   23 }
   24 
   25 void check_shell_security(unsigned char **cmd)
   26 {
   27     unsigned char *c = *cmd;
   28     while (*c) {
   29         if (!is_safe_in_shell(*c)) *c = '_';
   30         c++;
   31     }
   32 }
   33 
   34 int check_shell_url(unsigned char *url)
   35 {
   36     while (*url) {
   37         if (!is_safe_in_url(*url)) return -1;
   38         url++;
   39     }
   40     return 0;
   41 }
   42 
   43 unsigned char *escape_path(unsigned char *path)
   44 {
   45     unsigned char *result;
   46     size_t i;
   47     if (strchr(path, '"')) return stracpy(path);
   48     for (i = 0; path[i]; i++) if (!is_safe_in_url(path[i])) goto do_esc;
   49     return stracpy(path);
   50     do_esc:
   51     result = stracpy("\"");
   52     add_to_strn(&result, path);
   53     add_to_strn(&result, "\"");
   54     return result;
   55 }
   56 
   57 int get_e(char *env)
   58 {
   59     char *v;
   60     if ((v = getenv(env))) return atoi(v);
   61     return 0;
   62 }
   63 
   64 #if defined(WIN32)
   65 #include <windows.h>
   66 #endif
   67 
   68 #if defined(OS2)
   69 
   70 #define INCL_MOU
   71 #define INCL_VIO
   72 #define INCL_DOSPROCESS
   73 #define INCL_DOSERRORS
   74 #define INCL_DOSMODULEMGR
   75 #define INCL_WINCLIPBOARD
   76 #define INCL_WINSWITCHLIST
   77 #include <os2.h>
   78 #include <io.h>
   79 #include <process.h>
   80 #include <sys/video.h>
   81 #ifdef HAVE_SYS_FMUTEX_H
   82 #include <sys/builtin.h>
   83 #include <sys/fmutex.h>
   84 #endif
   85 
   86 #ifdef X2
   87 /* from xf86sup - XFree86 OS/2 support driver */
   88 #include <pty.h>
   89 #endif
   90 
   91 #endif
   92 
   93 #if defined(O_SIZE) && defined(__EMX__)
   94 
   95 int can_prealloc(char *name)
   96 {
   97     return name[0] && name[1] == ':' && dir_sep(name[2]);
   98 }
   99 
  100 int open_prealloc(char *name, int flags, int mode, off_t siz)
  101 {
  102     return open(name, flags | O_SIZE, mode, (unsigned long)siz);
  103 }
  104 
  105 void prealloc_truncate(int h, off_t siz)
  106 {
  107     ftruncate(h, siz);
  108 }
  109 
  110 #endif
  111 
  112 /* Terminal size */
  113 
  114 #ifdef WIN32
  115 
  116 /* Cygwin has a bug and loses SIGWINCH sometimes, so poll it */
  117 
  118 static void winch_thread(void *p, int l)
  119 {
  120     static int old_xsize, old_ysize;
  121     static int cur_xsize, cur_ysize;
  122     if (get_terminal_size(0, &old_xsize, &old_ysize)) return;
  123     while (1) {
  124         if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
  125         if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
  126             old_xsize = cur_xsize;
  127             old_ysize = cur_ysize;
  128             raise(SIGWINCH);
  129         }
  130         sleep(1);
  131     }
  132 }
  133 
  134 static void win32_resize_poll(void)
  135 {
  136     static int winch_thread_running = 0;
  137     if (!winch_thread_running) {
  138         if (start_thread(winch_thread, NULL, 0) >= 0)
  139             winch_thread_running = 1;
  140     }
  141 }
  142 
  143 #endif
  144 
  145 #if defined(UNIX) || defined(WIN32) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
  146 
  147 void sigwinch(void *s)
  148 {
  149     ((void (*)())s)();
  150 }
  151 
  152 void handle_terminal_resize(int fd, void (*fn)())
  153 {
  154     install_signal_handler(SIGWINCH, sigwinch, fn, 0);
  155 #ifdef WIN32
  156     win32_resize_poll();
  157 #endif
  158 }
  159 
  160 void unhandle_terminal_resize(int fd)
  161 {
  162     install_signal_handler(SIGWINCH, NULL, NULL, 0);
  163 }
  164 
  165 int get_terminal_size(int fd, int *x, int *y)
  166 {
  167     volatile struct winsize ws; /* Sun Studio misoptimizes it */
  168     if (!x || !y) return -1;
  169     if (ioctl(1, TIOCGWINSZ, &ws) != -1) {
  170         if (!(*x = ws.ws_col) && !(*x = get_e("COLUMNS"))) *x = 80;
  171         if (!(*y = ws.ws_row) && !(*y = get_e("LINES"))) *y = 24;
  172         return 0;
  173     } else {
  174         if (!(*x = get_e("COLUMNS"))) *x = 80;
  175         if (!(*y = get_e("LINES"))) *y = 24;
  176     }
  177     return 0;
  178 }
  179 
  180 #elif defined(OS2)
  181 
  182 #define A_DECL(type, var) type var##1, var##2, *var = _THUNK_PTR_STRUCT_OK(&var##1) ? &var##1 : &var##2
  183 
  184 int is_xterm(void)
  185 {
  186     static int xt = -1;
  187     if (xt == -1) xt = !!getenv("WINDOWID");
  188     return xt;
  189 }
  190 
  191 int winch_pipe[2];
  192 int winch_thread_running = 0;
  193 
  194 #define WINCH_SLEEPTIME 500 /* time in ms for winch thread to sleep */
  195 
  196 void winch_thread(void)
  197 {
  198     /* A thread which regularly checks whether the size of 
  199        window has changed. Then raise SIGWINCH or notifiy
  200        the thread responsible to handle this. */
  201     static int old_xsize, old_ysize;
  202     static int cur_xsize, cur_ysize;
  203 
  204     signal(SIGPIPE, SIG_IGN);
  205     if (get_terminal_size(1, &old_xsize, &old_ysize)) return;
  206     while (1) {
  207         if (get_terminal_size(1, &cur_xsize, &cur_ysize)) return;
  208         if ((old_xsize != cur_xsize) || (old_ysize != cur_ysize)) {
  209             old_xsize = cur_xsize;
  210             old_ysize = cur_ysize;
  211             write(winch_pipe[1], "x", 1);
  212             /* Resizing may take some time. So don't send a flood
  213                      of requests?! */
  214             _sleep2(2*WINCH_SLEEPTIME);   
  215         }
  216         else
  217             _sleep2(WINCH_SLEEPTIME);
  218     }
  219 }
  220 
  221 void winch(void *s)
  222 {
  223     char c;
  224     while (can_read(winch_pipe[0]) && read(winch_pipe[0], &c, 1) == 1);
  225     ((void (*)())s)();
  226 }
  227 
  228 void handle_terminal_resize(int fd, void (*fn)())
  229 {
  230     if (!is_xterm()) return;
  231     if (!winch_thread_running) {
  232         if (c_pipe(winch_pipe) < 0) return;
  233         winch_thread_running = 1;
  234         _beginthread((void (*)(void *))winch_thread, NULL, 0x32000, NULL);
  235     }
  236     set_handlers(winch_pipe[0], winch, NULL, NULL, fn);
  237 }
  238 
  239 void unhandle_terminal_resize(int fd)
  240 {
  241     set_handlers(winch_pipe[0], NULL, NULL, NULL, NULL);
  242 }
  243 
  244 int get_terminal_size(int fd, int *x, int *y)
  245 {
  246     if (!x || !y) return -1;
  247     if (is_xterm()) {
  248 #ifdef X2
  249         /* int fd; */
  250         int arc;
  251         struct winsize win;
  252 
  253         /* fd = STDIN_FILENO; */
  254         arc = ptioctl(1, TIOCGWINSZ, &win);
  255         if (arc) {
  256 /*
  257             debug("%d", errno);
  258 */
  259             *x = 80;
  260             *y = 24;
  261             return 0;
  262         }
  263         *y = win.ws_row;
  264         *x = win.ws_col;
  265 /*
  266         debug("%d %d", *x, *y);
  267 */
  268         goto set_default;
  269 #else
  270         *x = 80; *y = 24;
  271         return 0;
  272 #endif
  273     } else {
  274         int a[2] = { 0, 0 };
  275         _scrsize(a);
  276         *x = a[0];
  277         *y = a[1];
  278         set_default:
  279         if (*x == 0) {
  280             *x = get_e("COLUMNS");
  281             if (*x == 0) *x = 80;
  282         }
  283         if (*y == 0) {
  284             *y = get_e("LINES");
  285             if (*y == 0) *y = 24;
  286         }
  287     }
  288     return 0;
  289 }
  290 
  291 #endif
  292 
  293 /* Pipe */
  294 
  295 #if defined(UNIX) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
  296 
  297 void set_bin(int fd)
  298 {
  299 }
  300 
  301 int c_pipe(int *fd)
  302 {
  303     return pipe(fd);
  304 }
  305 
  306 #elif defined(OS2) || defined(WIN32)
  307 
  308 void set_bin(int fd)
  309 {
  310     setmode(fd, O_BINARY);
  311 }
  312 
  313 int c_pipe(int *fd)
  314 {
  315     int r = pipe(fd);
  316     if (!r) set_bin(fd[0]), set_bin(fd[1]);
  317     return r;
  318 }
  319 
  320 #endif
  321 
  322 /* Filename */
  323 
  324 int check_file_name(unsigned char *file)
  325 {
  326     return 1;       /* !!! FIXME */
  327 }
  328 
  329 /* Exec */
  330 
  331 int can_twterm() /* Check if it make sense to call a twterm. */
  332 {
  333     static int xt = -1;
  334     if (xt == -1) xt = !!getenv("TWDISPLAY");
  335     return xt;
  336 }
  337 
  338 
  339 #if defined(UNIX) || defined(SPAD)
  340 
  341 int is_xterm()
  342 {
  343     static int xt = -1;
  344     if (xt == -1) xt = getenv("DISPLAY") && *getenv("DISPLAY");
  345     return xt;
  346 }
  347 
  348 #elif defined(BEOS) || defined(ATHEOS)
  349 
  350 int is_xterm()
  351 {
  352     return 0;
  353 }
  354 
  355 #elif defined(WIN32) || defined(INTERIX)
  356 
  357 int is_xterm(void)
  358 {
  359     static int xt = -1;
  360     if (xt == -1) xt = !!getenv("WINDOWID");
  361     return xt;
  362 }
  363 
  364 #elif defined(RISCOS)
  365 
  366 int is_xterm()
  367 {
  368        return 1;
  369 }
  370 
  371 #endif
  372 
  373 tcount resize_count = 0;
  374 
  375 void close_fork_tty()
  376 {
  377     struct terminal *t;
  378     struct download *d;
  379     struct connection *c;
  380     struct k_conn *k;
  381     foreach (t, terminals) if (t->fdin > 0) close(t->fdin);
  382     foreach (d, downloads) if (d->handle > 0) close(d->handle);
  383     foreach (c, queue) close_socket(&c->sock1), close_socket(&c->sock2);
  384     foreach (k, keepalive_connections) close(k->conn);
  385 }
  386 
  387 void init_os(void)
  388 {
  389 #if defined(RLIMIT_OFILE) && !defined(RLIMIT_NOFILE)
  390 #define RLIMIT_NOFILE RLIMIT_OFILE
  391 #endif
  392 #if defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) && defined(RLIMIT_NOFILE)
  393     struct rlimit limit;
  394     if (getrlimit(RLIMIT_NOFILE, &limit))
  395         goto skip_limit;
  396     if (limit.rlim_cur > FD_SETSIZE) {
  397         limit.rlim_cur = FD_SETSIZE;
  398         setrlimit(RLIMIT_NOFILE, &limit);
  399     }
  400 skip_limit:;
  401 #endif
  402 }
  403 
  404 void init_os_terminal(void)
  405 {
  406 #ifdef INTERIX
  407     /* Some sort of terminal bug in Interix, if we run xterm -e links,
  408        terminal doesn't switch to raw mode, executing "stty sane" fixes it.
  409        Don't do this workaround on console. */
  410     unsigned char *term = getenv("TERM");
  411     if (!term || strncasecmp(term, "interix", 7))
  412         system("stty sane 2>/dev/null");
  413 #endif
  414 }
  415 
  416 #if defined(WIN32)
  417 
  418 void get_path_to_exe(void)
  419 {
  420     /* Standard method (argv[0]) doesn't work, if links is executed from
  421        symlink --- it returns symlink name and cmd.exe is unable to start
  422        it */
  423     unsigned r;
  424     static unsigned char path[4096];
  425     r = GetModuleFileName(NULL, path, sizeof path);
  426     if (r <= 0 || r >= sizeof path) {
  427         path_to_exe = g_argv[0];
  428         return;
  429     }
  430     path_to_exe = path;
  431 }
  432 
  433 #elif defined(OS2)
  434 
  435 void get_path_to_exe(void)
  436 {
  437     /* If you spawn links with quotation marks from cmd.exe,
  438        the quotation marks will be present in g_argv[0] ... and will
  439        prevent executing it */
  440     static unsigned char path[270];
  441     PPIB pib = NULL;
  442     path_to_exe = g_argv[0];
  443     /*if (!strchr(path_to_exe, ' ') && !strchr(path_to_exe, '"')) return;*/
  444     DosGetInfoBlocks(NULL, &pib);
  445     if (!pib) return;
  446     if (DosQueryModuleName(pib->pib_hmte, sizeof path, path)) return;
  447     path_to_exe = path;
  448 }
  449 
  450 #else
  451 
  452 void get_path_to_exe(void)
  453 {
  454     path_to_exe = g_argv[0];
  455 }
  456 
  457 #endif
  458 
  459 #if defined(WIN32) && defined(HAVE_CYGWIN_CONV_PATH)
  460 
  461 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
  462 {
  463     unsigned char *new_path;
  464     ssize_t sz;
  465     sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, NULL, 0);
  466     if (sz < 0) return stracpy(file);
  467     new_path = mem_alloc(sz);
  468     sz = cygwin_conv_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file, new_path, sz);
  469     if (sz < 0) {
  470         mem_free(new_path);
  471         return stracpy(file);
  472     }
  473     return new_path;
  474 }
  475 
  476 #elif defined(WIN32) && defined(HAVE_CYGWIN_CONV_TO_FULL_WIN32_PATH)
  477 
  478 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
  479 {
  480 #ifdef MAX_PATH
  481     unsigned char new_path[MAX_PATH];
  482 #else
  483     unsigned char new_path[1024];
  484 #endif
  485     *new_path = 0;
  486     cygwin_conv_to_full_win32_path(file, new_path);
  487     if (!*new_path) return stracpy(file);
  488     return stracpy(new_path);
  489 }
  490 
  491 #elif defined(INTERIX) && defined(HAVE_UNIXPATH2WIN)
  492 
  493 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
  494 {
  495     /* Convert path only if the program has ".exe" extension */
  496     unsigned char *prog_end;
  497     if (prog[0] == '"' || prog[0] == '\'') prog_end = strchr(prog + 1, prog[0]);
  498     else prog_end = strchr(prog, ' ');
  499     if (!prog_end) goto copy_path;
  500     if (prog_end - prog <= 4) goto copy_path;
  501     if (!strncasecmp(prog_end - 4, ".exe", 4)) {
  502 #ifdef MAX_PATH
  503         unsigned char new_path[MAX_PATH];
  504 #else
  505         unsigned char new_path[512];
  506 #endif
  507         unsigned char *newstr;
  508         int newstrl;
  509         unsigned char *p;
  510         if (unixpath2win(file, 0, new_path, sizeof(new_path)))
  511             goto copy_path;
  512         /*return stracpy(new_path);*/
  513         newstr = init_str();
  514         newstrl = 0;
  515         for (p = new_path; *p; p++) {
  516             /*
  517              * Unix shell hates backslash and Windows applications
  518              * accept '/'
  519              */
  520             if (*p == '\\') add_to_str(&newstr, &newstrl, "/");
  521             else add_chr_to_str(&newstr, &newstrl, *p);
  522         }
  523         return newstr;
  524     }
  525     copy_path:
  526     return stracpy(file);
  527 }
  528 
  529 #else
  530 
  531 unsigned char *os_conv_to_external_path(unsigned char *file, unsigned char *prog)
  532 {
  533     return stracpy(file);
  534 }
  535 
  536 #endif
  537 
  538 #if defined(INTERIX) && defined(HAVE_WINPATH2UNIX)
  539 
  540 unsigned char *os_fixup_external_program(unsigned char *prog)
  541 {
  542     unsigned char *prog_start;
  543     unsigned char *prog_end;
  544     if (prog[0] == '"' || prog[0] == '\'') {
  545         prog_start = prog + 1;
  546         prog_end = strchr(prog + 1, prog[0]);
  547         if (!prog_end)
  548             prog_end = strchr(prog, 0);
  549     } else {
  550         prog_start = prog;
  551         prog_end = prog + strcspn(prog, " ");
  552     }
  553     if (prog_end - prog_start >= 3 && upcase(prog_start[0]) >= 'A' && upcase(prog_start[0]) <= 'Z' && prog_start[1] == ':') {
  554 #ifdef MAX_PATH
  555         unsigned char new_path[MAX_PATH];
  556 #else
  557         unsigned char new_path[1024];
  558 #endif
  559         unsigned char *newstr;
  560         int newstrl;
  561         unsigned char *xpath = memacpy(prog_start, prog_end - prog_start);
  562         if (winpath2unix(xpath, 0, new_path, sizeof(new_path))) {
  563             mem_free(xpath);
  564             goto copy_prog;
  565         }
  566         mem_free(xpath);
  567         newstr = init_str();
  568         newstrl = 0;
  569         add_bytes_to_str(&newstr, &newstrl, prog, prog_start - prog);
  570         add_to_str(&newstr, &newstrl, new_path);
  571         add_to_str(&newstr, &newstrl, prog_end);
  572         return newstr;
  573     }
  574     copy_prog:
  575     return stracpy(prog);
  576 }
  577 
  578 
  579 #else
  580 
  581 unsigned char *os_fixup_external_program(unsigned char *prog)
  582 {
  583     return stracpy(prog);
  584 }
  585 
  586 #endif
  587 
  588 
  589 #if defined(UNIX) || defined(INTERIX) || defined(BEOS) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
  590 
  591 #if defined(BEOS) && defined(HAVE_SETPGID)
  592 
  593 int exe(char *path)
  594 {
  595     pid_t p;
  596     int s;
  597     if (!(p = fork())) {
  598         setpgid(0, 0);
  599         system(path);
  600         _exit(0);
  601     }
  602     if (p > 0) waitpid(p, &s, 0);
  603     else return system(path);
  604     return 0;
  605 }
  606 
  607 #else
  608 
  609 int exe(char *path)
  610 {
  611 #ifdef SIGTSTP
  612     signal(SIGTSTP, SIG_DFL);
  613 #endif
  614 #ifdef SIGCONT
  615     signal(SIGCONT, SIG_DFL);
  616 #endif
  617 #ifdef SIGWINCH
  618     signal(SIGWINCH, SIG_DFL);
  619 #endif
  620     return system(path);
  621 }
  622 
  623 #endif
  624 
  625 char *get_clipboard_text()  /* !!! FIXME */
  626 {
  627     return stracpy("");
  628 }
  629 
  630 void set_clipboard_text(char *data)
  631 {
  632     /* !!! FIXME */
  633 }
  634 
  635 void set_window_title(unsigned char *title)
  636 {
  637     /* !!! FIXME */
  638 }
  639 
  640 unsigned char *get_window_title()
  641 {
  642     /* !!! FIXME */
  643     return NULL;
  644 }
  645 
  646 int resize_window(int x, int y)
  647 {
  648     return -1;
  649 }
  650 
  651 #elif defined(WIN32)
  652 
  653 static int is_winnt(void)
  654 {
  655     OSVERSIONINFO v;
  656     v.dwOSVersionInfoSize = sizeof v;
  657     if (!GetVersionEx(&v)) return 0;
  658     return v.dwPlatformId >= VER_PLATFORM_WIN32_NT;
  659 }
  660 
  661 #define WIN32_START_STRING  "start /wait "
  662 
  663 int exe(char *path)
  664 {
  665     /* This is very tricky. We must have exactly 3 arguments, the first
  666        one shell and the second one "/c", otherwise Cygwin would quote
  667        the arguments and trash them */
  668     int ct;
  669     char buffer[1024];
  670     char buffer2[1024];
  671     pid_t pid;
  672     unsigned char *x1;
  673     char *arg;
  674     x1 = GETSHELL;
  675     if (!x1) x1 = DEFAULT_SHELL;
  676     arg = alloca(strlen(WIN32_START_STRING) + 3 + strlen(path) + 1);
  677     strcpy(arg, WIN32_START_STRING);
  678     if (*path == '"' && strlen(x1) >= 7 && !strcasecmp(x1 + strlen(x1) - 7, "cmd.exe")) strcat(arg, "\"\" ");
  679     strcat(arg, path);
  680     ct = GetConsoleTitle(buffer, sizeof buffer);
  681     if (!(pid = fork())) {
  682         int i;
  683     /* Win98 crashes if we spawn command.com and have some sockets open */
  684         for (i = 0; i < FD_SETSIZE; i++) close(i);
  685         open("nul", O_RDONLY);
  686         open("nul", O_WRONLY);
  687         open("nul", O_WRONLY);
  688         execlp(x1, x1, "/c", arg, NULL);
  689         _exit(1);
  690     }
  691     if (!is_winnt()) {
  692         sleep(1);
  693         if (ct && GetConsoleTitle(buffer2, sizeof buffer2) && !casecmp(buffer2, "start", 5)) {
  694             SetConsoleTitle(buffer);
  695         }
  696     }
  697     if (pid != -1) waitpid(pid, NULL, 0);
  698     return 0;
  699 }
  700 
  701 char *get_clipboard_text()
  702 {
  703     char buffer[256];
  704     unsigned char *str, *s, *d;
  705     int l;
  706     int r;
  707     int h = open("/dev/clipboard", O_RDONLY);
  708     if (h == -1) return stracpy("");
  709     set_bin(h); /* O_TEXT doesn't work on clipboard handle */
  710     str = init_str();
  711     l = 0;
  712     while ((r = hard_read(h, buffer, sizeof buffer)) > 0)
  713         add_bytes_to_str(&str, &l, buffer, r);
  714     close(h);
  715     for (s = str, d = str; *s; s++)
  716         if (!(s[0] == '\r' && s[1] == '\n')) *d++ = *s;
  717     *d = 0;
  718     return str;
  719 }
  720 
  721 /* Putting Czech characters to clipboard doesn't work, but it should be fixed
  722    rather in Cygwin than here */
  723 void set_clipboard_text(char *data)
  724 {
  725     unsigned char *conv_data;
  726     int l;
  727     int h;
  728     h = open("/dev/clipboard", O_WRONLY);
  729     if (h == -1) return;
  730     set_bin(h); /* O_TEXT doesn't work on clipboard handle */
  731     conv_data = init_str();
  732     l = 0;
  733     for (; *data; data++)
  734         if (*data == '\n') add_to_str(&conv_data, &l, "\r\n");
  735         else add_chr_to_str(&conv_data, &l, *data);
  736     hard_write(h, conv_data, l);
  737     mem_free(conv_data);
  738     close(h);
  739 }
  740 
  741 int clipboard_support(struct terminal *term)
  742 {
  743     return 1;
  744 }
  745 
  746 
  747 static int get_windows_cp(void)
  748 {
  749     unsigned char str[6];
  750     int cp, idx;
  751     static int win_cp_idx = -1;
  752     if (win_cp_idx != -1) return win_cp_idx;
  753     if (is_winnt())
  754         cp = GetConsoleOutputCP();
  755     else
  756         cp = GetACP();
  757     if (cp <= 0 || cp >= 100000) return 0;
  758     sprintf(str, "%d", cp);
  759     if ((idx = get_cp_index(str)) < 0) return 0;
  760     win_cp_idx = idx;
  761     return idx;
  762 }
  763 
  764 static int get_utf8_cp(void)
  765 {
  766     static int idx = -1;
  767     return idx >= 0 ? idx : (idx = get_cp_index("utf-8"));
  768 }
  769 
  770 void set_window_title(unsigned char *title)
  771 {
  772     unsigned char *t;
  773     struct conv_table *ct;
  774     if (!title) return;
  775     if (is_xterm()) return;
  776     ct = get_translation_table(get_utf8_cp(), get_windows_cp());
  777     t = convert_string(ct, title, strlen(title));
  778     SetConsoleTitle(t);
  779     mem_free(t);
  780 }
  781 
  782 unsigned char *get_window_title(void)
  783 {
  784     struct conv_table *ct;
  785     int r;
  786     char buffer[1024];
  787     if (is_xterm()) return NULL;
  788     if (!(r = GetConsoleTitle(buffer, sizeof buffer))) return NULL;
  789     ct = get_translation_table(get_windows_cp(), get_utf8_cp());
  790     return convert_string(ct, buffer, r);
  791 }
  792 
  793 static void call_resize(unsigned char *x1, int x, int y)
  794 {
  795     pid_t pid;
  796     unsigned char arg[40];
  797     sprintf(arg, "mode %d,%d", x, y);
  798     if (!(pid = fork())) {
  799         int i;
  800     /* Win98 crashes if we spawn command.com and have some sockets open */
  801         for (i = 0; i < FD_SETSIZE; i++) if (i != 1 && i != 2) close(i);
  802         open("nul", O_WRONLY);
  803         execlp(x1, x1, "/c", arg, NULL);
  804         _exit(1);
  805     }
  806     if (pid != -1) waitpid(pid, NULL, 0);
  807 }
  808 
  809 int resize_window(int x, int y)
  810 {
  811     int old_x, old_y;
  812     int ct = 0, fullscreen = 0;
  813     char buffer[1024];
  814     unsigned char *x1;
  815     if (is_xterm()) return -1;
  816     if (get_terminal_size(1, &old_x, &old_y)) return -1;
  817     x1 = GETSHELL;
  818     if (!x1) x1 = DEFAULT_SHELL;
  819     if (!is_winnt()) {
  820         ct = GetConsoleTitle(buffer, sizeof buffer);
  821     }
  822 
  823     call_resize(x1, x, y);
  824     if (!is_winnt()) {
  825         int new_x, new_y;
  826     /* If we resize console on Win98 in fullscreen mode, it won't be
  827        notified by Cygwin (it is valid for all Cygwin apps). So we must
  828        switch to windowed mode, resize it again (twice, because resizing
  829        to the same size won't have an effect) and switch back to full-screen
  830        mode. */
  831     /* I'm not sure what's the behavior on WinNT 4. Anybody wants to test?
  832        */
  833         if (!fullscreen && !get_terminal_size(1, &new_x, &new_y) && (new_x != x || new_y != y)) {
  834             fullscreen = 1;
  835             keybd_event(VK_MENU, 0x38, 0, 0);
  836             keybd_event(VK_RETURN, 0x1c, 0, 0);
  837             keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
  838             keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
  839             if (y != 25) call_resize(x1, 80, 25);
  840             else call_resize(x1, 80, 50);
  841             call_resize(x1, x, y);
  842             if (get_terminal_size(1, &new_x, &new_y) || new_x != x || new_y != y) call_resize(x1, old_x, old_y);
  843             keybd_event(VK_MENU, 0x38, 0, 0);
  844             keybd_event(VK_RETURN, 0x1c, 0, 0);
  845             keybd_event(VK_RETURN, 0x1c, KEYEVENTF_KEYUP, 0);
  846             keybd_event(VK_MENU, 0x38, KEYEVENTF_KEYUP, 0);
  847         }
  848         if (ct) SetConsoleTitle(buffer);
  849     }
  850     return 0;
  851 }
  852 
  853 #elif defined(OS2)
  854 
  855 int exe(char *path)
  856 {
  857     int flags = P_SESSION;
  858     pid_t pid;
  859     int ret;
  860     char *shell;
  861     if (!(shell = GETSHELL)) shell = DEFAULT_SHELL;
  862     if (is_xterm()) flags |= P_BACKGROUND;
  863     if ((pid = spawnlp(flags, shell, shell, "/c", path, NULL)) != -1)
  864         waitpid(pid, &ret, 0);
  865     else ret = -1;
  866     return ret;
  867 }
  868 
  869 char *get_clipboard_text()
  870 {
  871     PTIB tib;
  872     PPIB pib;
  873     HAB hab;
  874     HMQ hmq;
  875     ULONG oldType;
  876     char *ret = NULL;
  877 
  878     DosGetInfoBlocks(&tib, &pib);
  879 
  880     oldType = pib->pib_ultype;
  881 
  882     pib->pib_ultype = 3;
  883 
  884     if ((hab = WinInitialize(0)) != NULLHANDLE) {
  885         if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
  886 
  887             if (WinOpenClipbrd(hab)) {
  888                 ULONG fmtInfo = 0;
  889 
  890                 if (WinQueryClipbrdFmtInfo(hab, CF_TEXT, &fmtInfo)!=FALSE)
  891                 {
  892                     ULONG selClipText = WinQueryClipbrdData(hab, CF_TEXT);
  893 
  894                     if (selClipText)
  895                     {
  896                         char *u;
  897                         PCHAR pchClipText = (PCHAR)selClipText;
  898                         ret = mem_alloc(strlen(pchClipText)+1);
  899                         strcpy(ret, pchClipText);
  900                         while ((u = strchr(ret, 13))) memmove(u, u + 1, strlen(u + 1) + 1);
  901                     }
  902                 }
  903 
  904                 WinCloseClipbrd(hab);
  905             }
  906 
  907             WinDestroyMsgQueue(hmq);
  908         }
  909         WinTerminate(hab);
  910     }
  911 
  912     pib->pib_ultype = oldType;
  913 
  914     return ret;
  915 }
  916 
  917 void set_clipboard_text(char *data)
  918 {
  919     PTIB tib;
  920     PPIB pib;
  921     HAB hab;
  922     HMQ hmq;
  923     ULONG oldType;
  924 
  925     DosGetInfoBlocks(&tib, &pib);
  926 
  927     oldType = pib->pib_ultype;
  928 
  929     pib->pib_ultype = 3;
  930 
  931     if ((hab = WinInitialize(0)) != NULLHANDLE) {
  932         if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
  933             if(WinOpenClipbrd(hab)) {
  934                 PVOID pvShrObject = NULL;
  935                 if (DosAllocSharedMem(&pvShrObject, NULL, strlen(data)+1, PAG_COMMIT | PAG_WRITE | OBJ_GIVEABLE) == NO_ERROR) {
  936                     strcpy(pvShrObject, data);
  937                     WinEmptyClipbrd(hab);
  938                     WinSetClipbrdData(hab, (ULONG)pvShrObject, CF_TEXT, CFI_POINTER);
  939                 }
  940                 WinCloseClipbrd(hab);
  941             }
  942             WinDestroyMsgQueue(hmq);
  943         }
  944         WinTerminate(hab);
  945     }
  946 
  947     pib->pib_ultype = oldType;
  948 }
  949 
  950 unsigned char *get_window_title()
  951 {
  952 #ifndef OS2_DEBUG
  953     /*char *org_switch_title;*/
  954     char *org_win_title = NULL;
  955     static PTIB tib = NULL;
  956     static PPIB pib = NULL;
  957     ULONG oldType;
  958     HSWITCH hSw = NULLHANDLE;
  959     SWCNTRL swData;
  960     HAB hab;
  961     HMQ hmq;
  962 
  963     /* save current process title */
  964 
  965     if (!pib) DosGetInfoBlocks(&tib, &pib);
  966     oldType = pib->pib_ultype;
  967     memset(&swData, 0, sizeof swData);
  968     if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
  969     if (hSw!=NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
  970         /*org_switch_title = mem_alloc(strlen(swData.szSwtitle)+1);
  971         strcpy(org_switch_title, swData.szSwtitle);*/
  972         /* Go to PM */
  973         pib->pib_ultype = 3;
  974         if ((hab = WinInitialize(0)) != NULLHANDLE) {
  975             if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
  976                 org_win_title = mem_alloc(MAXNAMEL+1);
  977                 WinQueryWindowText(swData.hwnd, MAXNAMEL+1, org_win_title);
  978                 org_win_title[MAXNAMEL] = 0;
  979                 /* back From PM */
  980                 WinDestroyMsgQueue(hmq);
  981             }
  982             WinTerminate(hab);
  983         }
  984         pib->pib_ultype = oldType;
  985     }
  986     return org_win_title;
  987 #else
  988     return NULL;
  989 #endif
  990 }
  991 
  992 void set_window_title(unsigned char *title)
  993 {
  994 #ifndef OS2_DEBUG
  995     static PTIB tib;
  996     static PPIB pib;
  997     ULONG oldType;
  998     static HSWITCH hSw;
  999     SWCNTRL swData;
 1000     HAB hab;
 1001     HMQ hmq;
 1002     if (!title) return;
 1003     if (!pib) DosGetInfoBlocks(&tib, &pib);
 1004     oldType = pib->pib_ultype;
 1005     memset(&swData, 0, sizeof swData);
 1006     if (hSw == NULLHANDLE) hSw = WinQuerySwitchHandle(0, pib->pib_ulpid);
 1007     if (hSw!=NULLHANDLE && !WinQuerySwitchEntry(hSw, &swData)) {
 1008         safe_strncpy(swData.szSwtitle, title, MAXNAMEL);
 1009         WinChangeSwitchEntry(hSw, &swData);
 1010         /* Go to PM */
 1011         pib->pib_ultype = 3;
 1012         if ((hab = WinInitialize(0)) != NULLHANDLE) {
 1013             if ((hmq = WinCreateMsgQueue(hab, 0)) != NULLHANDLE) {
 1014                 if(swData.hwnd)
 1015                     WinSetWindowText(swData.hwnd, title);
 1016                     /* back From PM */
 1017                 WinDestroyMsgQueue(hmq);
 1018             }
 1019             WinTerminate(hab);
 1020         }
 1021     }
 1022     pib->pib_ultype = oldType;
 1023 #endif
 1024 }
 1025 
 1026 int resize_window(int x, int y)
 1027 {
 1028     int xfont, yfont;
 1029     A_DECL(VIOMODEINFO, vmi);
 1030     resize_count++;
 1031     if (is_xterm()) return -1;
 1032     vmi->cb = sizeof(*vmi);
 1033     if (VioGetMode(vmi, 0)) return -1;
 1034     vmi->col = x;
 1035     vmi->row = y;
 1036     /*debug("%d %d %d", vmi->buf_length, vmi->full_length, vmi->partial_length);*/
 1037     for (xfont = 9; xfont >= 8; xfont--)
 1038         for (yfont = 16; yfont >= 8; yfont--) {
 1039             vmi->hres = x * xfont;
 1040             vmi->vres = y * yfont;
 1041             if (vmi->vres <= 400) vmi->vres = 400;
 1042             else if (vmi->vres <= 480) vmi->vres = 480;
 1043             vmi->buf_length = vmi->full_length = vmi->partial_length = x * ((vmi->vres + yfont - 1) / yfont) * 2;
 1044             vmi->full_length = (vmi->full_length + 4095) & ~4095;
 1045             vmi->partial_length = (vmi->partial_length + 4095) & ~4095;
 1046             if (!VioSetMode(vmi, 0)) return 0;
 1047         }
 1048     return -1;
 1049 }
 1050 
 1051 #endif
 1052 
 1053 /* Threads */
 1054 
 1055 #if defined(HAVE_BEGINTHREAD) || defined(BEOS) || defined(HAVE_PTHREADS)
 1056 
 1057 struct tdata {
 1058     void (*fn)(void *, int);
 1059     int h;
 1060     unsigned char data[1];
 1061 };
 1062 
 1063 void bgt(struct tdata *t)
 1064 {
 1065     signal(SIGPIPE, SIG_IGN);
 1066     t->fn(t->data, t->h);
 1067     write(t->h, "x", 1);
 1068     close(t->h);
 1069     free(t);
 1070 }
 1071 
 1072 #ifdef HAVE_PTHREADS
 1073 void *bgpt(struct tdata *t)
 1074 {
 1075     bgt(t);
 1076     return NULL;
 1077 }
 1078 #endif
 1079 
 1080 #endif
 1081 
 1082 #if defined(UNIX) || defined(OS2) || defined(WIN32) || defined(INTERIX) || defined(RISCOS) || defined(ATHEOS) || defined(SPAD)
 1083 
 1084 void terminate_osdep() {}
 1085 
 1086 #endif
 1087 
 1088 #ifndef BEOS
 1089 
 1090 void block_stdin() {}
 1091 void unblock_stdin() {}
 1092 
 1093 #endif
 1094 
 1095 #if defined(BEOS)
 1096 
 1097 #include <be/kernel/OS.h>
 1098 
 1099 int thr_sem_init = 0;
 1100 sem_id thr_sem;
 1101 
 1102 struct list_head active_threads = { &active_threads, &active_threads };
 1103 
 1104 struct active_thread {
 1105     struct active_thread *next;
 1106     struct active_thread *prev;
 1107     thread_id tid;
 1108     void (*fn)(void *);
 1109     void *data;
 1110 };
 1111 
 1112 int32 started_thr(void *data)
 1113 {
 1114     struct active_thread *thrd = data;
 1115     thrd->fn(thrd->data);
 1116     if (acquire_sem(thr_sem) < B_NO_ERROR) return 0;
 1117     del_from_list(thrd);
 1118     free(thrd);
 1119     release_sem(thr_sem);
 1120     return 0;
 1121 }
 1122 
 1123 int start_thr(void (*fn)(void *), void *data, unsigned char *name)
 1124 {
 1125     struct active_thread *thrd;
 1126     int tid;
 1127     if (!thr_sem_init) {
 1128         if ((thr_sem = create_sem(0, "thread_sem")) < B_NO_ERROR) return -1;
 1129         thr_sem_init = 1;
 1130     } else if (acquire_sem(thr_sem) < B_NO_ERROR) return -1;
 1131     if (!(thrd = malloc(sizeof(struct active_thread)))) goto rel;
 1132     thrd->fn = fn;
 1133     thrd->data = data;
 1134     if ((tid = thrd->tid = spawn_thread(started_thr, name, B_NORMAL_PRIORITY, thrd)) < B_NO_ERROR) {
 1135         free(thrd);
 1136         rel:
 1137         release_sem(thr_sem);
 1138         return -1;
 1139     }
 1140     resume_thread(thrd->tid);
 1141     add_to_list(active_threads, thrd);
 1142     release_sem(thr_sem);
 1143     return tid;
 1144 }
 1145 
 1146 void terminate_osdep()
 1147 {
 1148     struct list_head *p;
 1149     struct active_thread *thrd;
 1150     if (acquire_sem(thr_sem) < B_NO_ERROR) return;
 1151     foreach(thrd, active_threads) kill_thread(thrd->tid);
 1152     while ((p = active_threads.next) != &active_threads) {
 1153         del_from_list(p);
 1154         free(p);
 1155     }
 1156     release_sem(thr_sem);
 1157 }
 1158 
 1159 int start_thread(void (*fn)(void *, int), void *ptr, int l)
 1160 {
 1161     int p[2];
 1162     struct tdata *t;
 1163     if (c_pipe(p) < 0) return -1;
 1164     if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
 1165     t->fn = fn;
 1166     t->h = p[1];
 1167     memcpy(t->data, ptr, l);
 1168     if (start_thr((void (*)(void *))bgt, t, "links_thread") < 0) {
 1169         close(p[0]);
 1170         close(p[1]);
 1171         free(t);
 1172         return -1;
 1173     }
 1174     return p[0];
 1175 }
 1176 
 1177 
 1178 #elif defined(HAVE_BEGINTHREAD)
 1179 
 1180 int start_thread(void (*fn)(void *, int), void *ptr, int l)
 1181 {
 1182     int p[2];
 1183     struct tdata *t;
 1184     if (c_pipe(p) < 0) return -1;
 1185     fcntl(p[0], F_SETFL, O_NONBLOCK);
 1186     fcntl(p[1], F_SETFL, O_NONBLOCK);
 1187     if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
 1188     t->fn = fn;
 1189     t->h = p[1];
 1190     memcpy(t->data, ptr, l);
 1191     if (_beginthread((void (*)(void *))bgt, NULL, 65536, t) == -1) {
 1192         close(p[0]);
 1193         close(p[1]);
 1194         free(t);
 1195         return -1;
 1196     }
 1197     return p[0];
 1198 }
 1199 
 1200 #ifdef HAVE__READ_KBD
 1201 
 1202 int tp = -1;
 1203 int ti = -1;
 1204 
 1205 void input_thread(void *p)
 1206 {
 1207     char c[2];
 1208     int h = (int)p;
 1209     signal(SIGPIPE, SIG_IGN);
 1210     while (1) {
 1211         /*c[0] = _read_kbd(0, 1, 1);
 1212         if (c[0]) if (write(h, c, 1) <= 0) break;
 1213         else {
 1214             int w;
 1215             printf("1");fflush(stdout);
 1216             c[1] = _read_kbd(0, 1, 1);
 1217             printf("2");fflush(stdout);
 1218             w = write(h, c, 2);
 1219             printf("3");fflush(stdout);
 1220             if (w <= 0) break;
 1221             if (w == 1) if (write(h, c+1, 1) <= 0) break;
 1222             printf("4");fflush(stdout);
 1223         }*/
 1224            /* for the records: 
 1225                  _read_kbd(0, 1, 1) will
 1226                  read a char, don't echo it, wait for one available and
 1227                  accept CTRL-C.
 1228                  Knowing that, I suggest we replace this call completly!
 1229             */
 1230                 *c = _read_kbd(0, 1, 1);
 1231                 write(h, c, 1);
 1232     }
 1233     close(h);
 1234 }
 1235 #endif /* #ifdef HAVE__READ_KBD */
 1236 
 1237 #if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
 1238 
 1239 #define USING_OS2_MOUSE
 1240 
 1241 #ifdef HAVE_SYS_FMUTEX_H
 1242 _fmutex mouse_mutex;
 1243 int mouse_mutex_init = 0;
 1244 #endif
 1245 int mouse_h = -1;
 1246 
 1247 struct os2_mouse_spec {
 1248     int p[2];
 1249     void (*fn)(void *, unsigned char *, int);
 1250     void *data;
 1251     unsigned char buffer[sizeof(struct event)];
 1252     int bufptr;
 1253     int terminate;
 1254 };
 1255 
 1256 void mouse_thread(void *p)
 1257 {
 1258     int status;
 1259     struct os2_mouse_spec *oms = p;
 1260     A_DECL(HMOU, mh);
 1261     A_DECL(MOUEVENTINFO, ms);
 1262     A_DECL(USHORT, rd);
 1263     A_DECL(USHORT, mask);
 1264     struct event ev;
 1265     signal(SIGPIPE, SIG_IGN);
 1266     ev.ev = EV_MOUSE;
 1267     if (MouOpen(NULL, mh)) goto ret;
 1268     mouse_h = *mh;
 1269     *mask = MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_BN1_DOWN |
 1270         MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_BN2_DOWN |
 1271         MOUSE_MOTION_WITH_BN3_DOWN | MOUSE_BN3_DOWN |
 1272         MOUSE_MOTION;
 1273     MouSetEventMask(mask, *mh);
 1274     *rd = MOU_WAIT;
 1275     status = -1;
 1276     while (1) {
 1277         if (MouReadEventQue(ms, rd, *mh)) break;
 1278 #ifdef HAVE_SYS_FMUTEX_H
 1279         _fmutex_request(&mouse_mutex, _FMR_IGNINT);
 1280 #endif
 1281         if (!oms->terminate) MouDrawPtr(*mh);
 1282 #ifdef HAVE_SYS_FMUTEX_H
 1283         _fmutex_release(&mouse_mutex);
 1284 #endif
 1285         ev.x = ms->col;
 1286         ev.y = ms->row;
 1287         /*debug("status: %d %d %d", ms->col, ms->row, ms->fs);*/
 1288         if (ms->fs & (MOUSE_BN1_DOWN | MOUSE_BN2_DOWN | MOUSE_BN3_DOWN)) ev.b = status = B_DOWN | (ms->fs & MOUSE_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_BN2_DOWN ? B_MIDDLE : B_RIGHT);
 1289         else if (ms->fs & (MOUSE_MOTION_WITH_BN1_DOWN | MOUSE_MOTION_WITH_BN2_DOWN | MOUSE_MOTION_WITH_BN3_DOWN)) {
 1290             int b = ms->fs & MOUSE_MOTION_WITH_BN1_DOWN ? B_LEFT : ms->fs & MOUSE_MOTION_WITH_BN2_DOWN ? B_MIDDLE : B_RIGHT;
 1291             if (status == -1) b |= B_DOWN;
 1292             else b |= B_DRAG;
 1293             ev.b = status = b;
 1294         }
 1295         else {
 1296             if (status == -1) continue;
 1297             ev.b = (status & BM_BUTT) | B_UP;
 1298             status = -1;
 1299         }
 1300         if (hard_write(oms->p[1], (unsigned char *)&ev, sizeof(struct event)) != sizeof(struct event)) break;
 1301     }
 1302 #ifdef HAVE_SYS_FMUTEX_H
 1303     _fmutex_request(&mouse_mutex, _FMR_IGNINT);
 1304 #endif
 1305     mouse_h = -1;
 1306     MouClose(*mh);
 1307 #ifdef HAVE_SYS_FMUTEX_H
 1308     _fmutex_release(&mouse_mutex);
 1309 #endif
 1310     ret:
 1311     close(oms->p[1]);
 1312     /*free(oms);*/
 1313 }
 1314 
 1315 void mouse_handle(struct os2_mouse_spec *oms)
 1316 {
 1317     int r;
 1318     if ((r = read(oms->p[0], oms->buffer + oms->bufptr, sizeof(struct event) - oms->bufptr)) <= 0) {
 1319         unhandle_mouse(oms);
 1320         return;
 1321     }
 1322     if ((oms->bufptr += r) == sizeof(struct event)) {
 1323         oms->bufptr = 0;
 1324         oms->fn(oms->data, oms->buffer, sizeof(struct event));
 1325     }
 1326 }
 1327 
 1328 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
 1329 {
 1330     struct os2_mouse_spec *oms;
 1331     if (is_xterm()) return NULL;
 1332 #ifdef HAVE_SYS_FMUTEX_H
 1333     if (!mouse_mutex_init) {
 1334         if (_fmutex_create(&mouse_mutex, 0)) return NULL;
 1335         mouse_mutex_init = 1;
 1336     }
 1337 #endif
 1338         /* This is never freed but it's allocated only once */
 1339     if (!(oms = malloc(sizeof(struct os2_mouse_spec)))) return NULL;
 1340     oms->fn = fn;
 1341     oms->data = data;
 1342     oms->bufptr = 0;
 1343     oms->terminate = 0;
 1344     if (c_pipe(oms->p)) {
 1345         free(oms);
 1346         return NULL;
 1347     }
 1348     _beginthread(mouse_thread, NULL, 0x10000, (void *)oms);
 1349     set_handlers(oms->p[0], (void (*)(void *))mouse_handle, NULL, NULL, oms);
 1350     return oms;
 1351 }
 1352 
 1353 void unhandle_mouse(void *om)
 1354 {
 1355     struct os2_mouse_spec *oms = om;
 1356     want_draw();
 1357     oms->terminate = 1;
 1358     set_handlers(oms->p[0], NULL, NULL, NULL, NULL);
 1359     close(oms->p[0]);
 1360     done_draw();
 1361 }
 1362 
 1363 void want_draw()
 1364 {
 1365     A_DECL(NOPTRRECT, pa);
 1366 #ifdef HAVE_SYS_FMUTEX_H
 1367     if (mouse_mutex_init) _fmutex_request(&mouse_mutex, _FMR_IGNINT);
 1368 #endif
 1369     if (mouse_h != -1) {
 1370         static int x = -1, y = -1;
 1371         static tcount c = -1;
 1372         if (x == -1 || y == -1 || (c != resize_count)) get_terminal_size(1, &x, &y), c = resize_count;
 1373         pa->row = 0;
 1374         pa->col = 0;
 1375         pa->cRow = y - 1;
 1376         pa->cCol = x - 1;
 1377         MouRemovePtr(pa, mouse_h);
 1378     }
 1379 }
 1380 
 1381 void done_draw()
 1382 {
 1383 #ifdef HAVE_SYS_FMUTEX_H
 1384     if (mouse_mutex_init) _fmutex_release(&mouse_mutex);
 1385 #endif
 1386 }
 1387 
 1388 #endif /* if HAVE_MOUOPEN */
 1389 
 1390 #elif defined(HAVE_PTHREADS)
 1391 
 1392 #include <pthread.h>
 1393 
 1394 int start_thread(void (*fn)(void *, int), void *ptr, int l)
 1395 {
 1396     pthread_t thread;
 1397     struct tdata *t;
 1398     int p[2];
 1399     if (c_pipe(p) < 0) return -1;
 1400     fcntl(p[0], F_SETFL, O_NONBLOCK);
 1401     fcntl(p[1], F_SETFL, O_NONBLOCK);
 1402     if (!(t = malloc(sizeof(struct tdata) + l))) return -1;
 1403     t->fn = fn;
 1404     t->h = p[1];
 1405     memcpy(t->data, ptr, l);
 1406     if (pthread_create(&thread, NULL, (void *(*)(void *))bgpt, t)) {
 1407         close(p[0]);
 1408         close(p[1]);
 1409         free(t);
 1410         return -1;
 1411     }
 1412     return p[0];
 1413 }
 1414 
 1415 #else /* HAVE_BEGINTHREAD */
 1416 
 1417 int start_thread(void (*fn)(void *, int), void *ptr, int l)
 1418 {
 1419     int p[2];
 1420     pid_t f;
 1421     if (c_pipe(p) < 0) return -1;
 1422     fcntl(p[0], F_SETFL, O_NONBLOCK);
 1423     fcntl(p[1], F_SETFL, O_NONBLOCK);
 1424     if (!(f = fork())) {
 1425         close_fork_tty();
 1426         close(p[0]);
 1427         fn(ptr, p[1]);
 1428         write(p[1], "x", 1);
 1429         close(p[1]);
 1430         _exit(0);
 1431     }
 1432     if (f == -1) {
 1433         close(p[0]);
 1434         close(p[1]);
 1435         return -1;
 1436     }
 1437     close(p[1]);
 1438     return p[0];
 1439 }
 1440 
 1441 #endif
 1442 
 1443 #ifndef USING_OS2_MOUSE
 1444 void want_draw() {}
 1445 void done_draw() {}
 1446 #endif
 1447 
 1448 int get_output_handle() { return 1; }
 1449 
 1450 #if defined(OS2)
 1451 
 1452 int get_ctl_handle() { return get_input_handle(); }
 1453 
 1454 #else
 1455 
 1456 int get_ctl_handle() { return 0; }
 1457 
 1458 #endif
 1459 
 1460 #if defined(BEOS)
 1461 
 1462 #elif defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD)
 1463 int get_input_handle()
 1464 {
 1465     int fd[2];
 1466     if (ti != -1) return ti;
 1467     if (is_xterm()) return 0;
 1468     if (c_pipe(fd) < 0) return 0;
 1469     ti = fd[0];
 1470     tp = fd[1];
 1471     _beginthread(input_thread, NULL, 0x10000, (void *)tp);
 1472 /*
 1473 #if defined(HAVE_MOUOPEN) && !defined(USE_GPM)
 1474     _beginthread(mouse_thread, NULL, 0x10000, (void *)tp);
 1475 #endif
 1476 */
 1477     return fd[0];
 1478 }
 1479 
 1480 #else
 1481 
 1482 int get_input_handle()
 1483 {
 1484     return 0;
 1485 }
 1486 
 1487 #endif /* defined(HAVE_BEGINTHREAD) && defined(HAVE__READ_KBD) */
 1488 
 1489 
 1490 void os_cfmakeraw(struct termios *t)
 1491 {
 1492 #ifdef HAVE_CFMAKERAW
 1493     cfmakeraw(t);
 1494 #ifdef VMIN
 1495     t->c_cc[VMIN] = 1;  /* cfmakeraw is broken on AIX */
 1496 #endif
 1497 #else
 1498     t->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
 1499     t->c_oflag &= ~OPOST;
 1500     t->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
 1501     t->c_cflag &= ~(CSIZE|PARENB);
 1502     t->c_cflag |= CS8;
 1503     t->c_cc[VMIN] = 1;
 1504     t->c_cc[VTIME] = 0;
 1505 #endif
 1506 #if defined(NO_CTRL_Z) && defined(VSUSP)
 1507     t->c_cc[VSUSP] = 0;
 1508 #endif
 1509 }
 1510 
 1511 #ifdef USE_GPM
 1512 
 1513 struct gpm_mouse_spec {
 1514     int h;
 1515     void (*fn)(void *, unsigned char *, int);
 1516     void *data;
 1517 };
 1518 
 1519 /* GPM installs its own signal handlers and we don't want them */
 1520 
 1521 sigset_t gpm_sigset;
 1522 char gpm_sigset_valid;
 1523 #ifdef SIGWINCH
 1524 struct sigaction gpm_winch;
 1525 char gpm_winch_valid;
 1526 #endif
 1527 #ifdef SIGTSTP
 1528 struct sigaction gpm_tstp;
 1529 char gpm_tstp_valid;
 1530 #endif
 1531 
 1532 static void save_gpm_signals(void)
 1533 {
 1534     sigset_t sig;
 1535     sigemptyset(&sig);
 1536 #ifdef SIGWINCH
 1537     sigaddset(&sig, SIGWINCH);
 1538 #endif
 1539 #ifdef SIGTSTP
 1540     sigaddset(&sig, SIGTSTP);
 1541 #endif
 1542     gpm_sigset_valid = !sigprocmask(SIG_BLOCK, &sig, &gpm_sigset);
 1543 #ifdef SIGWINCH
 1544     gpm_winch_valid = !sigaction(SIGWINCH, NULL, &gpm_winch);
 1545 #endif
 1546 #ifdef SIGTSTP
 1547     gpm_tstp_valid = !sigaction(SIGTSTP, NULL, &gpm_tstp);
 1548 #endif
 1549 }
 1550 
 1551 static void restore_gpm_signals(void)
 1552 {
 1553 #ifdef SIGWINCH
 1554     if (gpm_winch_valid) sigaction(SIGWINCH, &gpm_winch, NULL);
 1555 #endif
 1556 #ifdef SIGTSTP
 1557     if (gpm_tstp_valid) sigaction(SIGTSTP, &gpm_tstp, NULL);
 1558 #endif
 1559     if (gpm_sigset_valid) sigprocmask(SIG_SETMASK, &gpm_sigset, NULL);
 1560 }
 1561 
 1562 void gpm_mouse_in(struct gpm_mouse_spec *gms)
 1563 {
 1564     int g;
 1565     Gpm_Event gev;
 1566     struct event ev;
 1567     save_gpm_signals();
 1568     g = Gpm_GetEvent(&gev);
 1569     restore_gpm_signals();
 1570     if (g <= 0) {
 1571         set_handlers(gms->h, NULL, NULL, NULL, NULL);
 1572         gms->h = -1;
 1573         return;
 1574     }
 1575     ev.ev = EV_MOUSE;
 1576     ev.x = gev.x - 1;
 1577     ev.y = gev.y - 1;
 1578     if (ev.x < 0) ev.x = 0;
 1579     if (ev.y < 0) ev.y = 0;
 1580     if (gev.buttons & GPM_B_LEFT) ev.b = B_LEFT;
 1581     else if (gev.buttons & GPM_B_MIDDLE) ev.b = B_MIDDLE;
 1582     else if (gev.buttons & GPM_B_RIGHT) ev.b = B_RIGHT;
 1583     else return;
 1584     if (gev.type & GPM_DOWN) ev.b |= B_DOWN;
 1585     else if (gev.type & GPM_UP) ev.b |= B_UP;
 1586     else if (gev.type & GPM_DRAG) ev.b |= B_DRAG;
 1587     else return;
 1588     gms->fn(gms->data, (char *)&ev, sizeof(struct event));
 1589 }
 1590 
 1591 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data)
 1592 {
 1593     int h;
 1594     Gpm_Connect conn;
 1595     struct gpm_mouse_spec *gms;
 1596     conn.eventMask = ~GPM_MOVE;
 1597     conn.defaultMask = GPM_MOVE;
 1598     conn.minMod = 0;
 1599     conn.maxMod = 0;
 1600     save_gpm_signals();
 1601     h = Gpm_Open(&conn, cons);
 1602     restore_gpm_signals();
 1603     if (h < 0) return NULL;
 1604     gms = mem_alloc(sizeof(struct gpm_mouse_spec));
 1605     gms->h = h;
 1606     gms->fn = fn;
 1607     gms->data = data;
 1608     set_handlers(h, (void (*)(void *))gpm_mouse_in, NULL, NULL, gms);
 1609     return gms;
 1610 }
 1611 
 1612 void unhandle_mouse(void *h)
 1613 {
 1614     struct gpm_mouse_spec *gms = h;
 1615     if (gms->h != -1) set_handlers(gms->h, NULL, NULL, NULL, NULL);
 1616     save_gpm_signals();
 1617     Gpm_Close();
 1618     restore_gpm_signals();
 1619     mem_free(gms);
 1620 }
 1621 
 1622 #elif !defined(USING_OS2_MOUSE)
 1623 
 1624 void *handle_mouse(int cons, void (*fn)(void *, unsigned char *, int), void *data) { return NULL; }
 1625 void unhandle_mouse(void *data) { }
 1626 
 1627 #endif /* #ifdef USE_GPM */
 1628 
 1629 #if defined(WIN32) || defined(INTERIX)
 1630 
 1631 static int is_remote_connection(void)
 1632 {
 1633     return !!getenv("SSH_CONNECTION");
 1634 }
 1635 
 1636 #endif
 1637 
 1638 #if defined(OS2)
 1639 
 1640 int get_system_env()
 1641 {
 1642     if (is_xterm()) return 0;
 1643     return ENV_OS2VIO;      /* !!! FIXME: telnet */
 1644 }
 1645 
 1646 #elif defined(BEOS)
 1647 
 1648 int get_system_env()
 1649 {
 1650     unsigned char *term = getenv("TERM");
 1651     if (!term || (upcase(term[0]) == 'B' && upcase(term[1]) == 'E')) return ENV_BE;
 1652     return 0;
 1653 }
 1654 
 1655 #elif defined(WIN32)
 1656 
 1657 int get_system_env()
 1658 {
 1659     if (is_xterm()) return 0;
 1660     if (is_remote_connection()) return 0;
 1661     return ENV_WIN32;
 1662 }
 1663 
 1664 #elif defined(INTERIX)
 1665 
 1666 #define INTERIX_START_COMMAND   "/usr/contrib/win32/bin/start"
 1667 
 1668 int get_system_env(void)
 1669 {
 1670     if (is_xterm()) return 0;
 1671     if (is_remote_connection()) return 0;
 1672     if (!access(INTERIX_START_COMMAND, X_OK)) return ENV_INTERIX;
 1673     return 0;
 1674 }
 1675 
 1676 #else
 1677 
 1678 int get_system_env()
 1679 {
 1680     return 0;
 1681 }
 1682 
 1683 #endif
 1684 
 1685 void exec_new_links(struct terminal *term, unsigned char *xterm, unsigned char *exe, unsigned char *param)
 1686 {
 1687     unsigned char *str;
 1688     str = mem_alloc(strlen(xterm) + 1 + strlen(exe) + 1 + strlen(param) + 1);
 1689     if (*xterm) sprintf(str, "%s %s %s", xterm, exe, param);
 1690     else sprintf(str, "%s %s", exe, param);
 1691     exec_on_terminal(term, str, "", 2);
 1692     mem_free(str);
 1693 }
 1694 
 1695 void open_in_new_twterm(struct terminal *term, unsigned char *exe, unsigned char *param)
 1696 {
 1697     unsigned char *twterm;
 1698     if (!(twterm = getenv("LINKS_TWTERM"))) twterm = "twterm -e";
 1699     exec_new_links(term, twterm, exe, param);
 1700 }
 1701 
 1702 void open_in_new_xterm(struct terminal *term, unsigned char *exe, unsigned char *param)
 1703 {
 1704     unsigned char *xterm;
 1705     if (!(xterm = getenv("LINKS_XTERM"))) xterm = "xterm -e";
 1706     exec_new_links(term, xterm, exe, param);
 1707 }
 1708 
 1709 void open_in_new_screen(struct terminal *term, unsigned char *exe, unsigned char *param)
 1710 {
 1711     exec_new_links(term, "screen", exe, param);
 1712 }
 1713 
 1714 #ifdef OS2
 1715 void open_in_new_vio(struct terminal *term, unsigned char *exe, unsigned char *param)
 1716 {
 1717     unsigned char *x = stracpy("\"");
 1718     add_to_strn(&x, exe);
 1719     add_to_strn(&x, "\"");
 1720     exec_new_links(term, "start \"Links\" /c /f /win", x, param);
 1721     mem_free(x);
 1722 }
 1723 
 1724 void open_in_new_fullscreen(struct terminal *term, unsigned char *exe, unsigned char *param)
 1725 {
 1726     unsigned char *x = stracpy("\"");
 1727     add_to_strn(&x, exe);
 1728     add_to_strn(&x, "\"");
 1729     exec_new_links(term, "start \"Links\" /c /f /fs", x, param);
 1730     mem_free(x);
 1731 }
 1732 #endif
 1733 
 1734 #ifdef WIN32
 1735 void open_in_new_win32(struct terminal *term, unsigned char *exe, unsigned char *param)
 1736 {
 1737     exec_new_links(term, "", exe, param);
 1738 }
 1739 #endif
 1740 
 1741 #ifdef INTERIX
 1742 static void open_in_new_interix(struct terminal *term, unsigned char *exe, unsigned char *param)
 1743 {
 1744     unsigned char *param_x = stracpy(param);
 1745     add_to_strn(&param_x, "'");
 1746     exec_new_links(term, INTERIX_START_COMMAND " '\"Links\"' posix /u /c /bin/sh -c '", exe, param_x);
 1747     mem_free(param_x);
 1748 }
 1749 #endif
 1750 
 1751 #ifdef BEOS
 1752 void open_in_new_be(struct terminal *term, unsigned char *exe, unsigned char *param)
 1753 {
 1754     exec_new_links(term, "Terminal", exe, param);
 1755 }
 1756 #endif
 1757 
 1758 struct {
 1759     int env;
 1760     void (*fn)(struct terminal *term, unsigned char *, unsigned char *);
 1761     unsigned char *text;
 1762     unsigned char *hk;
 1763 } oinw[] = {
 1764     { ENV_XWIN, open_in_new_xterm, TEXT_(T_XTERM), TEXT_(T_HK_XTERM) },
 1765     { ENV_TWIN, open_in_new_twterm, TEXT_(T_TWTERM), TEXT_(T_HK_TWTERM) },
 1766     { ENV_SCREEN, open_in_new_screen, TEXT_(T_SCREEN), TEXT_(T_HK_SCREEN) },
 1767 #ifdef OS2
 1768     { ENV_OS2VIO, open_in_new_vio, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW) },
 1769     { ENV_OS2VIO, open_in_new_fullscreen, TEXT_(T_FULL_SCREEN), TEXT_(T_HK_FULL_SCREEN) },
 1770 #endif
 1771 #ifdef WIN32
 1772     { ENV_WIN32, open_in_new_win32, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW) },
 1773 #endif
 1774 #ifdef INTERIX
 1775     {ENV_INTERIX, open_in_new_interix, TEXT_(T_WINDOW), TEXT_(T_HK_WINDOW)},
 1776 #endif
 1777 #ifdef BEOS
 1778     { ENV_BE, open_in_new_be, TEXT_(T_BEOS_TERMINAL), TEXT_(T_HK_BEOS_TERMINAL) },
 1779 #endif
 1780     { 0, NULL, NULL, NULL },
 1781 };
 1782 
 1783 struct open_in_new *get_open_in_new(int environment)
 1784 {
 1785     int i;
 1786     struct open_in_new *oin = DUMMY;
 1787     int noin = 0;
 1788     if (anonymous) return NULL;
 1789     for (i = 0; oinw[i].env; i++) if ((environment & oinw[i].env) == oinw[i].env) {
 1790         if ((unsigned)noin > MAXINT / sizeof(struct open_in_new) - 2) overalloc();
 1791         oin = mem_realloc(oin, (noin + 2) * sizeof(struct open_in_new));
 1792         oin[noin].text = oinw[i].text;
 1793         oin[noin].hk = oinw[i].hk;
 1794         oin[noin].fn = oinw[i].fn;
 1795         noin++;
 1796         oin[noin].text = NULL;
 1797         oin[noin].hk = NULL;
 1798         oin[noin].fn = NULL;
 1799     }
 1800     if (oin == DUMMY) return NULL;
 1801     return oin;
 1802 }
 1803 
 1804 int can_resize_window(int environment)
 1805 {
 1806     if (environment & (ENV_OS2VIO | ENV_WIN32)) return 1;
 1807     return 0;
 1808 }
 1809 
 1810 int can_open_os_shell(int environment)
 1811 {
 1812 #ifdef OS2
 1813     if (environment & ENV_XWIN) return 0;
 1814 #endif
 1815 #ifdef WIN32
 1816     if (!(environment & ENV_WIN32)) return 0;
 1817 #endif
 1818 #ifdef BEOS
 1819     if (!(environment & ENV_BE)) return 0;
 1820 #endif
 1821     return 1;
 1822 }
 1823 
 1824 #ifndef OS2
 1825 void set_highpri()
 1826 {
 1827 }
 1828 #else
 1829 void set_highpri()
 1830 {
 1831     DosSetPriority(PRTYS_PROCESS, PRTYC_FOREGROUNDSERVER, 0, 0);
 1832 }
 1833 #endif
 1834 
 1835 #ifndef HAVE_MEMMOVE
 1836 void *memmove(void *dst0, const void *src0, size_t length)
 1837 {
 1838     unsigned char *dst = dst0;
 1839     const unsigned char *src = src0;
 1840 
 1841     if ((const unsigned char *)dst == src || !length)
 1842         return dst0;
 1843 
 1844     if ((const unsigned char *)dst <= src) {
 1845         while (length--) *dst++ = *src++;
 1846     } else {
 1847         dst += length - 1;
 1848         src += length - 1;
 1849         while (length--) *dst-- = *src--;
 1850     }
 1851     return dst0;
 1852 }
 1853 #endif
 1854 
 1855 #ifndef HAVE_RAISE
 1856 int raise(int s)
 1857 {
 1858 #ifdef HAVE_GETPID
 1859     return kill(getpid(), s);
 1860 #else
 1861     return 0;
 1862 #endif
 1863 };
 1864 #endif
 1865 #ifndef HAVE_STRTOUL
 1866 unsigned long strtoul(const char *nptr, char **endptr, int base)
 1867 {
 1868     if (*nptr == '-') {
 1869         if (endptr) *endptr = nptr;
 1870         return 0;
 1871     }
 1872     return (unsigned long)strtol(nptr,endptr,base);
 1873 };
 1874 #endif
 1875 #ifndef HAVE_STRERROR
 1876 extern char *sys_errlist[];
 1877 extern int sys_nerr;
 1878 char *strerror(int errnum)
 1879 {
 1880     if (errnum < 0 || errnum >= sys_nerr) return "Unknown error";
 1881     return sys_errlist[errnum];
 1882 };
 1883 #endif
 1884 #ifndef HAVE_GETTIMEOFDAY
 1885 int gettimeofday(struct timeval *tv, struct timezone *tz)
 1886 {
 1887     if (tv) tv->tv_sec = time(NULL), tv->tv_usec = 0;
 1888     if (tz) tz->tz_minuteswest = tz->tz_dsttime = 0;
 1889     return 0;
 1890 }
 1891 #endif
 1892 #ifndef HAVE_STRLEN
 1893 size_t strlen(const char *s)
 1894 {
 1895     size_t len = 0;
 1896     while (s[len]) len++;
 1897     return len;
 1898 }
 1899 #endif
 1900 #ifndef HAVE_STRCPY
 1901 char *strcpy(char *dst, const char *src)
 1902 {
 1903     return memcpy(dst, src, strlen(src) + 1);
 1904 }
 1905 #endif
 1906 #ifndef HAVE_STRCHR
 1907 char *strchr(const char *s, int c)
 1908 {
 1909     do {
 1910         if (*s == (char)c)
 1911             return (char *)s;
 1912     } while (*s++);
 1913     return NULL;
 1914 }
 1915 #endif
 1916 #ifndef HAVE_STRRCHR
 1917 char *strrchr(const char *s, int c)
 1918 {
 1919     char *ret = NULL;
 1920     do {
 1921         if (*s == (char)c)
 1922             ret = (char *)s;
 1923     } while (*s++);
 1924     return ret;
 1925 }
 1926 #endif
 1927 #ifndef HAVE_STRCMP
 1928 int strcmp(const char *s1, const char *s2)
 1929 {
 1930     while (1) {
 1931         if (*s1 != *s2) {
 1932             return (int)(unsigned char)*s1 - (int)(unsigned char)*s2;
 1933         }
 1934         if (!*s1) break;
 1935         s1++, s2++;
 1936     }
 1937     return 0;
 1938 }
 1939 #endif
 1940 #ifndef HAVE_STRNCMP
 1941 int strncmp(const char *s1, const char *s2, size_t n)
 1942 {
 1943     while (n--) {
 1944         if (*s1 != *s2) {
 1945             return (int)(unsigned char)*s1 - (int)(unsigned char)*s2;
 1946         }
 1947         if (!*s1) break;
 1948         s1++, s2++;
 1949     }
 1950     return 0;
 1951 }
 1952 #endif
 1953 #ifndef HAVE_STRCSPN
 1954 size_t strcspn(const char *s, const char *reject)
 1955 {
 1956     size_t r;
 1957     for (r = 0; *s; r++, s++) {
 1958         const char *rj;
 1959         for (rj = reject; *rj; rj++) if (*s == *rj) goto brk;
 1960     }
 1961     brk:
 1962     return r;
 1963 }
 1964 #endif
 1965 #ifndef HAVE_STRSTR
 1966 char *strstr(const char *haystack, const char *needle)
 1967 {
 1968     size_t hs = strlen(haystack);
 1969     size_t ns = strlen(needle);
 1970     while (hs >= ns) {
 1971         if (!memcmp(haystack, needle, ns)) return (char *)haystack;
 1972         haystack++, hs--;
 1973     }
 1974     return NULL;
 1975 }
 1976 #endif
 1977 #ifndef HAVE_TEMPNAM
 1978 char *tempnam(const char *dir, const char *pfx)
 1979 {
 1980     static int counter = 0;
 1981     unsigned char *d, *s, *a;
 1982     int l;
 1983     if (!(d = getenv("TMPDIR"))) {
 1984         if (dir) d = (unsigned char *)dir;
 1985         else if (!(d = getenv("TMP")) && !(d = getenv("TEMP"))) {
 1986 #ifdef P_tmpdir
 1987             d = P_tmpdir;
 1988 #else
 1989             d = "/tmp";
 1990 #endif
 1991         }
 1992     }
 1993     l = 0;
 1994     s = init_str();
 1995     add_to_str(&s, &l, d);
 1996     if (s[0] && s[strlen(s) - 1] != '/') add_chr_to_str(&s, &l, '/');
 1997     add_to_str(&s, &l, (unsigned char *)pfx);
 1998     add_num_to_str(&s, &l, counter++);
 1999     a = strdup(s);
 2000     mem_free(s);
 2001     return a;
 2002 }
 2003 #endif