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 }