| File: | src/lib/libcurses/tinfo/write_entry.c |
| Warning: | line 227, column 1 Potential memory leak |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: write_entry.c,v 1.13 2010/01/12 23:22:06 nicm Exp $ */ | |||
| 2 | ||||
| 3 | /**************************************************************************** | |||
| 4 | * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * | |||
| 5 | * * | |||
| 6 | * Permission is hereby granted, free of charge, to any person obtaining a * | |||
| 7 | * copy of this software and associated documentation files (the * | |||
| 8 | * "Software"), to deal in the Software without restriction, including * | |||
| 9 | * without limitation the rights to use, copy, modify, merge, publish, * | |||
| 10 | * distribute, distribute with modifications, sublicense, and/or sell * | |||
| 11 | * copies of the Software, and to permit persons to whom the Software is * | |||
| 12 | * furnished to do so, subject to the following conditions: * | |||
| 13 | * * | |||
| 14 | * The above copyright notice and this permission notice shall be included * | |||
| 15 | * in all copies or substantial portions of the Software. * | |||
| 16 | * * | |||
| 17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * | |||
| 18 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * | |||
| 19 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * | |||
| 20 | * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * | |||
| 21 | * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * | |||
| 22 | * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * | |||
| 23 | * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * | |||
| 24 | * * | |||
| 25 | * Except as contained in this notice, the name(s) of the above copyright * | |||
| 26 | * holders shall not be used in advertising or otherwise to promote the * | |||
| 27 | * sale, use or other dealings in this Software without prior written * | |||
| 28 | * authorization. * | |||
| 29 | ****************************************************************************/ | |||
| 30 | ||||
| 31 | /**************************************************************************** | |||
| 32 | * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * | |||
| 33 | * and: Eric S. Raymond <esr@snark.thyrsus.com> * | |||
| 34 | * and: Thomas E. Dickey 1996-on * | |||
| 35 | ****************************************************************************/ | |||
| 36 | ||||
| 37 | /* | |||
| 38 | * write_entry.c -- write a terminfo structure onto the file system | |||
| 39 | */ | |||
| 40 | ||||
| 41 | #include <curses.priv.h> | |||
| 42 | #include <hashed_db.h> | |||
| 43 | ||||
| 44 | #include <sys/stat.h> | |||
| 45 | ||||
| 46 | #include <tic.h> | |||
| 47 | #include <term_entry.h> | |||
| 48 | ||||
| 49 | #ifndef S_ISDIR | |||
| 50 | #define S_ISDIR(mode)((mode & 0170000) == 0040000) ((mode & S_IFMT0170000) == S_IFDIR0040000) | |||
| 51 | #endif | |||
| 52 | ||||
| 53 | #if 1 | |||
| 54 | #define TRACE_OUT(p) DEBUG(2, p) | |||
| 55 | #else | |||
| 56 | #define TRACE_OUT(p) /*nothing */ | |||
| 57 | #endif | |||
| 58 | ||||
| 59 | MODULE_ID("$Id: write_entry.c,v 1.13 2010/01/12 23:22:06 nicm Exp $") | |||
| 60 | ||||
| 61 | static int total_written; | |||
| 62 | ||||
| 63 | static int make_db_root(const char *); | |||
| 64 | static int write_object(TERMTYPE *, char *, unsigned *, unsigned); | |||
| 65 | ||||
| 66 | #if !USE_HASHED_DB0 | |||
| 67 | static void | |||
| 68 | write_file(char *filename, TERMTYPE *tp) | |||
| 69 | { | |||
| 70 | char buffer[MAX_ENTRY_SIZE4096]; | |||
| 71 | unsigned limit = sizeof(buffer); | |||
| 72 | unsigned offset = 0; | |||
| 73 | ||||
| 74 | FILE *fp = (_nc_access(filename, W_OK0x02) == 0) ? fopen(filename, "wb") : 0; | |||
| 75 | if (fp == 0) { | |||
| 76 | perror(filename); | |||
| 77 | _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename); | |||
| 78 | } | |||
| 79 | DEBUG(1, ("Created %s", filename)); | |||
| 80 | ||||
| 81 | if (write_object(tp, buffer, &offset, limit) == ERR(-1) | |||
| 82 | || fwrite(buffer, sizeof(char), offset, fp) != offset) { | |||
| 83 | _nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename); | |||
| 84 | } | |||
| 85 | ||||
| 86 | fclose(fp); | |||
| 87 | } | |||
| 88 | ||||
| 89 | /* | |||
| 90 | * Check for access rights to destination directories | |||
| 91 | * Create any directories which don't exist. | |||
| 92 | * | |||
| 93 | * Note: there's no reason to return the result of make_db_root(), since | |||
| 94 | * this function is called only in instances where that has to succeed. | |||
| 95 | */ | |||
| 96 | static void | |||
| 97 | check_writeable(int code) | |||
| 98 | { | |||
| 99 | static const char dirnames[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |||
| 100 | static bool_Bool verified[sizeof(dirnames)]; | |||
| 101 | ||||
| 102 | char dir[sizeof(LEAF_FMT"%c")]; | |||
| 103 | char *s = 0; | |||
| 104 | ||||
| 105 | if (code == 0 || (s = strchr(dirnames, code)) == 0) | |||
| 106 | _nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT"%c" "\"", code); | |||
| 107 | ||||
| 108 | if (verified[s - dirnames]) | |||
| 109 | return; | |||
| 110 | ||||
| 111 | snprintf(dir, sizeof(dir), LEAF_FMT"%c", code); | |||
| 112 | if (make_db_root(dir) < 0) { | |||
| 113 | _nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir); | |||
| 114 | } | |||
| 115 | ||||
| 116 | verified[s - dirnames] = TRUE1; | |||
| 117 | } | |||
| 118 | #endif /* !USE_HASHED_DB */ | |||
| 119 | ||||
| 120 | static int | |||
| 121 | make_db_path(char *dst, const char *src, unsigned limit) | |||
| 122 | { | |||
| 123 | int rc = -1; | |||
| 124 | const char *top = _nc_tic_dir(0); | |||
| 125 | ||||
| 126 | if (src == top || _nc_is_abs_path(src)) { | |||
| 127 | if (strlen(src) + 1 <= limit) { | |||
| 128 | (void) strlcpy(dst, src, limit); | |||
| 129 | rc = 0; | |||
| 130 | } | |||
| 131 | } else { | |||
| 132 | if (strlen(top) + strlen(src) + 2 <= limit) { | |||
| 133 | (void) snprintf(dst, limit, "%s/%s", top, src); | |||
| 134 | rc = 0; | |||
| 135 | } | |||
| 136 | } | |||
| 137 | #if USE_HASHED_DB0 | |||
| 138 | if (rc == 0) { | |||
| 139 | if (_nc_is_dir_path(dst)) { | |||
| 140 | rc = -1; | |||
| 141 | } else { | |||
| 142 | unsigned have = strlen(dst); | |||
| 143 | if (have > 3 && strcmp(dst + have - 3, DBM_SUFFIX)) { | |||
| 144 | if (have + 3 <= limit) | |||
| 145 | strlcat(dst, DBM_SUFFIX, limit); | |||
| 146 | else | |||
| 147 | rc = -1; | |||
| 148 | } | |||
| 149 | } | |||
| 150 | } | |||
| 151 | #endif | |||
| 152 | return rc; | |||
| 153 | } | |||
| 154 | ||||
| 155 | /* | |||
| 156 | * Make a database-root if it doesn't exist. | |||
| 157 | */ | |||
| 158 | static int | |||
| 159 | make_db_root(const char *path) | |||
| 160 | { | |||
| 161 | int rc; | |||
| 162 | char fullpath[PATH_MAX1024]; | |||
| 163 | ||||
| 164 | if ((rc = make_db_path(fullpath, path, sizeof(fullpath))) == 0) { | |||
| 165 | #if USE_HASHED_DB0 | |||
| 166 | DB *capdbp; | |||
| 167 | ||||
| 168 | if ((capdbp = _nc_db_open(fullpath, TRUE1)) == NULL((void*)0)) | |||
| 169 | rc = -1; | |||
| 170 | else if (_nc_db_close(capdbp) < 0) | |||
| 171 | rc = -1; | |||
| 172 | #else | |||
| 173 | struct stat statbuf; | |||
| 174 | ||||
| 175 | if ((rc = stat(path, &statbuf)) < 0) { | |||
| 176 | rc = mkdir(path, 0777); | |||
| 177 | } else if (_nc_access(path, R_OK0x04 | W_OK0x02 | X_OK0x01) < 0) { | |||
| 178 | rc = -1; /* permission denied */ | |||
| 179 | } else if (!(S_ISDIR(statbuf.st_mode)((statbuf.st_mode & 0170000) == 0040000))) { | |||
| 180 | rc = -1; /* not a directory */ | |||
| 181 | } | |||
| 182 | #endif | |||
| 183 | } | |||
| 184 | return rc; | |||
| 185 | } | |||
| 186 | ||||
| 187 | /* | |||
| 188 | * Set the write directory for compiled entries. | |||
| 189 | */ | |||
| 190 | NCURSES_EXPORT(void)void | |||
| 191 | _nc_set_writedir(char *dir) | |||
| 192 | { | |||
| 193 | const char *destination; | |||
| 194 | char actual[PATH_MAX1024]; | |||
| 195 | ||||
| 196 | if (dir == 0 | |||
| ||||
| 197 | && use_terminfo_vars()(!issetugid())) | |||
| 198 | dir = getenv("TERMINFO"); | |||
| 199 | ||||
| 200 | if (dir
| |||
| 201 | (void) _nc_tic_dir(dir); | |||
| 202 | ||||
| 203 | destination = _nc_tic_dir(0); | |||
| 204 | if (make_db_root(destination) < 0) { | |||
| 205 | char *home = _nc_home_terminfo(); | |||
| 206 | ||||
| 207 | if (home != 0) { | |||
| 208 | destination = home; | |||
| 209 | if (make_db_root(destination) < 0) | |||
| 210 | _nc_err_abort("%s: permission denied (errno %d)", | |||
| 211 | destination, errno(*__errno())); | |||
| 212 | } | |||
| 213 | } | |||
| 214 | ||||
| 215 | /* | |||
| 216 | * Note: because of this code, this logic should be exercised | |||
| 217 | * *once only* per run. | |||
| 218 | */ | |||
| 219 | #if USE_HASHED_DB0 | |||
| 220 | make_db_path(actual, destination, sizeof(actual)); | |||
| 221 | #else | |||
| 222 | if (chdir(_nc_tic_dir(destination)) < 0 | |||
| 223 | || getcwd(actual, sizeof(actual)) == 0) | |||
| 224 | _nc_err_abort("%s: not a directory", destination); | |||
| 225 | #endif | |||
| 226 | _nc_keep_tic_dir(strdup(actual)); | |||
| 227 | } | |||
| ||||
| 228 | ||||
| 229 | /* | |||
| 230 | * Save the compiled version of a description in the filesystem. | |||
| 231 | * | |||
| 232 | * make a copy of the name-list | |||
| 233 | * break it up into first-name and all-but-last-name | |||
| 234 | * creat(first-name) | |||
| 235 | * write object information to first-name | |||
| 236 | * close(first-name) | |||
| 237 | * for each name in all-but-last-name | |||
| 238 | * link to first-name | |||
| 239 | * | |||
| 240 | * Using 'time()' to obtain a reference for file timestamps is unreliable, | |||
| 241 | * e.g., with NFS, because the filesystem may have a different time | |||
| 242 | * reference. We check for pre-existence of links by latching the first | |||
| 243 | * timestamp from a file that we create. | |||
| 244 | * | |||
| 245 | * The _nc_warning() calls will report a correct line number only if | |||
| 246 | * _nc_curr_line is properly set before the write_entry() call. | |||
| 247 | */ | |||
| 248 | ||||
| 249 | NCURSES_EXPORT(void)void | |||
| 250 | _nc_write_entry(TERMTYPE *const tp) | |||
| 251 | { | |||
| 252 | #if USE_HASHED_DB0 | |||
| 253 | ||||
| 254 | char buffer[MAX_ENTRY_SIZE4096 + 1]; | |||
| 255 | unsigned limit = sizeof(buffer); | |||
| 256 | unsigned offset = 0; | |||
| 257 | ||||
| 258 | #else /* !USE_HASHED_DB */ | |||
| 259 | ||||
| 260 | struct stat statbuf; | |||
| 261 | char filename[PATH_MAX1024]; | |||
| 262 | char linkname[PATH_MAX1024]; | |||
| 263 | #if USE_SYMLINKS0 | |||
| 264 | char symlinkname[PATH_MAX1024]; | |||
| 265 | #if !HAVE_LINK1 | |||
| 266 | #undef HAVE_LINK1 | |||
| 267 | #define HAVE_LINK1 1 | |||
| 268 | #endif | |||
| 269 | #endif /* USE_SYMLINKS */ | |||
| 270 | ||||
| 271 | static int call_count; | |||
| 272 | static time_t start_time; /* time at start of writes */ | |||
| 273 | ||||
| 274 | #endif /* USE_HASHED_DB */ | |||
| 275 | ||||
| 276 | char name_list[MAX_TERMINFO_LENGTH4096]; | |||
| 277 | char *first_name, *other_names; | |||
| 278 | char *ptr; | |||
| 279 | ||||
| 280 | assert(strlen(tp->term_names) != 0)((void)0); | |||
| 281 | assert(strlen(tp->term_names) < sizeof(name_list))((void)0); | |||
| 282 | ||||
| 283 | (void) strlcpy(name_list, tp->term_names, sizeof(name_list)); | |||
| 284 | DEBUG(7, ("Name list = '%s'", name_list)); | |||
| 285 | ||||
| 286 | first_name = name_list; | |||
| 287 | ||||
| 288 | ptr = &name_list[strlen(name_list) - 1]; | |||
| 289 | other_names = ptr + 1; | |||
| 290 | ||||
| 291 | while (ptr > name_list && *ptr != '|') | |||
| 292 | ptr--; | |||
| 293 | ||||
| 294 | if (ptr != name_list) { | |||
| 295 | *ptr = '\0'; | |||
| 296 | ||||
| 297 | for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++) | |||
| 298 | continue; | |||
| 299 | ||||
| 300 | if (*ptr == '\0') | |||
| 301 | other_names = ptr; | |||
| 302 | else { | |||
| 303 | *ptr = '\0'; | |||
| 304 | other_names = ptr + 1; | |||
| 305 | } | |||
| 306 | } | |||
| 307 | ||||
| 308 | DEBUG(7, ("First name = '%s'", first_name)); | |||
| 309 | DEBUG(7, ("Other names = '%s'", other_names)); | |||
| 310 | ||||
| 311 | _nc_set_type(first_name); | |||
| 312 | ||||
| 313 | #if USE_HASHED_DB0 | |||
| 314 | if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR(-1)) { | |||
| 315 | DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE1); | |||
| 316 | DBT key, data; | |||
| 317 | ||||
| 318 | if (capdb != 0) { | |||
| 319 | buffer[0] = 0; | |||
| 320 | ||||
| 321 | memset(&key, 0, sizeof(key)); | |||
| 322 | key.data = tp->term_names; | |||
| 323 | key.size = strlen(tp->term_names); | |||
| 324 | ||||
| 325 | memset(&data, 0, sizeof(data)); | |||
| 326 | data.data = buffer; | |||
| 327 | data.size = offset + 1; | |||
| 328 | ||||
| 329 | _nc_db_put(capdb, &key, &data); | |||
| 330 | ||||
| 331 | buffer[0] = 2; | |||
| 332 | ||||
| 333 | key.data = name_list; | |||
| 334 | key.size = strlen(name_list); | |||
| 335 | ||||
| 336 | strlcpy(buffer + 1, tp->term_names, sizeof(buffer) - 1); | |||
| 337 | data.size = strlen(tp->term_names) + 1; | |||
| 338 | ||||
| 339 | _nc_db_put(capdb, &key, &data); | |||
| 340 | ||||
| 341 | while (*other_names != '\0') { | |||
| 342 | ptr = other_names++; | |||
| 343 | while (*other_names != '|' && *other_names != '\0') | |||
| 344 | other_names++; | |||
| 345 | ||||
| 346 | if (*other_names != '\0') | |||
| 347 | *(other_names++) = '\0'; | |||
| 348 | ||||
| 349 | key.data = ptr; | |||
| 350 | key.size = strlen(ptr); | |||
| 351 | ||||
| 352 | _nc_db_put(capdb, &key, &data); | |||
| 353 | } | |||
| 354 | _nc_db_close(capdb); | |||
| 355 | } | |||
| 356 | } | |||
| 357 | #else /* !USE_HASHED_DB */ | |||
| 358 | if (call_count++ == 0) { | |||
| 359 | start_time = 0; | |||
| 360 | } | |||
| 361 | ||||
| 362 | if (strlen(first_name) >= sizeof(filename) - 3) | |||
| 363 | _nc_warning("terminal name too long."); | |||
| 364 | ||||
| 365 | snprintf(filename, sizeof(filename), LEAF_FMT"%c" "/%s", first_name[0], first_name); | |||
| 366 | ||||
| 367 | /* | |||
| 368 | * Has this primary name been written since the first call to | |||
| 369 | * write_entry()? If so, the newer write will step on the older, | |||
| 370 | * so warn the user. | |||
| 371 | */ | |||
| 372 | if (start_time > 0 && | |||
| 373 | stat(filename, &statbuf) >= 0 | |||
| 374 | && statbuf.st_mtimest_mtim.tv_sec >= start_time) { | |||
| 375 | _nc_warning("name multiply defined."); | |||
| 376 | } | |||
| 377 | ||||
| 378 | check_writeable(first_name[0]); | |||
| 379 | write_file(filename, tp); | |||
| 380 | ||||
| 381 | if (start_time == 0) { | |||
| 382 | if (stat(filename, &statbuf) < 0 | |||
| 383 | || (start_time = statbuf.st_mtimest_mtim.tv_sec) == 0) { | |||
| 384 | _nc_syserr_abort("error obtaining time from %s/%s", | |||
| 385 | _nc_tic_dir(0), filename); | |||
| 386 | } | |||
| 387 | } | |||
| 388 | while (*other_names != '\0') { | |||
| 389 | ptr = other_names++; | |||
| 390 | assert(ptr < buffer + sizeof(buffer) - 1)((void)0); | |||
| 391 | while (*other_names != '|' && *other_names != '\0') | |||
| 392 | other_names++; | |||
| 393 | ||||
| 394 | if (*other_names != '\0') | |||
| 395 | *(other_names++) = '\0'; | |||
| 396 | ||||
| 397 | if (strlen(ptr) > sizeof(linkname) - 3) { | |||
| 398 | _nc_warning("terminal alias %s too long.", ptr); | |||
| 399 | continue; | |||
| 400 | } | |||
| 401 | if (strchr(ptr, '/') != 0) { | |||
| 402 | _nc_warning("cannot link alias %s.", ptr); | |||
| 403 | continue; | |||
| 404 | } | |||
| 405 | ||||
| 406 | check_writeable(ptr[0]); | |||
| 407 | snprintf(linkname, sizeof(linkname), LEAF_FMT"%c" "/%s", ptr[0], ptr); | |||
| 408 | ||||
| 409 | if (strcmp(filename, linkname) == 0) { | |||
| 410 | _nc_warning("self-synonym ignored"); | |||
| 411 | } else if (stat(linkname, &statbuf) >= 0 && | |||
| 412 | statbuf.st_mtimest_mtim.tv_sec < start_time) { | |||
| 413 | _nc_warning("alias %s multiply defined.", ptr); | |||
| 414 | } else if (_nc_access(linkname, W_OK0x02) == 0) | |||
| 415 | #if HAVE_LINK1 | |||
| 416 | { | |||
| 417 | int code; | |||
| 418 | #if USE_SYMLINKS0 | |||
| 419 | strlcpy(symlinkname, "../", sizeof(symlinkname)); | |||
| 420 | strlcat(symlinkname, filename, sizeof(symlinkname)); | |||
| 421 | #endif /* USE_SYMLINKS */ | |||
| 422 | #if HAVE_REMOVE1 | |||
| 423 | code = remove(linkname); | |||
| 424 | #else | |||
| 425 | code = unlink(linkname); | |||
| 426 | #endif | |||
| 427 | if (code != 0 && errno(*__errno()) == ENOENT2) | |||
| 428 | code = 0; | |||
| 429 | #if USE_SYMLINKS0 | |||
| 430 | if (symlink(symlinkname, linkname) < 0) | |||
| 431 | #else | |||
| 432 | if (link(filename, linkname) < 0) | |||
| 433 | #endif /* USE_SYMLINKS */ | |||
| 434 | { | |||
| 435 | /* | |||
| 436 | * If there wasn't anything there, and we cannot | |||
| 437 | * link to the target because it is the same as the | |||
| 438 | * target, then the source must be on a filesystem | |||
| 439 | * that uses caseless filenames, such as Win32, etc. | |||
| 440 | */ | |||
| 441 | if (code == 0 && errno(*__errno()) == EEXIST17) | |||
| 442 | _nc_warning("can't link %s to %s", filename, linkname); | |||
| 443 | else if (code == 0 && (errno(*__errno()) == EPERM1 || errno(*__errno()) == ENOENT2)) | |||
| 444 | write_file(linkname, tp); | |||
| 445 | else { | |||
| 446 | #if MIXEDCASE_FILENAMES1 | |||
| 447 | _nc_syserr_abort("can't link %s to %s", filename, linkname); | |||
| 448 | #else | |||
| 449 | _nc_warning("can't link %s to %s (errno=%d)", filename, | |||
| 450 | linkname, errno(*__errno())); | |||
| 451 | #endif | |||
| 452 | } | |||
| 453 | } else { | |||
| 454 | DEBUG(1, ("Linked %s", linkname)); | |||
| 455 | } | |||
| 456 | } | |||
| 457 | #else /* just make copies */ | |||
| 458 | write_file(linkname, tp); | |||
| 459 | #endif /* HAVE_LINK */ | |||
| 460 | } | |||
| 461 | #endif /* USE_HASHED_DB */ | |||
| 462 | } | |||
| 463 | ||||
| 464 | static unsigned | |||
| 465 | fake_write(char *dst, | |||
| 466 | unsigned *offset, | |||
| 467 | unsigned limit, | |||
| 468 | char *src, | |||
| 469 | unsigned want, | |||
| 470 | unsigned size) | |||
| 471 | { | |||
| 472 | int have = (limit - *offset); | |||
| 473 | ||||
| 474 | want *= size; | |||
| 475 | if (have > 0) { | |||
| 476 | if ((int) want > have) | |||
| 477 | want = have; | |||
| 478 | memcpy(dst + *offset, src, want); | |||
| 479 | *offset += want; | |||
| 480 | } else { | |||
| 481 | want = 0; | |||
| 482 | } | |||
| 483 | return (int) (want / size); | |||
| 484 | } | |||
| 485 | ||||
| 486 | #define Write(buf, size, count)fake_write(buffer, offset, limit, (char *) buf, count, size) fake_write(buffer, offset, limit, (char *) buf, count, size) | |||
| 487 | ||||
| 488 | #undef LITTLE_ENDIAN /* BSD/OS defines this as a feature macro */ | |||
| 489 | #define HI(x)((x) / 256) ((x) / 256) | |||
| 490 | #define LO(x)((x) % 256) ((x) % 256) | |||
| 491 | #define LITTLE_ENDIAN(p, x)(p)[0] = ((x) % 256), (p)[1] = ((x) / 256) (p)[0] = LO(x)((x) % 256), (p)[1] = HI(x)((x) / 256) | |||
| 492 | ||||
| 493 | #define WRITE_STRING(str)(fake_write(buffer, offset, limit, (char *) str, strlen(str) + 1, sizeof(char)) == strlen(str) + 1) (Write(str, sizeof(char), strlen(str) + 1)fake_write(buffer, offset, limit, (char *) str, strlen(str) + 1, sizeof(char)) == strlen(str) + 1) | |||
| 494 | ||||
| 495 | static int | |||
| 496 | compute_offsets(char **Strings, unsigned strmax, short *offsets) | |||
| 497 | { | |||
| 498 | size_t nextfree = 0; | |||
| 499 | unsigned i; | |||
| 500 | ||||
| 501 | for (i = 0; i < strmax; i++) { | |||
| 502 | if (Strings[i] == ABSENT_STRING(char *)0) { | |||
| 503 | offsets[i] = -1; | |||
| 504 | } else if (Strings[i] == CANCELLED_STRING(char *)(-1)) { | |||
| 505 | offsets[i] = -2; | |||
| 506 | } else { | |||
| 507 | offsets[i] = nextfree; | |||
| 508 | nextfree += strlen(Strings[i]) + 1; | |||
| 509 | TRACE_OUT(("put Strings[%d]=%s(%d)", (int) i, | |||
| 510 | _nc_visbuf(Strings[i]), (int) nextfree)); | |||
| 511 | } | |||
| 512 | } | |||
| 513 | return nextfree; | |||
| 514 | } | |||
| 515 | ||||
| 516 | static void | |||
| 517 | convert_shorts(unsigned char *buf, short *Numbers, unsigned count) | |||
| 518 | { | |||
| 519 | unsigned i; | |||
| 520 | for (i = 0; i < count; i++) { | |||
| 521 | if (Numbers[i] == ABSENT_NUMERIC(-1)) { /* HI/LO won't work */ | |||
| 522 | buf[2 * i] = buf[2 * i + 1] = 0377; | |||
| 523 | } else if (Numbers[i] == CANCELLED_NUMERIC(-2)) { /* HI/LO won't work */ | |||
| 524 | buf[2 * i] = 0376; | |||
| 525 | buf[2 * i + 1] = 0377; | |||
| 526 | } else { | |||
| 527 | LITTLE_ENDIAN(buf + 2 * i, Numbers[i])(buf + 2 * i)[0] = ((Numbers[i]) % 256), (buf + 2 * i)[1] = ( (Numbers[i]) / 256); | |||
| 528 | TRACE_OUT(("put Numbers[%d]=%d", i, Numbers[i])); | |||
| 529 | } | |||
| 530 | } | |||
| 531 | } | |||
| 532 | ||||
| 533 | #define even_boundary(value)((value) % 2 != 0 && fake_write(buffer, offset, limit , (char *) &zero, 1, sizeof(char)) != 1) \ | |||
| 534 | ((value) % 2 != 0 && Write(&zero, sizeof(char), 1)fake_write(buffer, offset, limit, (char *) &zero, 1, sizeof (char)) != 1) | |||
| 535 | ||||
| 536 | #if NCURSES_XNAMES1 | |||
| 537 | static unsigned | |||
| 538 | extended_Booleans(TERMTYPE *tp) | |||
| 539 | { | |||
| 540 | unsigned short result = 0; | |||
| 541 | unsigned short i; | |||
| 542 | ||||
| 543 | for (i = 0; i < tp->ext_Booleans; ++i) { | |||
| 544 | if (tp->Booleans[BOOLCOUNT44 + i] == TRUE1) | |||
| 545 | result = (i + 1); | |||
| 546 | } | |||
| 547 | return result; | |||
| 548 | } | |||
| 549 | ||||
| 550 | static unsigned | |||
| 551 | extended_Numbers(TERMTYPE *tp) | |||
| 552 | { | |||
| 553 | unsigned short result = 0; | |||
| 554 | unsigned short i; | |||
| 555 | ||||
| 556 | for (i = 0; i < tp->ext_Numbers; ++i) { | |||
| 557 | if (tp->Numbers[NUMCOUNT39 + i] != ABSENT_NUMERIC(-1)) | |||
| 558 | result = (i + 1); | |||
| 559 | } | |||
| 560 | return result; | |||
| 561 | } | |||
| 562 | ||||
| 563 | static unsigned | |||
| 564 | extended_Strings(TERMTYPE *tp) | |||
| 565 | { | |||
| 566 | unsigned short result = 0; | |||
| 567 | unsigned short i; | |||
| 568 | ||||
| 569 | for (i = 0; i < tp->ext_Strings; ++i) { | |||
| 570 | if (tp->Strings[STRCOUNT414 + i] != ABSENT_STRING(char *)0) | |||
| 571 | result = (i + 1); | |||
| 572 | } | |||
| 573 | return result; | |||
| 574 | } | |||
| 575 | ||||
| 576 | /* | |||
| 577 | * _nc_align_termtype() will extend entries that are referenced in a use= | |||
| 578 | * clause - discard the unneeded data. | |||
| 579 | */ | |||
| 580 | static bool_Bool | |||
| 581 | extended_object(TERMTYPE *tp) | |||
| 582 | { | |||
| 583 | bool_Bool result = FALSE0; | |||
| 584 | ||||
| 585 | if (_nc_user_definable) { | |||
| 586 | result = ((extended_Booleans(tp) | |||
| 587 | + extended_Numbers(tp) | |||
| 588 | + extended_Strings(tp)) != 0); | |||
| 589 | } | |||
| 590 | return result; | |||
| 591 | } | |||
| 592 | #endif | |||
| 593 | ||||
| 594 | static int | |||
| 595 | write_object(TERMTYPE *tp, char *buffer, unsigned *offset, unsigned limit) | |||
| 596 | { | |||
| 597 | char *namelist; | |||
| 598 | size_t namelen, boolmax, nummax, strmax; | |||
| 599 | char zero = '\0'; | |||
| 600 | size_t i; | |||
| 601 | short nextfree; | |||
| 602 | short offsets[MAX_ENTRY_SIZE4096 / 2]; | |||
| 603 | unsigned char buf[MAX_ENTRY_SIZE4096]; | |||
| 604 | unsigned last_bool = BOOLWRITE37; | |||
| 605 | unsigned last_num = NUMWRITE33; | |||
| 606 | unsigned last_str = STRWRITE394; | |||
| 607 | ||||
| 608 | #if NCURSES_XNAMES1 | |||
| 609 | /* | |||
| 610 | * Normally we limit the list of values to exclude the "obsolete" | |||
| 611 | * capabilities. However, if we are accepting extended names, add | |||
| 612 | * these as well, since they are used for supporting translation | |||
| 613 | * to/from termcap. | |||
| 614 | */ | |||
| 615 | if (_nc_user_definable) { | |||
| 616 | last_bool = BOOLCOUNT44; | |||
| 617 | last_num = NUMCOUNT39; | |||
| 618 | last_str = STRCOUNT414; | |||
| 619 | } | |||
| 620 | #endif | |||
| 621 | ||||
| 622 | namelist = tp->term_names; | |||
| 623 | namelen = strlen(namelist) + 1; | |||
| 624 | ||||
| 625 | boolmax = 0; | |||
| 626 | for (i = 0; i < last_bool; i++) { | |||
| 627 | if (tp->Booleans[i] == TRUE1) | |||
| 628 | boolmax = i + 1; | |||
| 629 | } | |||
| 630 | ||||
| 631 | nummax = 0; | |||
| 632 | for (i = 0; i < last_num; i++) { | |||
| 633 | if (tp->Numbers[i] != ABSENT_NUMERIC(-1)) | |||
| 634 | nummax = i + 1; | |||
| 635 | } | |||
| 636 | ||||
| 637 | strmax = 0; | |||
| 638 | for (i = 0; i < last_str; i++) { | |||
| 639 | if (tp->Strings[i] != ABSENT_STRING(char *)0) | |||
| 640 | strmax = i + 1; | |||
| 641 | } | |||
| 642 | ||||
| 643 | nextfree = compute_offsets(tp->Strings, strmax, offsets); | |||
| 644 | ||||
| 645 | /* fill in the header */ | |||
| 646 | LITTLE_ENDIAN(buf, MAGIC)(buf)[0] = ((0432) % 256), (buf)[1] = ((0432) / 256); | |||
| 647 | LITTLE_ENDIAN(buf + 2, min(namelen, MAX_NAME_SIZE + 1))(buf + 2)[0] = ((((namelen) > (512 + 1) ? (512 + 1) : (namelen ))) % 256), (buf + 2)[1] = ((((namelen) > (512 + 1) ? (512 + 1) : (namelen))) / 256); | |||
| 648 | LITTLE_ENDIAN(buf + 4, boolmax)(buf + 4)[0] = ((boolmax) % 256), (buf + 4)[1] = ((boolmax) / 256); | |||
| 649 | LITTLE_ENDIAN(buf + 6, nummax)(buf + 6)[0] = ((nummax) % 256), (buf + 6)[1] = ((nummax) / 256 ); | |||
| 650 | LITTLE_ENDIAN(buf + 8, strmax)(buf + 8)[0] = ((strmax) % 256), (buf + 8)[1] = ((strmax) / 256 ); | |||
| 651 | LITTLE_ENDIAN(buf + 10, nextfree)(buf + 10)[0] = ((nextfree) % 256), (buf + 10)[1] = ((nextfree ) / 256); | |||
| 652 | ||||
| 653 | /* write out the header */ | |||
| 654 | TRACE_OUT(("Header of %s @%d", namelist, *offset)); | |||
| 655 | if (Write(buf, 12, 1)fake_write(buffer, offset, limit, (char *) buf, 1, 12) != 1 | |||
| 656 | || Write(namelist, sizeof(char), namelen)fake_write(buffer, offset, limit, (char *) namelist, namelen, sizeof(char)) != namelen) | |||
| 657 | return (ERR(-1)); | |||
| 658 | ||||
| 659 | for (i = 0; i < boolmax; i++) | |||
| 660 | if (tp->Booleans[i] == TRUE1) | |||
| 661 | buf[i] = TRUE1; | |||
| 662 | else | |||
| 663 | buf[i] = FALSE0; | |||
| 664 | if (Write(buf, sizeof(char), boolmax)fake_write(buffer, offset, limit, (char *) buf, boolmax, sizeof (char)) != boolmax) | |||
| 665 | return (ERR(-1)); | |||
| 666 | ||||
| 667 | if (even_boundary(namelen + boolmax)((namelen + boolmax) % 2 != 0 && fake_write(buffer, offset , limit, (char *) &zero, 1, sizeof(char)) != 1)) | |||
| 668 | return (ERR(-1)); | |||
| 669 | ||||
| 670 | TRACE_OUT(("Numerics begin at %04x", *offset)); | |||
| 671 | ||||
| 672 | /* the numerics */ | |||
| 673 | convert_shorts(buf, tp->Numbers, nummax); | |||
| 674 | if (Write(buf, 2, nummax)fake_write(buffer, offset, limit, (char *) buf, nummax, 2) != nummax) | |||
| 675 | return (ERR(-1)); | |||
| 676 | ||||
| 677 | TRACE_OUT(("String offsets begin at %04x", *offset)); | |||
| 678 | ||||
| 679 | /* the string offsets */ | |||
| 680 | convert_shorts(buf, offsets, strmax); | |||
| 681 | if (Write(buf, 2, strmax)fake_write(buffer, offset, limit, (char *) buf, strmax, 2) != strmax) | |||
| 682 | return (ERR(-1)); | |||
| 683 | ||||
| 684 | TRACE_OUT(("String table begins at %04x", *offset)); | |||
| 685 | ||||
| 686 | /* the strings */ | |||
| 687 | for (i = 0; i < strmax; i++) | |||
| 688 | if (VALID_STRING(tp->Strings[i])((tp->Strings[i]) != (char *)(-1) && (tp->Strings [i]) != (char *)0)) | |||
| 689 | if (!WRITE_STRING(tp->Strings[i])(fake_write(buffer, offset, limit, (char *) tp->Strings[i] , strlen(tp->Strings[i]) + 1, sizeof(char)) == strlen(tp-> Strings[i]) + 1)) | |||
| 690 | return (ERR(-1)); | |||
| 691 | ||||
| 692 | #if NCURSES_XNAMES1 | |||
| 693 | if (extended_object(tp)) { | |||
| 694 | unsigned extcnt = NUM_EXT_NAMES(tp)((tp)->ext_Booleans + (tp)->ext_Numbers + (tp)->ext_Strings ); | |||
| 695 | ||||
| 696 | if (even_boundary(nextfree)((nextfree) % 2 != 0 && fake_write(buffer, offset, limit , (char *) &zero, 1, sizeof(char)) != 1)) | |||
| 697 | return (ERR(-1)); | |||
| 698 | ||||
| 699 | nextfree = compute_offsets(tp->Strings + STRCOUNT414, | |||
| 700 | tp->ext_Strings, | |||
| 701 | offsets); | |||
| 702 | TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree)); | |||
| 703 | ||||
| 704 | if (tp->ext_Strings >= SIZEOF(offsets)(sizeof(offsets)/sizeof(offsets[0]))) | |||
| 705 | return (ERR(-1)); | |||
| 706 | ||||
| 707 | nextfree += compute_offsets(tp->ext_Names, | |||
| 708 | extcnt, | |||
| 709 | offsets + tp->ext_Strings); | |||
| 710 | TRACE_OUT(("after extended capnames, nextfree=%d", nextfree)); | |||
| 711 | strmax = tp->ext_Strings + extcnt; | |||
| 712 | ||||
| 713 | /* | |||
| 714 | * Write the extended header | |||
| 715 | */ | |||
| 716 | LITTLE_ENDIAN(buf + 0, tp->ext_Booleans)(buf + 0)[0] = ((tp->ext_Booleans) % 256), (buf + 0)[1] = ( (tp->ext_Booleans) / 256); | |||
| 717 | LITTLE_ENDIAN(buf + 2, tp->ext_Numbers)(buf + 2)[0] = ((tp->ext_Numbers) % 256), (buf + 2)[1] = ( (tp->ext_Numbers) / 256); | |||
| 718 | LITTLE_ENDIAN(buf + 4, tp->ext_Strings)(buf + 4)[0] = ((tp->ext_Strings) % 256), (buf + 4)[1] = ( (tp->ext_Strings) / 256); | |||
| 719 | LITTLE_ENDIAN(buf + 6, strmax)(buf + 6)[0] = ((strmax) % 256), (buf + 6)[1] = ((strmax) / 256 ); | |||
| 720 | LITTLE_ENDIAN(buf + 8, nextfree)(buf + 8)[0] = ((nextfree) % 256), (buf + 8)[1] = ((nextfree) / 256); | |||
| 721 | TRACE_OUT(("WRITE extended-header @%d", *offset)); | |||
| 722 | if (Write(buf, 10, 1)fake_write(buffer, offset, limit, (char *) buf, 1, 10) != 1) | |||
| 723 | return (ERR(-1)); | |||
| 724 | ||||
| 725 | TRACE_OUT(("WRITE %d booleans @%d", tp->ext_Booleans, *offset)); | |||
| 726 | if (tp->ext_Booleans | |||
| 727 | && Write(tp->Booleans + BOOLCOUNT, sizeof(char),fake_write(buffer, offset, limit, (char *) tp->Booleans + 44 , tp->ext_Booleans, sizeof(char)) | |||
| 728 | tp->ext_Booleans)fake_write(buffer, offset, limit, (char *) tp->Booleans + 44 , tp->ext_Booleans, sizeof(char)) != tp->ext_Booleans) | |||
| 729 | return (ERR(-1)); | |||
| 730 | ||||
| 731 | if (even_boundary(tp->ext_Booleans)((tp->ext_Booleans) % 2 != 0 && fake_write(buffer, offset, limit, (char *) &zero, 1, sizeof(char)) != 1)) | |||
| 732 | return (ERR(-1)); | |||
| 733 | ||||
| 734 | TRACE_OUT(("WRITE %d numbers @%d", tp->ext_Numbers, *offset)); | |||
| 735 | if (tp->ext_Numbers) { | |||
| 736 | convert_shorts(buf, tp->Numbers + NUMCOUNT39, tp->ext_Numbers); | |||
| 737 | if (Write(buf, 2, tp->ext_Numbers)fake_write(buffer, offset, limit, (char *) buf, tp->ext_Numbers , 2) != tp->ext_Numbers) | |||
| 738 | return (ERR(-1)); | |||
| 739 | } | |||
| 740 | ||||
| 741 | /* | |||
| 742 | * Convert the offsets for the ext_Strings and ext_Names tables, | |||
| 743 | * in that order. | |||
| 744 | */ | |||
| 745 | convert_shorts(buf, offsets, strmax); | |||
| 746 | TRACE_OUT(("WRITE offsets @%d", *offset)); | |||
| 747 | if (Write(buf, 2, strmax)fake_write(buffer, offset, limit, (char *) buf, strmax, 2) != strmax) | |||
| 748 | return (ERR(-1)); | |||
| 749 | ||||
| 750 | /* | |||
| 751 | * Write the string table after the offset tables so we do not | |||
| 752 | * have to do anything about alignment. | |||
| 753 | */ | |||
| 754 | for (i = 0; i < tp->ext_Strings; i++) { | |||
| 755 | if (VALID_STRING(tp->Strings[i + STRCOUNT])((tp->Strings[i + 414]) != (char *)(-1) && (tp-> Strings[i + 414]) != (char *)0)) { | |||
| 756 | TRACE_OUT(("WRITE ext_Strings[%d]=%s", (int) i, | |||
| 757 | _nc_visbuf(tp->Strings[i + STRCOUNT]))); | |||
| 758 | if (!WRITE_STRING(tp->Strings[i + STRCOUNT])(fake_write(buffer, offset, limit, (char *) tp->Strings[i + 414], strlen(tp->Strings[i + 414]) + 1, sizeof(char)) == strlen (tp->Strings[i + 414]) + 1)) | |||
| 759 | return (ERR(-1)); | |||
| 760 | } | |||
| 761 | } | |||
| 762 | ||||
| 763 | /* | |||
| 764 | * Write the extended names | |||
| 765 | */ | |||
| 766 | for (i = 0; i < extcnt; i++) { | |||
| 767 | TRACE_OUT(("WRITE ext_Names[%d]=%s", (int) i, tp->ext_Names[i])); | |||
| 768 | if (!WRITE_STRING(tp->ext_Names[i])(fake_write(buffer, offset, limit, (char *) tp->ext_Names[ i], strlen(tp->ext_Names[i]) + 1, sizeof(char)) == strlen( tp->ext_Names[i]) + 1)) | |||
| 769 | return (ERR(-1)); | |||
| 770 | } | |||
| 771 | ||||
| 772 | } | |||
| 773 | #endif /* NCURSES_XNAMES */ | |||
| 774 | ||||
| 775 | total_written++; | |||
| 776 | return (OK(0)); | |||
| 777 | } | |||
| 778 | ||||
| 779 | /* | |||
| 780 | * Returns the total number of entries written by this process | |||
| 781 | */ | |||
| 782 | NCURSES_EXPORT(int)int | |||
| 783 | _nc_tic_written(void) | |||
| 784 | { | |||
| 785 | return total_written; | |||
| 786 | } |