Back to index

tetex-bin  3.0
Defines | Functions | Variables
util.c File Reference
#include "xdvi-config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include "xdvi.h"
#include "hypertex.h"
#include "dvi-init.h"
#include "special.h"
#include "string-utils.h"
#include "kpathsea/tex-file.h"
#include "events.h"
#include "util.h"
#include "x_util.h"
#include "message-window.h"
#include "search-internal.h"
#include "encodings.h"
#include "filehist.h"
#include "xm_prefs.h"
#include <errno.h>
#include <ctype.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <pwd.h>
#include <locale.h>

Go to the source code of this file.

Defines

#define FLAKY_SIGPOLL   1
#define MAXSYMLINKS   5
#define BUF_SIZE   1024
#define P_tmpdir   "/tmp"
#define TMP_BUF_SIZE   4 * 1024

Functions

struct dl_listdl_list_insert (struct dl_list *list, void *item)
struct dl_listdl_list_head (struct dl_list *list)
struct dl_listdl_list_push_front (struct dl_list *list, void *item)
struct dl_listdl_list_truncate (struct dl_list *list)
struct dl_listdl_list_truncate_head (struct dl_list *list)
Boolean dl_list_remove_item (struct dl_list **list)
struct dl_listdl_list_remove (struct dl_list *list, const void *item, int *count, void **removed_item, Boolean(*compare_func)(const void *item1, const void *item2))
FILEtry_fopen (const char *fname, const char *mode)
FILEtry_fdopen (int fd, const char *mode)
int try_open (const char *fname, int flags)
int try_open_mode (const char *fname, int flags, mode_t mode)
void xdvi_exit (int status)
void do_abort ()
char * expand_homedir (const char *path)
char * my_realpath (const char *path, char *resolved)
voidxmalloc (unsigned size)
voidxrealloc (void *where, unsigned size)
char * xstrdup (const char *str)
char * xmemdup (const char *str, size_t len)
char * xstrcat (char *str1, const char *str2)
void alloc_bitmap (struct bitmap *bitmap)
int memicmp (const char *s1, const char *s2, size_t n)
void close_a_file (void)
FILEXFOPEN (const char *path, const char *mode)
int xpipe (int *fd)
unsigned long get_bytes (FILE *fp, int size)
long get_lbytes (FILE *fp, int size)
int xdvi_temp_fd (char **str)
void handle_child_exit (int status, struct xchild *this)
static void dummy_write_proc (int fd)
char * read_child_error (int fd)
Boolean fork_process (const char *proc_name, Boolean redirect_stdout, const char *dirname, childProcT exit_proc, void *data, char *const argv[])
void prep_fd (int fd, wide_bool noblock)
Boolean pointerlocate (int *xpos, int *ypos)
unsigned long parse_debugging_string (const char *arg)
unsigned long parse_debugging_option (const char *ptr)
int get_avg_font_width (XFontStruct *font)
char ** split_line (const char *line, char sep, size_t begin, size_t end, size_t *ret_items)
char * find_file (const char *filename, struct stat *statbuf, kpse_file_format_type pathinfo)
Boolean find_str_int_hash (hashTableT *hashtable, const char *key, size_t *val)
void put_str_int_hash (hashTableT *hashtable, const char *key, size_t val)
void set_dvi_name_expand (const char *new_filename)
void set_dvi_name (char *new_filename)
Boolean copy_fp (FILE *in, FILE *out)
Boolean copy_file (const char *from_path, const char *to_path)
const char * get_text_encoding (void)
char * iconv_convert_string (const char *from_enc, const char *to_enc, const char *str)

Variables

static const char tmp_suffix [] = "/xdvi-XXXXXX"

Define Documentation

#define BUF_SIZE   1024

Definition at line 142 of file util.c.

#define FLAKY_SIGPOLL   1

Definition at line 98 of file util.c.

#define MAXSYMLINKS   5

Definition at line 129 of file util.c.

#define P_tmpdir   "/tmp"

Definition at line 939 of file util.c.

#define TMP_BUF_SIZE   4 * 1024

Function Documentation

void alloc_bitmap ( struct bitmap bitmap)

Definition at line 790 of file util.c.

{
    unsigned int size;

    /* fprintf(stderr, "allocating bitmap of size %u x %u\n", bitmap->w, bitmap->h); */
    /* width must be multiple of <arch-defined> bits for raster_op */
    bitmap->bytes_wide = ROUNDUP((int)bitmap->w, BMBITS) * BMBYTES;
    size = bitmap->bytes_wide * bitmap->h;
    bitmap->bits = xmalloc(size != 0 ? size : 1);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 828 of file util.c.

{
    struct font *fontp;
    unsigned short oldest = USHRT_MAX;
    struct font *f = NULL;

    if (globals.debug & DBG_OPEN)
       puts("Calling close_a_file().");

    for (fontp = font_head; fontp != NULL; fontp = fontp->next) {
       if (fontp->file != NULL && fontp->timestamp <= oldest) {
           f = fontp;
           oldest = fontp->timestamp;
       }
    }
    /* fprintf(stderr, "oldest = %u\n", oldest); */
    if (f == NULL)
       XDVI_FATAL((stderr, "Can't find an open pixel file to close"));
    fclose(f->file);
    f->file = NULL;
}

Here is the caller graph for this function:

Boolean copy_file ( const char *  from_path,
const char *  to_path 
)

Definition at line 1671 of file util.c.

                                                      {
    FILE *from_fp;
    FILE *to_fp;

    Boolean retval;

    if ((from_fp = try_fopen(from_path, "rb")) == NULL) {
       XDVI_ERROR((stderr, "opening %s for reading failed: %s", from_path, strerror(errno)));
       return False;
    }

    if ((to_fp = try_fopen(to_path, "wb")) == NULL) {
       XDVI_ERROR((stderr, "opening %s for writing failed: %s", to_path, strerror(errno)));
       return False;
    }

    retval = copy_fp(from_fp, to_fp);

    fclose(from_fp);
    fclose(to_fp);

    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean copy_fp ( FILE in,
FILE out 
)

Definition at line 1645 of file util.c.

{
#define TMP_BUF_SIZE 4 * 1024
    char buf[TMP_BUF_SIZE];
    
    while (feof(in) == 0) {
       size_t bytes_in, bytes_out;
       
       bytes_in = fread(buf, 1, TMP_BUF_SIZE, in);
       if (bytes_in < TMP_BUF_SIZE && !feof(in))
           return False;
       bytes_out = fwrite(buf, 1, bytes_in, out);
/*     fprintf(stderr, "read %d, wrote %d bytes\n", bytes_in, bytes_out); */
       if (bytes_out < bytes_in)
           return False;
    }
    return True;

#undef TMP_BUF_SIZE
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct dl_list* dl_list_head ( struct dl_list list) [read]

Definition at line 177 of file util.c.

{
    for (; list != NULL && list->prev != NULL; list = list->prev) { ; }
    return list;
}

Here is the caller graph for this function:

struct dl_list* dl_list_insert ( struct dl_list list,
void item 
) [read]

Definition at line 148 of file util.c.

{
    struct dl_list *new_elem = xmalloc(sizeof *new_elem);
    new_elem->item = item;
    new_elem->next = NULL;
    new_elem->prev = NULL;
    
    if (list == NULL) {
       list = new_elem;
    }
    else {
       /* append after current position */
       struct dl_list *ptr = list;
       
       new_elem->next = ptr->next;
       new_elem->prev = ptr;
       
       if (ptr->next != NULL)
           ptr->next->prev = new_elem;
       
       ptr->next = new_elem;
    }
    return new_elem;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct dl_list* dl_list_push_front ( struct dl_list list,
void item 
) [read]

Definition at line 188 of file util.c.

{
    struct dl_list *new_elem = xmalloc(sizeof *new_elem);
    new_elem->item = item;
    new_elem->next = NULL;
    new_elem->prev = NULL;
    
    if (list != NULL) { /* prepend to current position */
       new_elem->next = list;
       list->prev = new_elem;
    }
    return new_elem;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct dl_list* dl_list_remove ( struct dl_list list,
const void item,
int count,
void **  removed_item,
Boolean(*)(const void *item1, const void *item2)  compare_func 
) [read]

Definition at line 262 of file util.c.

{
    struct dl_list *ptr = list;
    while (ptr != NULL) {
       struct dl_list *next = ptr->next;
       if (compare_func(ptr->item, item)) { /* match */
           *removed_item = ptr->item;
           (*count)++;
           if (ptr->prev != NULL) {
              ptr->prev->next = ptr->next;
           }
           else { /* removed first element */
              list = list->next;
           }

           if (ptr->next != NULL)
              ptr->next->prev = ptr->prev;
           free(ptr);
           ptr = NULL;
       }
       ptr = next;
    }
    return list;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean dl_list_remove_item ( struct dl_list **  list)

Definition at line 240 of file util.c.

{
    struct dl_list *ptr = *list; /* item to remove */
    if (ptr->prev == NULL)
       return False;
    ptr->prev->next = ptr->next;
    if (ptr->next != NULL)
       ptr->next->prev = ptr->prev;
    /* update list */
    *list = (*list)->prev;
    /* remove item */
    free(ptr);
    
    return True;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct dl_list* dl_list_truncate ( struct dl_list list) [read]

Definition at line 206 of file util.c.

{
    struct dl_list *ptr = list->next;
    struct dl_list *save;

    list->next = NULL;
    
    while (ptr != NULL) {
       save = ptr->next;
       free(ptr);
       ptr = save;
    }
    return list;
}

Here is the call graph for this function:

Here is the caller graph for this function:

struct dl_list* dl_list_truncate_head ( struct dl_list list) [read]

Definition at line 226 of file util.c.

{
    struct dl_list *ptr = list->next;
    if (list->next != NULL)
       list->next->prev = NULL;
    free(list);
    return ptr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 435 of file util.c.

{
#if PS
    ps_destroy();
#endif
    /*     if (globals.widgets.top_level) */
    /*        exit_clean_windows(); */
    abort();
}

Here is the call graph for this function:

static void dummy_write_proc ( int  fd) [static]

Definition at line 1056 of file util.c.

{
    UNUSED(fd);
    fprintf(stderr, "============== dummy_write_proc called for fd %d\n", fd);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* expand_homedir ( const char *  path)

Definition at line 451 of file util.c.

{
    char *resolved = NULL;
    const char *orig_path = path;
    UNUSED(orig_path); /* if HAVE_GETPWNAM or HAVE_GETPWUID && HAVE_GETUID */

    if (path == NULL)
       return NULL;
    
    /* if path doesn't start with ~, just return a copy of path */
    if (*path != '~')
       return xstrdup(path);

    /* expand ~/ or ~user */
    path++;
    if (*path == '/') { /* expand `~/' to `$HOME/' */
       char *homedir = getenv("HOME");
       if (homedir != NULL) {
           resolved = xstrdup(homedir);
           resolved = xstrcat(resolved, path);
       }
       else {
#if defined(HAVE_GETPWUID) && defined(HAVE_GETUID)
           /* homedir not set */
           struct passwd *entry = getpwuid(getuid());
           if (entry != NULL) {
              homedir = entry->pw_dir;
              if (homedir != NULL) {
                  resolved = xstrdup(homedir);
                  resolved = xstrcat(resolved, path);
              }
              else {
                  XDVI_ERROR((stderr, "getpwnam returned NULL for entry->pw_dir: %s", strerror(errno)));
                  return NULL;
              }
           }
           else {
              XDVI_ERROR((stderr, "getpwnam failed: %s", strerror(errno)));
              return NULL;
           }
#else
           popup_message(globals.widgets.top_level,
                       MSG_WARN,
                       NULL,
                       "$HOME not set, and getpwuid() or getuid() not supported - could not expand \"%s\".",
                       orig_path);
           return NULL;
#endif
       }
       TRACE_GUI((stderr, "resolved: |%s|", resolved));
       return resolved;
    }
    else { /* ~user -> try getpwnam() to get homedir */
#ifdef HAVE_GETPWNAM
       struct passwd *entry;
       char *separator = strchr(path, '/');
       char *homedir;

       TRACE_GUI((stderr, "separator is: |%s|, len of username: %d",
                 separator, (int)(separator - path)));
       if (separator == NULL)
           return NULL;

       resolved = xmalloc(separator - path + 1);
       memcpy(resolved, path, separator - path);
       resolved[separator - path] = '\0';

       TRACE_GUI((stderr, "username is: |%s|", resolved));
       entry = getpwnam(resolved);
       if (entry == NULL) {
           XDVI_ERROR((stderr, "getpwnam failed: %s", strerror(errno)));
           return NULL;
       }
       TRACE_GUI((stderr, "homedir of user is: |%s|", entry->pw_dir));
       homedir = entry->pw_dir;
           
       free(resolved);
       resolved = xstrdup(homedir);
       resolved = xstrcat(resolved, path + (separator - path));
       TRACE_GUI((stderr, "resolved: |%s|", resolved));
       return resolved;
#else
       popup_message(globals.widgets.top_level,
                    MSG_WARN,
                    NULL,
                    "Expanding \"%s\" failed: This platform doesn't support getpwnam().",
                    orig_path);
       return NULL;
#endif
    }

}

Here is the call graph for this function:

Here is the caller graph for this function:

char* find_file ( const char *  filename,
struct stat statbuf,
kpse_file_format_type  pathinfo 
)

Definition at line 1468 of file util.c.

{
    char *tmp;
    char *pathname;

    TRACE_SRC((stderr, "checking filename \"%s\"", filename));

    /*
     * case 1:
     * try absolute filename
     */
    if (filename[0] == '/') {
       if (stat(filename, statbuf) == 0) {
           TRACE_SRC((stderr, "Found absolute filename \"%s\"", filename));
           return xstrdup(filename);
       }
       else {
           TRACE_SRC((stderr, "Can't stat absolute filename \"%s\"\n", filename));
           return NULL;
       }
    }

    /*
     * case 2:
     * prepend filename with dir component from the `main' xdvi file (globals.dvi_file.dirname).
     * This works for both
     * /absolute/path/ + filename
     * and
     * /absolute/path/ + relative/path/filename
     */
    ASSERT(globals.dvi_file.dirname != NULL, "globals.dvi_file.dirname should have been initialized");
    {
       pathname = xstrdup(globals.dvi_file.dirname);
       pathname = xstrcat(pathname, filename);

       TRACE_SRC((stderr, "Trying globals.dvi_file.dirname: \"%s\"", pathname));
       if (stat(pathname, statbuf) == 0) {
           return pathname;
       }
    }

    /*
     * case 3:
     * try current directory; if it's a match, expand to full (but uncanonicalized) path name.
     */
    if (stat(filename, statbuf) == 0) {
       TRACE_SRC((stderr, "Found file \"%s\" in current dir", filename));
       free(pathname);
       return expand_filename(filename, USE_CWD_PATH);
    }

    /*
     * case 4:
     * try a kpathsea search for filename
     */
    TRACE_SRC((stderr,
              "trying kpathsearch for filename \"%s\"",
              filename));
    tmp = kpse_find_file(filename, pathinfo, True);

    if (tmp != NULL && stat(tmp, statbuf) == 0) {
       TRACE_SRC((stderr, "Found file: `%s'", tmp));
       free(pathname);
       return tmp;
    }

    /*
     * case 5:
     * try a kpathsea search for pathname
     */
    TRACE_SRC((stderr,
              "trying kpathsearch for pathname \"%s\"",
              pathname));
    tmp = kpse_find_file(pathname, pathinfo, True);

    if (tmp != NULL && stat(tmp, statbuf) == 0) {
       TRACE_SRC((stderr, "Found file: `%s'", tmp));
       free(pathname);
       return tmp;
    }

    /* not found */
    free(pathname);
    free(tmp);
    errno = 0;
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean find_str_int_hash ( hashTableT hashtable,
const char *  key,
size_t val 
)

Definition at line 1573 of file util.c.

{
    string *ret;
#ifdef KPSE_DEBUG
    if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
       kpse_debug_hash_lookup_int = True;
#endif
    ret = hash_lookup(*hashtable, key);
#ifdef KPSE_DEBUG
    if (KPSE_DEBUG_P (KPSE_DEBUG_HASH))
       kpse_debug_hash_lookup_int = False;
#endif

    if (ret != NULL) {
       long l = (long)*ret;
       *val = (size_t)l;
       return True;
    }
    return False;
}

Here is the caller graph for this function:

Boolean fork_process ( const char *  proc_name,
Boolean  redirect_stdout,
const char *  dirname,
childProcT  exit_proc,
void data,
char *const  argv[] 
)

Definition at line 1099 of file util.c.

{
    int i, pid;
    struct xchild *my_child = xmalloc(sizeof *my_child);
    struct xio *my_io = xmalloc(sizeof *my_io);
    int err_pipe[2];
    char *volatile buf = xstrdup("");

    for (i = 0; argv[i] != NULL; i++) {
       TRACE_GUI((stderr, "argv: |%s|", argv[i]));
       buf = xstrcat(buf, argv[i]);
       buf = xstrcat(buf, " ");
    }
    
    if (i > 0)
       buf[strlen(buf) - 1] = '\0'; /* chop off trailing space */

    TRACE_GUI((stderr, "forking: |%s|", buf));
    
    /* flush output buffers to avoid double buffering (i.e. data
       waiting in the output buffer being written twice, by the parent
       and the child) */
    fflush(stdout);
    fflush(stderr);

    if (pipe(err_pipe) < 0) {
       XDVI_FATAL((stderr, "pipe error"));
    }

    switch (pid = vfork()) {
    case -1:  /* forking error */
       perror("vfork");
       close(err_pipe[0]);
       close(err_pipe[1]);
       return False;
    case 0:   /* child */
       if (dirname != NULL)
           chdir(dirname);
       if (globals.debug & DBG_FILES) {
           char path[MAXPATHLEN];
           getcwd(path, MAXPATHLEN);
           fprintf(stderr, "Directory of running `%s': `%s'\n",
                  proc_name, path);
       }
       /* FIXME: There's a bug which prevents this from working
          with xdvi as child: Whenever xdvi tries to print to stderr,
          this will hang the child forever. Closing all other file
          descriptors, as in the #if TRY_FIX regions, seems to fix
          this, but it also loses all output ...
        */
#if TRY_FIX
       close(0);
       close(1);
#endif /* TRY_FIX */
       close(err_pipe[0]);  /* no reading from stderr */

       /* redirect writing to stderr */
       if (dup2(err_pipe[1], STDERR_FILENO) != STDERR_FILENO) {
           perror("dup2 for stderr");
           _exit(EXIT_FAILURE);
           return False;    /* make compiler happy */
       }
       if (redirect_stdout) {
           /* also redirect writing to stdout */
           if (dup2(err_pipe[1], STDOUT_FILENO) != STDOUT_FILENO) {
              perror("dup2 for stdout");
              _exit(EXIT_FAILURE);
              return False; /* make compiler happy */
           }
       }

#if TRY_FIX
       /* close all remaining descriptors */
       i = 2;
       while (i < 256 /* TODO: better handling of OPEN_MAX; see Stevens p. 43 */) {
           close(i++);
       }
#endif /* TRY_FIX */
       execvp(proc_name, argv);

       /* arrive here only if execvp failed */
       fprintf(stderr, "%s: Execution of %s failed.\n", globals.program_name, proc_name);
       fflush(stderr);
       close(err_pipe[1]);
       _exit(EXIT_FAILURE);
       return False;        /* make compiler happy */
    default:  /* parent */
       close(err_pipe[1]);  /* no writing to stderr */

       my_io->next = NULL;
       my_io->fd = err_pipe[0];
       my_io->xio_events = XIO_IN;
#if HAVE_POLL
       my_io->pfd = NULL;
#endif
       my_io->read_proc = read_child_error;
       my_io->write_proc = dummy_write_proc;
       
       my_child->next = NULL;
       my_child->pid = pid;
       my_child->name = buf;
       my_child->data = data;
       if (exit_proc == NULL) { /* use default exit procedure */
           my_child->proc = handle_child_exit;
       }
       else {
           my_child->proc = exit_proc;
       }
       my_child->io = my_io;
       
       set_chld(my_child);
       
       return True;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

int get_avg_font_width ( XFontStruct *  font)

Definition at line 1347 of file util.c.

{
    int width;

    assert(font != NULL);
    width = font->max_bounds.width + font->min_bounds.width / 2;
    if (width == 0) {
       /* if min_bounds.width = -max_bounds.width, we probably
          have a scalable TT font; try to determine its actual
          width by measuring the letter `x':
       */
       width = XTextWidth(font, "x", 1);
    }
    if (width == 0) { /* last resort */
       width = font->max_bounds.width / 2;
    }
    return width;
    
}

Here is the caller graph for this function:

unsigned long get_bytes ( FILE fp,
int  size 
)

Definition at line 905 of file util.c.

{
    long x = 0;

    while (size--)
       x = (x << 8) | get_byte(fp);
    return x;
}

Here is the call graph for this function:

Here is the caller graph for this function:

long get_lbytes ( FILE fp,
int  size 
)

Definition at line 915 of file util.c.

{
    long x;

#if    __STDC__
    x = (signed char)getc(fp);
#else
    x = (unsigned char)getc(fp);
    if (x & 0x80)
       x -= 0x100;
#endif
    while (--size)
       x = (x << 8) | get_byte(fp);
    return x;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1696 of file util.c.

{
    const char *text_encoding = NULL;
    
    /* if resource.text_encoding isn't set, use nl_langinfo() if langinfo is available */
    if (resource.text_encoding == NULL) {
#if USE_LANGINFO
       if (globals.orig_locale == NULL) {
           XDVI_ERROR((stderr, "Call to setlocale() returned NULL; assuming ISO-8859-1 charset."));
           text_encoding = "ISO-8859-1";
       }
       else {
           if (strcmp(globals.orig_locale, "C") == 0 || strcmp(globals.orig_locale, "POSIX") == 0) {
              /* nl_langinfo returns rather strange values for these ... */
              text_encoding = "ISO-8859-1";
              TRACE_FIND((stderr, "Assuming |%s| for locale |%s|",
                         text_encoding, globals.orig_locale));
           }
           else {
              text_encoding = nl_langinfo(CODESET);
              TRACE_FIND((stderr, "nl_langinfo returned: |%s| for locale |%s|",
                         text_encoding, globals.orig_locale));
           }
       }
#else
       XDVI_WARNING((stderr,
                    "nl_langinfo() not available on this platform, "
                    "and XDvi.textEncoding resource not set; using default "
                    "encoding ISO-8859-1."));
       text_encoding = "ISO-8859-1";
#endif
    }
    else {
       text_encoding = resource.text_encoding;
    }
    return text_encoding;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void handle_child_exit ( int  status,
struct xchild this 
)

Definition at line 1020 of file util.c.

{
    char *err_msg = NULL;
    
    /* if child exited with error and xio struct is available for child,
       print error text */
    if (this->io != NULL
       && (WIFEXITED(status) != 0)
       && (WEXITSTATUS(status) != 0)
       && (err_msg = (this->io->read_proc)(this->io->fd)) != NULL) {

       if (this->name == NULL) {
           popup_message(globals.widgets.top_level,
                       MSG_WARN,
                       NULL,
                       err_msg[0] == '\0' ? "An unknown error occurred" : err_msg);
       }
       else {
           popup_message(globals.widgets.top_level,
                       MSG_WARN,
                       "Xdvi tries to collect all messages from STDERR. "
                       "When no useful error message is available "
                       "(e.g. because the program has written to STDOUT instead), "
                       "try to run the command again from the command line "
                       "to find out what the problem was.",
                       "Command \"%s\" exited with error code %d\n%s\n",
                       this->name, WEXITSTATUS(status), err_msg);
       }
       free(err_msg);
    }
    free(this->name);
    free(this->io);
    free(this);
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* iconv_convert_string ( const char *  from_enc,
const char *  to_enc,
const char *  str 
)

Definition at line 1735 of file util.c.

{
    static Boolean have_warned = False;
#if HAVE_ICONV_H
    size_t input_len = strlen(str);
    size_t conv_len = input_len * 4 + 1; /* worst case ... */
    int conv_len_save = conv_len;
    char *conv_buf = xmalloc(conv_len);
    const char *in_ptr = str;
    const char *out_ptr = conv_buf;

    iconv_t conv_desc = iconv_open(to_enc, from_enc);

    if (conv_desc == (iconv_t)(-1)) {
       if (!have_warned) {
           popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
                       MSG_ERR,
                       NULL,
                       "iconv_open() error: Encoding \"%s\" is not supported by this version of iconv.\n"
                       "Please check the output of \"iconv -l\" and set the X resource\n"
                       "\"XDvi.textEncoding\" to an appropriate value.", from_enc);
           have_warned = True;
       }
       free(conv_buf);
       return NULL;
    }

    TRACE_FIND((stderr, "iconv_convert_string: from `%s', to `%s'", from_enc, to_enc));
    if (iconv(conv_desc, (iconv_char_pptrT)&in_ptr, &input_len, (char **)&out_ptr, &conv_len) == (size_t)(-1)) {
       popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
                    MSG_ERR,
                    NULL,
                    "iconv_convert_string(): Could not convert %s to %s: %s.",
                    from_enc, to_enc, strerror(errno));
       iconv_close(conv_desc);
       free(conv_buf);
       return NULL;
    }

    iconv_close(conv_desc);
    conv_len = conv_len_save - conv_len;
    conv_buf[conv_len] = '\0';

    TRACE_FIND((stderr, "after iconv conversion: |%s| %lu bytes\n",
              conv_buf, (unsigned long)conv_len));

    
    return conv_buf;
    
#else /* HAVE_ICONV_H */

    UNUSED(from_enc);
    UNUSED(to_enc);
    UNUSED(str);
    
    /* no iconv available */
    if (!have_warned) {
       popup_message(XtNameToWidget(globals.widgets.top_level, "*find_popup"),
                    MSG_ERR,
                    "You can either set the \"LANG\" environment variable or the X resource "
                    "\"XDvi.textEncoding\" to make xdvi use a different language/encoding setting.\n"
                    "Without iconv, only the encodings ISO-8859-1 and UTF-8 are supported. "
                    "For real iconv support, you will need to install the iconv library "
                    "and recompile xdvik.",
                    "Cannot convert from %s to UTF-8 without iconv support compiled in.");
       have_warned = True;
    }
    return NULL;
    
#endif /* HAVE_ICONV_H */
}

Here is the call graph for this function:

Here is the caller graph for this function:

int memicmp ( const char *  s1,
const char *  s2,
size_t  n 
)

Definition at line 809 of file util.c.

{
    while (n > 0) {
       int i = tolower((int)*s1) - *s2;
       if (i != 0)
           return i;
       ++s1;
       ++s2;
       --n;
    }
    return 0;
}

Here is the caller graph for this function:

char* my_realpath ( const char *  path,
char *  resolved 
)

Definition at line 558 of file util.c.

{
    struct stat sb;
    int n;
    /*     char *p, *q, *tmp; */
    char *base;
    char tmpbuf[MAXPATHLEN];
    int symlinks = 0;
#ifdef HAVE_FCHDIR
    int fd;
#else
    char cwd[MAXPATHLEN];
#endif

    /* Save cwd for going back later */
#ifdef HAVE_FCHDIR
    if ((fd = try_open(".", O_RDONLY)) < 0)
       return NULL;
#else /* HAVE_FCHDIR */
    if (
# ifdef HAVE_GETCWD
       getcwd(cwd, MAXPATHLEN)
# else
       getwd(cwd)
# endif
       == NULL)
       return NULL;
#endif /* HAVE_FCHDIR */

    if (strlen(path) + 1 > MAXPATHLEN) {
       errno = ENAMETOOLONG;
       return NULL;
    }
    
    strcpy(resolved, path);

    for (;;) { /* loop for resolving symlinks in base name */
       /* get base name and dir name components */
       char *p = strrchr(resolved, '/');
       if (p != NULL) {
           base = p + 1;
           if (p == resolved) {
              /* resolved is in root dir; this must be treated as a special case,
                 since we can't chop off at `/'; instead, just use the `/':
              */
              p = "/";
           }
           else {
              /* not in root dir; chop off path name at slash */
              while (p > resolved && *p == '/') /* for multiple trailing slashes */
                  p--;
              *(p + 1) = '\0';
              p = resolved;
           }

           /* change into that dir */
           if (chdir(p) != 0)
              break;
       }
       else /* no directory component */
           base = resolved;

       /* resolve symlinks or directory names (not used in our case) in basename */
       if (*base != '\0') {
           if (
#ifdef HAVE_LSTAT
              lstat(base, &sb)
#else
              stat(base, &sb)
#endif
              == 0) {
#ifdef HAVE_LSTAT
              if (S_ISLNK(sb.st_mode)) { /* if it's a symlink, iterate for what it links to */
                  if (++symlinks > MAXSYMLINKS) {
                     errno = ELOOP;
                     break;
                  }

                  if ((n = readlink(base, resolved, MAXPATHLEN)) < 0)
                     break;

                  resolved[n] = '\0';
                  continue;
              }
#endif /* HAVE_LSTAT */
              if (S_ISDIR(sb.st_mode)) { /* if it's a directory, go there */
                  if (chdir(base) != 0)
                     break;

                  base = "";
              }
           }
       }

       /* Now get full pathname of current directory and concatenate it with saved copy of base name */
       strcpy(tmpbuf, base); /* cannot overrun, since strlen(base) <= strlen(path) < MAXPATHLEN */
       if (
#ifdef HAVE_GETCWD
           getcwd(resolved, MAXPATHLEN)
#else
           getwd(resolved)
#endif
           == NULL)
           break;

       /* need to append a slash if resolved is not the root dir */
       if (!(resolved[0] == '/' && resolved[1] == '\0')) {
           if (strlen(resolved) + 2 > MAXPATHLEN) {
              errno = ENAMETOOLONG;
              break;
           }
           strcat(resolved, "/");
       }

       if (*tmpbuf) {
           if (strlen(resolved) + strlen(tmpbuf) + 1 > MAXPATHLEN) {
              errno = ENAMETOOLONG;
              break;
           }
           strcat(resolved, tmpbuf);
       }

       /* go back to where we came from */
#ifdef HAVE_FCHDIR
       fchdir(fd);
       close(fd);
#else
       chdir(cwd);
#endif
       return resolved;
    }

    /* arrive here in case of error: go back to where we came from, and return NULL */
#ifdef HAVE_FCHDIR
    fchdir(fd);
    close(fd);
#else
    chdir(cwd);
#endif
    return NULL;
}

Here is the call graph for this function:

unsigned long parse_debugging_option ( const char *  ptr)

Definition at line 1331 of file util.c.

{
    if (ptr == NULL)
       return 0L;
    else if (isdigit((int)*ptr)) {
       if (resource.debug_arg == NULL)
           return DBG_ALL; /* per default debug everything */
       else
           return strtol(resource.debug_arg, (char **)NULL, 10);
    } else if (*ptr == '-')
       return DBG_ALL;
    else return parse_debugging_string(ptr);
}

Here is the call graph for this function:

Here is the caller graph for this function:

unsigned long parse_debugging_string ( const char *  arg)

Definition at line 1280 of file util.c.

{
    int retval = 0;
    const char *curr, *last;
    size_t i;
    
    curr = last = arg;

    while (curr != '\0') {
       Boolean matched = False;

       while (isspace((int)*curr))
           curr++;
       for (i = 0; debug_options[i].description != NULL; i++) {
           /* match on length of passed argument, to allow for abbreviations */
           if (memicmp(curr,
                     debug_options[i].description,
                     strlen(debug_options[i].description)) == 0
              && (curr[strlen(debug_options[i].description)] == '\0'
                  || curr[strlen(debug_options[i].description)] == ','
                  || isspace((int)curr[strlen(debug_options[i].description)]))) {
              matched = True;
              retval |= debug_options[i].bitmap;
              fprintf(stderr, "Debugging option: \"%s\" = \"%s\", debug: %d\n",
                     curr, debug_options[i].description, retval);
           }
       }
       if (!matched) {
           char *tempstr = xstrdup(curr);
           char *test;
           if ((test = strchr(curr, ',')) != NULL) {
              *test = '\0';
           }
           XDVI_WARNING((stderr, "Ignoring unknown debugging option \"%s\". Valid options are:\n", tempstr));
           for (i = 0; debug_options[i].description != NULL; i++) {
              fprintf(stderr, "`%s'%s",
                     debug_options[i].description,
                     debug_options[i].help_formatting);
           }
           fprintf(stderr, "\n");
           free(tempstr);
       }
       curr = strchr(curr, ',');
       if (curr != NULL)
           curr++;
    }

    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Boolean pointerlocate ( int xpos,
int ypos 
)

Definition at line 1266 of file util.c.

{
    Window root, child;
    int root_x, root_y;
    unsigned int keys_buttons;

    if (!XtIsRealized(globals.widgets.top_level))
       return False;
    
    return XQueryPointer(DISP, mane.win, &root, &child,
                      &root_x, &root_y, xpos, ypos, &keys_buttons);
}

Here is the caller graph for this function:

void prep_fd ( int  fd,
wide_bool  noblock 
)

Definition at line 1226 of file util.c.

{
    /* Set file descriptor for non-blocking I/O */
    if (noblock)
       (void) fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
    
#if !FLAKY_SIGPOLL
# if HAVE_STREAMS
    if (isastream(fd) > 0) {
       if (ioctl(fd, I_SETSIG,
                S_RDNORM | S_RDBAND | S_HANGUP | S_WRNORM) == -1)
           perror("xdvi: ioctl I_SETSIG");
    }
    else
# endif
       {
# ifdef FASYNC
           if (fcntl(fd, F_SETOWN, getpid()) == -1)
              perror("xdvi: fcntl F_SETOWN");
           if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | FASYNC) == -1)
              perror("xdvi: fcntl F_SETFL");
# elif defined SIOCSPGRP && defined FIOASYNC
           /* For HP-UX B.10.10 and maybe others.  See "man 7 socket".  */
           int arg;
           
           arg = getpid();
           if (ioctl(fd, SIOCSPGRP, &arg) == -1)
              perror("xdvi: ioctl SIOCSPGRP");
           arg = 1;
           if (ioctl(fd, FIOASYNC, &arg) == -1)
              perror("xdvi: ioctl FIOASYNC");
# endif
       }
#endif /* not FLAKY_SIGPOLL */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void put_str_int_hash ( hashTableT hashtable,
const char *  key,
size_t  val 
)

Definition at line 1600 of file util.c.

{
    long ptr = (long)val;
    hash_insert(hashtable, key, (const string)ptr);
}

Here is the caller graph for this function:

char* read_child_error ( int  fd)

Definition at line 1068 of file util.c.

{
    int bytes = 0, buf_old_size = 0, buf_new_size = 0;
    char tmp_buf[BUF_SIZE];
    char *err_buf = xstrdup("");
    char *ret;
    /* collect stderr messages into err_buf */
    while ((bytes = read(fd, tmp_buf, BUF_SIZE - 1)) > 0) {
       buf_old_size = buf_new_size;
       buf_new_size += bytes;
       err_buf = xrealloc(err_buf, buf_new_size + 1);
       memcpy(err_buf + buf_old_size, tmp_buf, buf_new_size - buf_old_size);
       err_buf[buf_new_size] = '\0';
    }

    close(fd);
    ret = escape_format_arg(err_buf); /* this allocates ret */
    free(err_buf);
    return ret;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void set_dvi_name ( char *  new_filename)

Definition at line 1625 of file util.c.

{
    ASSERT(new_filename != NULL, "");
    free(globals.dvi_name);
    globals.dvi_name = new_filename;

    free(globals.dvi_file.dirname);
    globals.dvi_file.dirname = get_dir_component(globals.dvi_name);

    ASSERT(globals.dvi_file.dirname != NULL, "dvi_name should be a path with dir component");
    globals.dvi_file.dirlen = strlen(globals.dvi_file.dirname);
}   

Here is the call graph for this function:

Here is the caller graph for this function:

void set_dvi_name_expand ( const char *  new_filename)

Definition at line 1608 of file util.c.

{
    ASSERT(new_filename != NULL, "");
    free(globals.dvi_name);
    globals.dvi_name = expand_filename_append_dvi(new_filename, USE_CWD_PATH, True);

    free(globals.dvi_file.dirname);
    globals.dvi_file.dirname = get_dir_component(globals.dvi_name);

    ASSERT(globals.dvi_file.dirname != NULL, "dvi_name should be a path with dir component");
    globals.dvi_file.dirlen = strlen(globals.dvi_file.dirname);
}   

Here is the call graph for this function:

Here is the caller graph for this function:

char** split_line ( const char *  line,
char  sep,
size_t  begin,
size_t  end,
size_t ret_items 
)

Definition at line 1376 of file util.c.

{
    const char *c_ptr = line + begin;
    const char *e_ptr = line + end;
    const char *test_end;
    
    size_t result_cnt = 0;
    size_t alloc_len = 0;
    size_t len;
    const size_t ALLOC_STEP = 8;
    char **result_arr = NULL;
    
    /* create new result item, resizing result_arr as needed
     * (an empty string will coun1 as 1 item: "") */
    while (result_cnt + 1 >= alloc_len) {
       alloc_len += ALLOC_STEP;
       result_arr = xrealloc(result_arr, alloc_len * sizeof *result_arr);
    }

    while (c_ptr <= e_ptr) {
       /* skip leading whitespace */
       while (c_ptr < e_ptr && isspace((int)*c_ptr)) {
           c_ptr++;
       }

       /* find end of current elem, which is either the separator or out of range */
       test_end = strchr(c_ptr, sep);
       /* skip escaped separators */
       while (test_end != NULL && test_end <= e_ptr) {
           if (test_end > c_ptr && *(test_end - 1) == '\\') {
              test_end = strchr(test_end + 1, sep);
           }
           else
              break;
       }
       /* if nothing found, use e_ptr */
       if (test_end == NULL || test_end > e_ptr) {
           test_end = e_ptr;
       }

       len = test_end - c_ptr;

       /* skip trailing whitespace */
       while (len > 0 && isspace((int)c_ptr[len - 1])) {
           len--;
       }

       result_arr[result_cnt] = xmalloc(len + 1);
       /* copy into result item, skipping the escape '\\' characters */
       {
           size_t i = 0, j = 0;
           while (i < len) {
              if (c_ptr[i] == '\\' && c_ptr[i + 1] == sep) /* i + 1 is safe since (i < len) */
                  i++;
              result_arr[result_cnt][j++] = c_ptr[i++];
           }
           result_arr[result_cnt][j] = '\0';
       }
       result_cnt++;
       
       /* skip to next item */
       c_ptr = test_end + 1;
    }
    result_arr[result_cnt] = NULL; /* null-terminate return array, just to be safe */
    *ret_items = result_cnt;
    return result_arr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

FILE* try_fdopen ( int  fd,
const char *  mode 
)

Definition at line 342 of file util.c.

{
    FILE *fp = fdopen(fd, mode);
    if (fp == NULL && (errno == EMFILE || errno == ENFILE)) {
       close_a_file();
       fp = fdopen(fd, mode);
    }
    return fp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

FILE* try_fopen ( const char *  fname,
const char *  mode 
)

Definition at line 328 of file util.c.

{
    FILE *fp = fopen(fname, mode);
    if (fp == NULL && (errno == EMFILE || errno == ENFILE)) {
       close_a_file();
       fp = fopen(fname, mode);
    }
    return fp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int try_open ( const char *  fname,
int  flags 
)

Definition at line 357 of file util.c.

{
    int fd = open(fname, flags);
    if (fd < 0 && (errno == EMFILE || errno == ENFILE)) {
       close_a_file();
       fd = open(fname, flags);
    }
    return fd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int try_open_mode ( const char *  fname,
int  flags,
mode_t  mode 
)

Definition at line 371 of file util.c.

{
    int fd = open(fname, flags, mode);
    if (fd < 0 && (errno == EMFILE || errno == ENFILE)) {
       close_a_file();
       fd = open(fname, flags);
    }
    return fd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void xdvi_exit ( int  status)

Definition at line 391 of file util.c.

{
    /* do the following only if the window has been opened: */
    if (globals.widgets.top_level != 0 && XtIsRealized(globals.widgets.top_level)) {
       char *filehist;
       file_history_set_page(current_page);
       filehist = file_history_get_list();
       store_preference(NULL, "fileHistory", "%s", filehist);
       free(filehist);

#if MOTIF
       if (preferences_changed()) {
           return;
       }
/*      else { */
/*     fprintf(stderr, "Preferences not changed.\n"); */
/*      } */
#endif
       /* try to save user preferences, unless we're exiting with an error */
       if (status == 0 && !save_user_preferences(True))
           return;
    
       /* Clean up the "xdvi windows" property in the root window.  */
       update_window_property(XtWindow(globals.widgets.top_level), False);
    }

#if PS
    ps_destroy();
#endif
    remove_tmp_dvi_file();

    close_iconv();

    exit(status);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int xdvi_temp_fd ( char **  str)

Definition at line 945 of file util.c.

{
    int fd;
    char *p;
    size_t len;
    static const char *template = NULL;
#if !HAVE_MKSTEMP
    static unsigned long seed;
    static char letters[] =
       "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._";
    char *p1;
#endif

    if (*str != NULL) {
       p = *str;

       /* O_EXCL is there for security (if root runs xdvi) */
       if (!((fd = try_open_mode(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1
             && errno == EEXIST))
           return fd;
#if HAVE_MKSTEMP
       memcpy(p + strlen(p) - 6, "XXXXXX", 6);
#endif
    }
    else {
       if (template == NULL) {
           const char *ourdir;

           ourdir = getenv("TMPDIR");
           if (ourdir == NULL || access(ourdir, W_OK) < 0) {
              ourdir = P_tmpdir;
              if (access(ourdir, W_OK) < 0)
                  ourdir = ".";
           }
           len = strlen(ourdir);
           if (len > 0 && ourdir[len - 1] == '/')
              --len;
           template = p = xmalloc(len + sizeof tmp_suffix);
           memcpy(p, ourdir, len);
           memcpy(p + len, tmp_suffix, sizeof tmp_suffix);
#if !HAVE_MKSTEMP
           seed = 123456789 * time(NULL) + 987654321 * getpid();
#endif
       }
       *str = p = xstrdup(template);
    }

#if HAVE_MKSTEMP
    fd = mkstemp(p);
    if (fd == -1 && (errno == EMFILE || errno == ENFILE)) {
       close_a_file();
       memcpy(p + strlen(p) - 6, "XXXXXX", 6);
       fd = mkstemp(p);
    }
#else
    p1 = p + strlen(p) - 6;
    for (;;) {
       unsigned long s = ++seed;
       char *p2;

       for (p2 = p1 + 5; p2 >= p1; --p2) {
           *p2 = letters[s & 63];
           s >>= 6;
       }
       if (!((fd = try_open_mode(p, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) == -1
             && errno == EEXIST))
           break;
    }
#endif
    return fd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

FILE* XFOPEN ( const char *  path,
const char *  mode 
)

Definition at line 856 of file util.c.

{
    FILE *fp = NULL;
#ifdef TESTING_OPEN_FILES
    fprintf(stderr, "trying to open |%s|\n", path);
#endif
    if ((fp = try_fopen(path, mode)) == NULL && (errno == EMFILE || errno == ENFILE)) {
       XDVI_FATAL((stderr, "too many open files"));
    }
    return fp;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* xmalloc ( unsigned  size)

Definition at line 708 of file util.c.

{
    void *mem = malloc(size);

    if (mem == NULL)
       XDVI_FATAL((stderr, "Out of memory (allocating %u bytes).", size));
    return mem;
}
char* xmemdup ( const char *  str,
size_t  len 
)

Definition at line 753 of file util.c.

{
    char *new;

    new = xmalloc(len);
    memcpy(new, str, len);
    return new;
}

Here is the call graph for this function:

int xpipe ( int fd)

Definition at line 877 of file util.c.

{
    int       retval;
    
    for (;;) {
       retval = socketpair(AF_UNIX, SOCK_STREAM, 0, fd);
       if (retval == 0) { /* success */
           break;
       }
       if ((errno != EMFILE && errno != ENFILE)) {
           /* failed, but not because of too many files */
           break;
       }
       close_a_file();
    }
    return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void* xrealloc ( void where,
unsigned  size 
)

Definition at line 718 of file util.c.

{
    void *mem = realloc(where, size);

    if (mem == NULL)
       XDVI_FATAL((stderr, "Out of memory (reallocating %u bytes).", size));
    return mem;
}

Here is the call graph for this function:

char* xstrcat ( char *  str1,
const char *  str2 
)

Definition at line 774 of file util.c.

{
    size_t len1 = (str1 == NULL) ? 0 : strlen(str1);
    size_t len2 = strlen(str2) + 1;

    str1 = xrealloc(str1, len1 + len2);
    memcpy(str1 + len1, str2, len2);
    return str1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

char* xstrdup ( const char *  str)

Definition at line 733 of file util.c.

{
    size_t len;
    char *new;

    ASSERT(fprintf(stderr, "Test assertion!\n") && 1 == 0);
    ASSERT(str != NULL, "");
    len = strlen(str) + 1;
    new = xmalloc(len);
    memcpy(new, str, len);
    return new;
}

Variable Documentation

const char tmp_suffix[] = "/xdvi-XXXXXX" [static]

Definition at line 942 of file util.c.