wdvi

network DVI viewer
Log | Files | Refs

util.c (8336B)


      1 /*========================================================================*\
      2 
      3 Copyright (c) 1990-2013  Paul Vojta
      4 
      5 Permission is hereby granted, free of charge, to any person obtaining a copy
      6 of this software and associated documentation files (the "Software"), to
      7 deal in the Software without restriction, including without limitation the
      8 rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      9 sell copies of the Software, and to permit persons to whom the Software is
     10 furnished to do so, subject to the following conditions:
     11 
     12 The above copyright notice and this permission notice shall be included in
     13 all copies or substantial portions of the Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18 PAUL VOJTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
     19 IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 NOTE:
     23 	xdvi is based on prior work, as noted in the modification history
     24 	in xdvi.c.
     25 
     26 \*========================================================================*/
     27 
     28 #include <err.h>
     29 #include <fcntl.h>	/* fcntl() */
     30 #include <stdlib.h>	/* malloc(), realloc() */
     31 #include <string.h>	/* strdup(), memcpy() */
     32 #include <strings.h>	/* bcopy() */
     33 #include <pwd.h>	/* getpwuid(), getpwnam() */
     34 #include <unistd.h>	/* getuid() */
     35 
     36 #include "util.h"
     37 #include "xdvi.h"
     38 
     39 
     40 /*
     41  *	General utility routines.
     42  */
     43 
     44 /*
     45  *	Either (re)allocate storage or fail with explanation.
     46  */
     47 void *
     48 xmalloc(size_t size)
     49 {
     50 	void	*mem	= malloc(size);
     51 
     52 	if (mem == NULL)
     53 	    err(1, "malloc %zu bytes", size);
     54 	return mem;
     55 }
     56 
     57 void *
     58 xrealloc(void *where, size_t size)
     59 {
     60 	void	*mem	= realloc(where, size);
     61 
     62 	if (mem == NULL)
     63 	    err(1, "realloc %zu bytes", size);
     64 	return mem;
     65 }
     66 
     67 /*
     68  *	Allocate a new string.
     69  */
     70 char *
     71 xstrdup(const char *str)
     72 {
     73 	char	*new;
     74 
     75 	if ((new = strdup(str)) == NULL)
     76 		err(1, "strdup");
     77 	return new;
     78 }
     79 
     80 /*
     81  *	Allocate a new string.  The second argument is the length.
     82  */
     83 char *
     84 xmemdup(const char *str, size_t len)
     85 {
     86 	char	*new;
     87 
     88 	new = xmalloc(len);
     89 	memcpy(new, str, len);
     90 	return new;
     91 }
     92 
     93 /*
     94  *	Expand the matrix *ffline to at least the given size.
     95  */
     96 void
     97 expandline(size_t n)
     98 {
     99 	size_t	newlen	= n + 128;
    100 
    101 	ffline = (ffline == NULL) ? xmalloc(newlen) : xrealloc(ffline, newlen);
    102 	ffline_len = newlen;
    103 }
    104 
    105 /*
    106  *	Allocate bitmap for given font and character
    107  */
    108 void
    109 alloc_bitmap(struct bitmap *bitmap)
    110 {
    111 	unsigned int	size;
    112 
    113 	/* width must be multiple of 16 bits for raster_op */
    114 	bitmap->bytes_wide = ROUNDUP((int) bitmap->w, BMBITS) * BMBYTES;
    115 	size = bitmap->bytes_wide * bitmap->h;
    116 	bitmap->bits = xmalloc(size != 0 ? size : 1);
    117 }
    118 
    119 /*
    120  *	Open a file in the given mode.
    121  */
    122 FILE *
    123 xfopen(const char *filename, const char *type)
    124 {
    125 	FILE	*f;
    126 
    127 	f = fopen(filename, type);
    128 
    129 	if (f != NULL)
    130 	    (void) fcntl(fileno(f), F_SETFD, 1);
    131 
    132 	return f;
    133 }
    134 
    135 /*
    136  *	Perform tilde expansion, updating the character pointer unless the
    137  *	user was not found.
    138  */
    139 const	struct passwd *
    140 ff_getpw(const char **pp, const char *p_end)
    141 {
    142 	const	char		*p	= *pp;
    143 	const	char		*p1;
    144 	unsigned		len;
    145 	const	struct passwd	*pw;
    146 	int			count;
    147 
    148 	++p;	/* skip the tilde */
    149 	p1 = p;
    150 	while (p1 < p_end && *p1 != '/') ++p1;
    151 	len = p1 - p;
    152 
    153 	if (len != 0) {
    154 	    if (len >= ffline_len)
    155 		expandline(len);
    156 	    bcopy(p, ffline, len);
    157 	    ffline[len] = '\0';
    158 	}
    159 
    160 	for (count = 0;; ++count) {
    161 	    if (len == 0)	/* if no user name */
    162 		pw = getpwuid(getuid());
    163 	    else
    164 		pw = getpwnam(ffline);
    165 
    166 	    if (pw != NULL) {
    167 		*pp = p1;
    168 		return pw;
    169 	    }
    170 
    171 	    /* On some systems, getpw{uid,nam} return without setting errno,
    172 	     * even if the call failed because of too many open files.
    173 	     * Therefore, we play it safe here.
    174 	     */
    175 	    if (count >= 2 && len != 0 && getpwuid(getuid()) != NULL)
    176 		return NULL;
    177 	}
    178 }
    179 
    180 /*
    181  *
    182  *      Read size bytes from the FILE fp, constructing them into a
    183  *      signed/unsigned integer.
    184  *
    185  */
    186 unsigned long
    187 num(FILE *fp, int size)
    188 {
    189 	long	x	= 0;
    190 
    191 	while (size--)
    192 		x = (x << 8) | one(fp);
    193 	return x;
    194 }
    195 
    196 long
    197 snum(FILE *fp, int size)
    198 {
    199 	long	x;
    200 
    201 	x = (signed char) getc(fp);
    202 	while (--size)
    203 		x = (x << 8) | one(fp);
    204 	return x;
    205 }
    206 
    207 /*
    208  *	General AVL tree mechanism.  Search for a node, and return it if found.
    209  *	Otherwise insert a node.
    210  *	This uses the AVL algorithm from Knuth Vol. 3.
    211  */
    212 struct avl *
    213 avladd(const char *key, size_t key_len, struct avl **headp, size_t size)
    214 {
    215 	struct avl	*ap;
    216 	struct avl	**app;
    217 	struct avl	*sp;	/* place where rebalancing may be necessary */
    218 	struct avl	**spp;	/* points to sp */
    219 	int		i;
    220 
    221 	/* Search */
    222 	spp = app = headp;
    223 	for (;;) {
    224 	    ap = *app;
    225 	    if (ap == NULL)	/* bottom of tree */
    226 		break;
    227 	    if (ap->bal != 0)
    228 		spp = app;
    229 	    i = key_len - ap->key_len;
    230 	    if (i == 0)
    231 		i = memcmp(key, ap->key, key_len);
    232 	    if (i == 0)		/* found record already */
    233 		return ap;
    234 	    if (i < 0)		/* move left */
    235 		app = &ap->left;
    236 	    else
    237 		app = &ap->right;
    238 	}
    239 
    240 	/* Insert */
    241 	ap = xmalloc(size);
    242 	ap->key = key;
    243 	ap->key_len = key_len;
    244 	ap->bal = 0;
    245 	ap->left = ap->right = NULL;
    246 	*app = ap;
    247 
    248 	/* Adjust balance factors */
    249 	sp = *spp;
    250 	if (sp == ap)
    251 	    return ap;
    252 	i = key_len - sp->key_len;
    253 	if (i == 0)
    254 	    i = memcmp(key, sp->key, key_len);
    255 	sp = (i < 0 ? sp->left : sp->right);
    256 	while (sp != ap) {
    257 	    i = key_len - sp->key_len;
    258 	    if (i == 0)
    259 		i = memcmp(key, sp->key, key_len);
    260 	    if (i < 0) {
    261 		sp->bal = -1;
    262 		sp = sp->left;
    263 	    }
    264 	    else {
    265 		sp->bal = 1;
    266 		sp = sp->right;
    267 	    }
    268 	}
    269 
    270 	/* Balancing act */
    271 	sp = *spp;
    272 	i = key_len - sp->key_len;
    273 	if (i == 0)
    274 	    i = memcmp(key, sp->key, key_len);
    275 	if (i < 0) {
    276 	    if (sp->bal >= 0)
    277 		--sp->bal;
    278 	    else {	/* need to rebalance */
    279 		struct avl *left;
    280 
    281 		left = sp->left;
    282 		if (left->bal < 0) {	/* single rotation */
    283 		    sp->left = left->right;
    284 		    left->right = sp;
    285 		    sp->bal = left->bal = 0;
    286 		    *spp = left;
    287 		}
    288 		else {			/* double rotation */
    289 		    struct avl	*newtop;
    290 
    291 		    newtop = left->right;
    292 		    sp->left = newtop->right;
    293 		    newtop->right = sp;
    294 		    left->right = newtop->left;
    295 		    newtop->left = left;
    296 		    sp->bal = left->bal = 0;
    297 		    if (newtop->bal < 0) ++sp->bal;
    298 		    else if (newtop->bal > 0) --left->bal;
    299 		    newtop->bal = 0;
    300 		    *spp = newtop;
    301 		}
    302 	    }
    303 	}
    304 	else {
    305 	    if (sp->bal <= 0)
    306 		++sp->bal;
    307 	    else {	/* need to rebalance */
    308 		struct avl *right;
    309 
    310 		right = sp->right;
    311 		if (right->bal > 0) {	/* single rotation */
    312 		    sp->right = right->left;
    313 		    right->left = sp;
    314 		    sp->bal = right->bal = 0;
    315 		    *spp = right;
    316 		}
    317 		else {			/* double rotation */
    318 		    struct avl	*newtop;
    319 
    320 		    newtop = right->left;
    321 		    sp->right = newtop->left;
    322 		    newtop->left = sp;
    323 		    right->left = newtop->right;
    324 		    newtop->right = right;
    325 		    sp->bal = right->bal = 0;
    326 		    if (newtop->bal > 0) --sp->bal;
    327 		    else if (newtop->bal < 0) ++right->bal;
    328 		    newtop->bal = 0;
    329 		    *spp = newtop;
    330 		}
    331 	    }
    332 	}
    333 
    334 	return ap;
    335 }
    336 
    337 /*
    338  * Try and parse dest_url[] as a url:
    339  * - ignore protocol if found
    340  * - hostname is either what's remaining or up to a colon or slash character
    341  * - if colon is found, port number is either what is remaining or up to slash
    342  *   character
    343  * - if slash is found the rest of the string is a document path
    344  *
    345  * On success a struct url pointer is returned that the caller must
    346  * free, otherwise NULL returned.
    347  */
    348 struct url *
    349 parse_url(const char dest_url[])
    350 {
    351 	struct url	*url;
    352 	char		*sep_url;
    353 	char		*proto_loc;
    354 	char		*reset;
    355 
    356 	url = xmalloc(sizeof(struct url));
    357 	url->port = "443";
    358 	url->orig_url = dest_url;
    359 	url->document = "";
    360 
    361 	/* dest_url[] will be modified */
    362 	sep_url = xstrdup(dest_url);
    363 
    364 	/* Do not care if this is specified, https is assumed. */
    365 	if ((proto_loc = strstr(sep_url, "://")) != NULL) {
    366 		*proto_loc = '\0';
    367 		if (strcmp(sep_url, "https") != 0)
    368 			warnx("ignoring scheme '%s'", sep_url);
    369 		sep_url = proto_loc + strlen("://");
    370 	}
    371 
    372 	url->hostname = sep_url;
    373 
    374 	reset = strsep(&sep_url, ":");
    375 	if (sep_url != NULL)
    376 		url->port = sep_url;
    377 	else
    378 		sep_url = reset;
    379 
    380 	strsep(&sep_url, "/");
    381 	if (sep_url != NULL)
    382 		/* / was found, set document path */
    383 		url->document = sep_url;
    384 
    385 	return url;
    386 }