150276Speter/**************************************************************************** 2184989Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 3150276Speter * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32166124Srafan * and: Thomas E. Dickey 1996-on * 3350276Speter ****************************************************************************/ 3450276Speter 3550276Speter/* 3650276Speter * write_entry.c -- write a terminfo structure onto the file system 3750276Speter */ 3850276Speter 3950276Speter#include <curses.priv.h> 40166124Srafan#include <hashed_db.h> 4150276Speter 4250276Speter#include <sys/stat.h> 4350276Speter 4450276Speter#include <tic.h> 4550276Speter#include <term_entry.h> 4650276Speter 4750276Speter#ifndef S_ISDIR 4850276Speter#define S_ISDIR(mode) ((mode & S_IFMT) == S_IFDIR) 4950276Speter#endif 5050276Speter 51166124Srafan#if 1 5250276Speter#define TRACE_OUT(p) DEBUG(2, p) 5350276Speter#else 5462449Speter#define TRACE_OUT(p) /*nothing */ 5550276Speter#endif 5650276Speter 57184989SrafanMODULE_ID("$Id: write_entry.c,v 1.72 2008/08/03 19:24:00 tom Exp $") 5850276Speter 5950276Speterstatic int total_written; 6050276Speter 61166124Srafanstatic int make_db_root(const char *); 62166124Srafanstatic int write_object(TERMTYPE *, char *, unsigned *, unsigned); 6350276Speter 64166124Srafan#if !USE_HASHED_DB 6562449Speterstatic void 66166124Srafanwrite_file(char *filename, TERMTYPE *tp) 6750276Speter{ 68166124Srafan char buffer[MAX_ENTRY_SIZE]; 69166124Srafan unsigned limit = sizeof(buffer); 70166124Srafan unsigned offset = 0; 71166124Srafan 7262449Speter FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0; 7362449Speter if (fp == 0) { 7462449Speter perror(filename); 7562449Speter _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename); 7662449Speter } 7762449Speter DEBUG(1, ("Created %s", filename)); 7850276Speter 79166124Srafan if (write_object(tp, buffer, &offset, limit) == ERR 80166124Srafan || fwrite(buffer, sizeof(char), offset, fp) != offset) { 8162449Speter _nc_syserr_abort("error writing %s/%s", _nc_tic_dir(0), filename); 8262449Speter } 83166124Srafan 8462449Speter fclose(fp); 8550276Speter} 8650276Speter 8750276Speter/* 88166124Srafan * Check for access rights to destination directories 89166124Srafan * Create any directories which don't exist. 9050276Speter * 91166124Srafan * Note: there's no reason to return the result of make_db_root(), since 92166124Srafan * this function is called only in instances where that has to succeed. 9350276Speter */ 94166124Srafanstatic void 95166124Srafancheck_writeable(int code) 96166124Srafan{ 97166124Srafan static const char dirnames[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; 98166124Srafan static bool verified[sizeof(dirnames)]; 99166124Srafan 100174993Srafan char dir[sizeof(LEAF_FMT)]; 101166124Srafan char *s = 0; 102166124Srafan 103166124Srafan if (code == 0 || (s = strchr(dirnames, code)) == 0) 104174993Srafan _nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT "\"", code); 105166124Srafan 106166124Srafan if (verified[s - dirnames]) 107166124Srafan return; 108166124Srafan 109174993Srafan sprintf(dir, LEAF_FMT, code); 110166124Srafan if (make_db_root(dir) < 0) { 111166124Srafan _nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir); 112166124Srafan } 113166124Srafan 114166124Srafan verified[s - dirnames] = TRUE; 115166124Srafan} 116166124Srafan#endif /* !USE_HASHED_DB */ 117166124Srafan 11862449Speterstatic int 119166124Srafanmake_db_path(char *dst, const char *src, unsigned limit) 12050276Speter{ 121166124Srafan int rc = -1; 122166124Srafan const char *top = _nc_tic_dir(0); 12350276Speter 124166124Srafan if (src == top || _nc_is_abs_path(src)) { 125166124Srafan if (strlen(src) + 1 <= limit) { 126166124Srafan (void) strcpy(dst, src); 127166124Srafan rc = 0; 128166124Srafan } 12962449Speter } else { 130166124Srafan if (strlen(top) + strlen(src) + 2 <= limit) { 131166124Srafan (void) sprintf(dst, "%s/%s", top, src); 132166124Srafan rc = 0; 133166124Srafan } 13462449Speter } 135166124Srafan#if USE_HASHED_DB 136166124Srafan if (rc == 0) { 137166124Srafan if (_nc_is_dir_path(dst)) { 138166124Srafan rc = -1; 139166124Srafan } else { 140166124Srafan unsigned have = strlen(dst); 141166124Srafan if (have > 3 && strcmp(dst + have - 3, DBM_SUFFIX)) { 142166124Srafan if (have + 3 <= limit) 143166124Srafan strcat(dst, DBM_SUFFIX); 144166124Srafan else 145166124Srafan rc = -1; 146166124Srafan } 147166124Srafan } 148166124Srafan } 149166124Srafan#endif 150166124Srafan return rc; 151166124Srafan} 15250276Speter 153166124Srafan/* 154166124Srafan * Make a database-root if it doesn't exist. 155166124Srafan */ 156166124Srafanstatic int 157166124Srafanmake_db_root(const char *path) 158166124Srafan{ 159166124Srafan int rc; 160166124Srafan char fullpath[PATH_MAX]; 161166124Srafan 162166124Srafan if ((rc = make_db_path(fullpath, path, sizeof(fullpath))) == 0) { 163166124Srafan#if USE_HASHED_DB 164166124Srafan DB *capdbp; 165166124Srafan 166166124Srafan if ((capdbp = _nc_db_open(fullpath, TRUE)) == NULL) 167166124Srafan rc = -1; 168166124Srafan else if (_nc_db_close(capdbp) < 0) 169166124Srafan rc = -1; 170166124Srafan#else 171166124Srafan struct stat statbuf; 172166124Srafan 173166124Srafan if ((rc = stat(path, &statbuf)) < 0) { 174166124Srafan rc = mkdir(path, 0777); 175166124Srafan } else if (_nc_access(path, R_OK | W_OK | X_OK) < 0) { 17662449Speter rc = -1; /* permission denied */ 17762449Speter } else if (!(S_ISDIR(statbuf.st_mode))) { 17862449Speter rc = -1; /* not a directory */ 17950276Speter } 180166124Srafan#endif 18162449Speter } 18262449Speter return rc; 18350276Speter} 18450276Speter 185166124Srafan/* 186166124Srafan * Set the write directory for compiled entries. 187166124Srafan */ 18876726SpeterNCURSES_EXPORT(void) 18962449Speter_nc_set_writedir(char *dir) 19050276Speter{ 19150276Speter const char *destination; 19250276Speter char actual[PATH_MAX]; 19350276Speter 19466963Speter if (dir == 0 19576726Speter && use_terminfo_vars()) 19666963Speter dir = getenv("TERMINFO"); 19766963Speter 19850276Speter if (dir != 0) 19950276Speter (void) _nc_tic_dir(dir); 20050276Speter 20150276Speter destination = _nc_tic_dir(0); 202166124Srafan if (make_db_root(destination) < 0) { 20362449Speter char *home = _nc_home_terminfo(); 20450276Speter 20550276Speter if (home != 0) { 20650276Speter destination = home; 207166124Srafan if (make_db_root(destination) < 0) 20850276Speter _nc_err_abort("%s: permission denied (errno %d)", 20976726Speter destination, errno); 21050276Speter } 21150276Speter } 21250276Speter 21350276Speter /* 21450276Speter * Note: because of this code, this logic should be exercised 21550276Speter * *once only* per run. 21650276Speter */ 217166124Srafan#if USE_HASHED_DB 218166124Srafan make_db_path(actual, destination, sizeof(actual)); 219166124Srafan#else 22050276Speter if (chdir(_nc_tic_dir(destination)) < 0 22162449Speter || getcwd(actual, sizeof(actual)) == 0) 22250276Speter _nc_err_abort("%s: not a directory", destination); 223166124Srafan#endif 22450276Speter _nc_keep_tic_dir(strdup(actual)); 22550276Speter} 22650276Speter 22750276Speter/* 22850276Speter * Save the compiled version of a description in the filesystem. 22950276Speter * 23050276Speter * make a copy of the name-list 23150276Speter * break it up into first-name and all-but-last-name 23250276Speter * creat(first-name) 23350276Speter * write object information to first-name 23450276Speter * close(first-name) 23550276Speter * for each name in all-but-last-name 23650276Speter * link to first-name 23750276Speter * 23850276Speter * Using 'time()' to obtain a reference for file timestamps is unreliable, 23950276Speter * e.g., with NFS, because the filesystem may have a different time 24050276Speter * reference. We check for pre-existence of links by latching the first 24150276Speter * timestamp from a file that we create. 24250276Speter * 24350276Speter * The _nc_warning() calls will report a correct line number only if 24450276Speter * _nc_curr_line is properly set before the write_entry() call. 24550276Speter */ 24650276Speter 247166124SrafanNCURSES_EXPORT(void) 248166124Srafan_nc_write_entry(TERMTYPE *const tp) 24950276Speter{ 250166124Srafan#if USE_HASHED_DB 251166124Srafan 252166124Srafan char buffer[MAX_ENTRY_SIZE + 1]; 253166124Srafan unsigned limit = sizeof(buffer); 254166124Srafan unsigned offset = 0; 255166124Srafan 256166124Srafan#else /* !USE_HASHED_DB */ 257166124Srafan 25862449Speter struct stat statbuf; 25962449Speter char filename[PATH_MAX]; 26062449Speter char linkname[PATH_MAX]; 26150276Speter#if USE_SYMLINKS 26262449Speter char symlinkname[PATH_MAX]; 26397049Speter#if !HAVE_LINK 26497049Speter#undef HAVE_LINK 26597049Speter#define HAVE_LINK 1 26697049Speter#endif 26750276Speter#endif /* USE_SYMLINKS */ 268166124Srafan 26962449Speter static int call_count; 27062449Speter static time_t start_time; /* time at start of writes */ 27150276Speter 272166124Srafan#endif /* USE_HASHED_DB */ 27350276Speter 274166124Srafan char name_list[MAX_TERMINFO_LENGTH]; 275166124Srafan char *first_name, *other_names; 276166124Srafan char *ptr; 277166124Srafan 278184989Srafan assert(strlen(tp->term_names) != 0); 279184989Srafan assert(strlen(tp->term_names) < sizeof(name_list)); 280184989Srafan 28162449Speter (void) strcpy(name_list, tp->term_names); 28262449Speter DEBUG(7, ("Name list = '%s'", name_list)); 28350276Speter 28462449Speter first_name = name_list; 28550276Speter 28662449Speter ptr = &name_list[strlen(name_list) - 1]; 28762449Speter other_names = ptr + 1; 28850276Speter 28962449Speter while (ptr > name_list && *ptr != '|') 29062449Speter ptr--; 29150276Speter 29262449Speter if (ptr != name_list) { 29362449Speter *ptr = '\0'; 29450276Speter 29562449Speter for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++) 29662449Speter continue; 29750276Speter 29862449Speter if (*ptr == '\0') 29962449Speter other_names = ptr; 30062449Speter else { 30162449Speter *ptr = '\0'; 30262449Speter other_names = ptr + 1; 30350276Speter } 30462449Speter } 30550276Speter 30662449Speter DEBUG(7, ("First name = '%s'", first_name)); 30762449Speter DEBUG(7, ("Other names = '%s'", other_names)); 30850276Speter 30962449Speter _nc_set_type(first_name); 31050276Speter 311166124Srafan#if USE_HASHED_DB 312166124Srafan if (write_object(tp, buffer + 1, &offset, limit - 1) != ERR) { 313166124Srafan DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE); 314166124Srafan DBT key, data; 315166124Srafan 316166124Srafan if (capdb != 0) { 317166124Srafan buffer[0] = 0; 318166124Srafan 319166124Srafan memset(&key, 0, sizeof(key)); 320166124Srafan key.data = tp->term_names; 321166124Srafan key.size = strlen(tp->term_names); 322166124Srafan 323166124Srafan memset(&data, 0, sizeof(data)); 324166124Srafan data.data = buffer; 325166124Srafan data.size = offset + 1; 326166124Srafan 327166124Srafan _nc_db_put(capdb, &key, &data); 328166124Srafan 329166124Srafan buffer[0] = 2; 330166124Srafan 331166124Srafan key.data = name_list; 332166124Srafan key.size = strlen(name_list); 333166124Srafan 334166124Srafan strcpy(buffer + 1, tp->term_names); 335166124Srafan data.size = strlen(tp->term_names) + 1; 336166124Srafan 337166124Srafan _nc_db_put(capdb, &key, &data); 338166124Srafan 339166124Srafan while (*other_names != '\0') { 340166124Srafan ptr = other_names++; 341166124Srafan while (*other_names != '|' && *other_names != '\0') 342166124Srafan other_names++; 343166124Srafan 344166124Srafan if (*other_names != '\0') 345166124Srafan *(other_names++) = '\0'; 346166124Srafan 347166124Srafan key.data = ptr; 348166124Srafan key.size = strlen(ptr); 349166124Srafan 350166124Srafan _nc_db_put(capdb, &key, &data); 351166124Srafan } 352166124Srafan _nc_db_close(capdb); 353166124Srafan } 354166124Srafan } 355166124Srafan#else /* !USE_HASHED_DB */ 356166124Srafan if (call_count++ == 0) { 357166124Srafan start_time = 0; 358166124Srafan } 359166124Srafan 360184989Srafan if (strlen(first_name) >= sizeof(filename) - 3) 36162449Speter _nc_warning("terminal name too long."); 36250276Speter 363174993Srafan sprintf(filename, LEAF_FMT "/%s", first_name[0], first_name); 36450276Speter 36562449Speter /* 36662449Speter * Has this primary name been written since the first call to 36762449Speter * write_entry()? If so, the newer write will step on the older, 36862449Speter * so warn the user. 36962449Speter */ 37062449Speter if (start_time > 0 && 37162449Speter stat(filename, &statbuf) >= 0 37262449Speter && statbuf.st_mtime >= start_time) { 37362449Speter _nc_warning("name multiply defined."); 37462449Speter } 37550276Speter 37662449Speter check_writeable(first_name[0]); 37762449Speter write_file(filename, tp); 37850276Speter 37962449Speter if (start_time == 0) { 38062449Speter if (stat(filename, &statbuf) < 0 38162449Speter || (start_time = statbuf.st_mtime) == 0) { 38262449Speter _nc_syserr_abort("error obtaining time from %s/%s", 38376726Speter _nc_tic_dir(0), filename); 38450276Speter } 38562449Speter } 38662449Speter while (*other_names != '\0') { 38762449Speter ptr = other_names++; 388184989Srafan assert(ptr < buffer + sizeof(buffer) - 1); 38962449Speter while (*other_names != '|' && *other_names != '\0') 39062449Speter other_names++; 39150276Speter 39262449Speter if (*other_names != '\0') 39362449Speter *(other_names++) = '\0'; 39450276Speter 39562449Speter if (strlen(ptr) > sizeof(linkname) - 3) { 39662449Speter _nc_warning("terminal alias %s too long.", ptr); 39762449Speter continue; 39862449Speter } 39962449Speter if (strchr(ptr, '/') != 0) { 40062449Speter _nc_warning("cannot link alias %s.", ptr); 40162449Speter continue; 40262449Speter } 40350276Speter 40462449Speter check_writeable(ptr[0]); 405174993Srafan sprintf(linkname, LEAF_FMT "/%s", ptr[0], ptr); 40650276Speter 40762449Speter if (strcmp(filename, linkname) == 0) { 40862449Speter _nc_warning("self-synonym ignored"); 40962449Speter } else if (stat(linkname, &statbuf) >= 0 && 41076726Speter statbuf.st_mtime < start_time) { 41162449Speter _nc_warning("alias %s multiply defined.", ptr); 41262449Speter } else if (_nc_access(linkname, W_OK) == 0) 41350276Speter#if HAVE_LINK 41462449Speter { 41562449Speter int code; 41650276Speter#if USE_SYMLINKS 41762449Speter strcpy(symlinkname, "../"); 41862449Speter strncat(symlinkname, filename, sizeof(symlinkname) - 4); 41962449Speter symlinkname[sizeof(symlinkname) - 1] = '\0'; 42050276Speter#endif /* USE_SYMLINKS */ 42150276Speter#if HAVE_REMOVE 42262449Speter code = remove(linkname); 42350276Speter#else 42462449Speter code = unlink(linkname); 42550276Speter#endif 42662449Speter if (code != 0 && errno == ENOENT) 42762449Speter code = 0; 42850276Speter#if USE_SYMLINKS 42962449Speter if (symlink(symlinkname, linkname) < 0) 43050276Speter#else 43162449Speter if (link(filename, linkname) < 0) 43250276Speter#endif /* USE_SYMLINKS */ 43362449Speter { 43462449Speter /* 43562449Speter * If there wasn't anything there, and we cannot 43662449Speter * link to the target because it is the same as the 43762449Speter * target, then the source must be on a filesystem 43862449Speter * that uses caseless filenames, such as Win32, etc. 43962449Speter */ 44062449Speter if (code == 0 && errno == EEXIST) 44162449Speter _nc_warning("can't link %s to %s", filename, linkname); 44276726Speter else if (code == 0 && (errno == EPERM || errno == ENOENT)) 44362449Speter write_file(linkname, tp); 44476726Speter else { 44576726Speter#if MIXEDCASE_FILENAMES 44662449Speter _nc_syserr_abort("can't link %s to %s", filename, linkname); 44776726Speter#else 44876726Speter _nc_warning("can't link %s to %s (errno=%d)", filename, 44976726Speter linkname, errno); 45076726Speter#endif 45176726Speter } 45262449Speter } else { 45362449Speter DEBUG(1, ("Linked %s", linkname)); 45462449Speter } 45562449Speter } 45650276Speter#else /* just make copies */ 45762449Speter write_file(linkname, tp); 45850276Speter#endif /* HAVE_LINK */ 45962449Speter } 460166124Srafan#endif /* USE_HASHED_DB */ 46150276Speter} 46250276Speter 463166124Srafanstatic unsigned 464166124Srafanfake_write(char *dst, 465166124Srafan unsigned *offset, 466166124Srafan unsigned limit, 467166124Srafan char *src, 468166124Srafan unsigned want, 469166124Srafan unsigned size) 470166124Srafan{ 471166124Srafan int have = (limit - *offset); 472166124Srafan 473166124Srafan want *= size; 474166124Srafan if (have > 0) { 475166124Srafan if ((int) want > have) 476166124Srafan want = have; 477166124Srafan memcpy(dst + *offset, src, want); 478166124Srafan *offset += want; 479166124Srafan } else { 480166124Srafan want = 0; 481166124Srafan } 482166124Srafan return (int) (want / size); 483166124Srafan} 484166124Srafan 485166124Srafan#define Write(buf, size, count) fake_write(buffer, offset, limit, (char *) buf, count, size) 486166124Srafan 48762449Speter#undef LITTLE_ENDIAN /* BSD/OS defines this as a feature macro */ 48850276Speter#define HI(x) ((x) / 256) 48950276Speter#define LO(x) ((x) % 256) 49050276Speter#define LITTLE_ENDIAN(p, x) (p)[0] = LO(x), (p)[1] = HI(x) 49150276Speter 492166124Srafan#define WRITE_STRING(str) (Write(str, sizeof(char), strlen(str) + 1) == strlen(str) + 1) 49350276Speter 49462449Speterstatic int 49597049Spetercompute_offsets(char **Strings, unsigned strmax, short *offsets) 49650276Speter{ 49750276Speter size_t nextfree = 0; 49897049Speter unsigned i; 49950276Speter 50050276Speter for (i = 0; i < strmax; i++) { 50150276Speter if (Strings[i] == ABSENT_STRING) { 50250276Speter offsets[i] = -1; 50350276Speter } else if (Strings[i] == CANCELLED_STRING) { 50450276Speter offsets[i] = -2; 50550276Speter } else { 50650276Speter offsets[i] = nextfree; 50750276Speter nextfree += strlen(Strings[i]) + 1; 508174993Srafan TRACE_OUT(("put Strings[%d]=%s(%d)", (int) i, 509184989Srafan _nc_visbuf(Strings[i]), (int) nextfree)); 51050276Speter } 51150276Speter } 51250276Speter return nextfree; 51350276Speter} 51450276Speter 51562449Speterstatic void 51697049Speterconvert_shorts(unsigned char *buf, short *Numbers, unsigned count) 51750276Speter{ 51897049Speter unsigned i; 51950276Speter for (i = 0; i < count; i++) { 52062449Speter if (Numbers[i] == ABSENT_NUMERIC) { /* HI/LO won't work */ 52162449Speter buf[2 * i] = buf[2 * i + 1] = 0377; 52262449Speter } else if (Numbers[i] == CANCELLED_NUMERIC) { /* HI/LO won't work */ 52362449Speter buf[2 * i] = 0376; 52462449Speter buf[2 * i + 1] = 0377; 52550276Speter } else { 52662449Speter LITTLE_ENDIAN(buf + 2 * i, Numbers[i]); 52750276Speter TRACE_OUT(("put Numbers[%d]=%d", i, Numbers[i])); 52850276Speter } 52950276Speter } 53050276Speter} 53150276Speter 53250276Speter#define even_boundary(value) \ 533166124Srafan ((value) % 2 != 0 && Write(&zero, sizeof(char), 1) != 1) 53450276Speter 535166124Srafan#if NCURSES_XNAMES 536166124Srafanstatic unsigned 537166124Srafanextended_Booleans(TERMTYPE *tp) 538166124Srafan{ 539166124Srafan unsigned short result = 0; 540166124Srafan unsigned short i; 541166124Srafan 542166124Srafan for (i = 0; i < tp->ext_Booleans; ++i) { 543166124Srafan if (tp->Booleans[BOOLCOUNT + i] == TRUE) 544166124Srafan result = (i + 1); 545166124Srafan } 546166124Srafan return result; 547166124Srafan} 548166124Srafan 549166124Srafanstatic unsigned 550166124Srafanextended_Numbers(TERMTYPE *tp) 551166124Srafan{ 552166124Srafan unsigned short result = 0; 553166124Srafan unsigned short i; 554166124Srafan 555166124Srafan for (i = 0; i < tp->ext_Numbers; ++i) { 556166124Srafan if (tp->Numbers[NUMCOUNT + i] != ABSENT_NUMERIC) 557166124Srafan result = (i + 1); 558166124Srafan } 559166124Srafan return result; 560166124Srafan} 561166124Srafan 562166124Srafanstatic unsigned 563166124Srafanextended_Strings(TERMTYPE *tp) 564166124Srafan{ 565166124Srafan unsigned short result = 0; 566166124Srafan unsigned short i; 567166124Srafan 568166124Srafan for (i = 0; i < tp->ext_Strings; ++i) { 569166124Srafan if (tp->Strings[STRCOUNT + i] != ABSENT_STRING) 570166124Srafan result = (i + 1); 571166124Srafan } 572166124Srafan return result; 573166124Srafan} 574166124Srafan 575166124Srafan/* 576166124Srafan * _nc_align_termtype() will extend entries that are referenced in a use= 577166124Srafan * clause - discard the unneeded data. 578166124Srafan */ 579166124Srafanstatic bool 580166124Srafanextended_object(TERMTYPE *tp) 581166124Srafan{ 582166124Srafan bool result = FALSE; 583166124Srafan 584166124Srafan if (_nc_user_definable) { 585166124Srafan result = ((extended_Booleans(tp) 586166124Srafan + extended_Numbers(tp) 587166124Srafan + extended_Strings(tp)) != 0); 588166124Srafan } 589166124Srafan return result; 590166124Srafan} 591166124Srafan#endif 592166124Srafan 59362449Speterstatic int 594166124Srafanwrite_object(TERMTYPE *tp, char *buffer, unsigned *offset, unsigned limit) 59550276Speter{ 59662449Speter char *namelist; 59762449Speter size_t namelen, boolmax, nummax, strmax; 59862449Speter char zero = '\0'; 59962449Speter size_t i; 60062449Speter short nextfree; 60162449Speter short offsets[MAX_ENTRY_SIZE / 2]; 60262449Speter unsigned char buf[MAX_ENTRY_SIZE]; 60362449Speter unsigned last_bool = BOOLWRITE; 60462449Speter unsigned last_num = NUMWRITE; 60562449Speter unsigned last_str = STRWRITE; 60650276Speter 60762449Speter#if NCURSES_XNAMES 60862449Speter /* 60962449Speter * Normally we limit the list of values to exclude the "obsolete" 61062449Speter * capabilities. However, if we are accepting extended names, add 61162449Speter * these as well, since they are used for supporting translation 61262449Speter * to/from termcap. 61362449Speter */ 61462449Speter if (_nc_user_definable) { 61562449Speter last_bool = BOOLCOUNT; 61662449Speter last_num = NUMCOUNT; 61762449Speter last_str = STRCOUNT; 61862449Speter } 61962449Speter#endif 62050276Speter 62162449Speter namelist = tp->term_names; 62262449Speter namelen = strlen(namelist) + 1; 62350276Speter 62462449Speter boolmax = 0; 62562449Speter for (i = 0; i < last_bool; i++) { 62662449Speter if (tp->Booleans[i] == TRUE) 62762449Speter boolmax = i + 1; 62862449Speter } 62950276Speter 63062449Speter nummax = 0; 63162449Speter for (i = 0; i < last_num; i++) { 63262449Speter if (tp->Numbers[i] != ABSENT_NUMERIC) 63362449Speter nummax = i + 1; 63462449Speter } 63550276Speter 63662449Speter strmax = 0; 63762449Speter for (i = 0; i < last_str; i++) { 63862449Speter if (tp->Strings[i] != ABSENT_STRING) 63962449Speter strmax = i + 1; 64062449Speter } 64150276Speter 64262449Speter nextfree = compute_offsets(tp->Strings, strmax, offsets); 64350276Speter 64462449Speter /* fill in the header */ 64562449Speter LITTLE_ENDIAN(buf, MAGIC); 64662449Speter LITTLE_ENDIAN(buf + 2, min(namelen, MAX_NAME_SIZE + 1)); 64762449Speter LITTLE_ENDIAN(buf + 4, boolmax); 64862449Speter LITTLE_ENDIAN(buf + 6, nummax); 64962449Speter LITTLE_ENDIAN(buf + 8, strmax); 65062449Speter LITTLE_ENDIAN(buf + 10, nextfree); 65150276Speter 65262449Speter /* write out the header */ 653166124Srafan TRACE_OUT(("Header of %s @%d", namelist, *offset)); 654166124Srafan if (Write(buf, 12, 1) != 1 655166124Srafan || Write(namelist, sizeof(char), namelen) != namelen) 65662449Speter return (ERR); 65750276Speter 65862449Speter for (i = 0; i < boolmax; i++) 65962449Speter if (tp->Booleans[i] == TRUE) 66062449Speter buf[i] = TRUE; 66162449Speter else 66262449Speter buf[i] = FALSE; 663166124Srafan if (Write(buf, sizeof(char), boolmax) != boolmax) 66462449Speter return (ERR); 66550276Speter 66662449Speter if (even_boundary(namelen + boolmax)) 66762449Speter return (ERR); 66850276Speter 669166124Srafan TRACE_OUT(("Numerics begin at %04x", *offset)); 67050276Speter 67162449Speter /* the numerics */ 67262449Speter convert_shorts(buf, tp->Numbers, nummax); 673166124Srafan if (Write(buf, 2, nummax) != nummax) 67462449Speter return (ERR); 67550276Speter 676166124Srafan TRACE_OUT(("String offsets begin at %04x", *offset)); 67750276Speter 67862449Speter /* the string offsets */ 67962449Speter convert_shorts(buf, offsets, strmax); 680166124Srafan if (Write(buf, 2, strmax) != strmax) 68162449Speter return (ERR); 68250276Speter 683166124Srafan TRACE_OUT(("String table begins at %04x", *offset)); 68462449Speter 68562449Speter /* the strings */ 68662449Speter for (i = 0; i < strmax; i++) 68762449Speter if (VALID_STRING(tp->Strings[i])) 68862449Speter if (!WRITE_STRING(tp->Strings[i])) 68962449Speter return (ERR); 69062449Speter 69150276Speter#if NCURSES_XNAMES 692166124Srafan if (extended_object(tp)) { 69362449Speter unsigned extcnt = NUM_EXT_NAMES(tp); 69450276Speter 69562449Speter if (even_boundary(nextfree)) 69662449Speter return (ERR); 69750276Speter 698184989Srafan nextfree = compute_offsets(tp->Strings + STRCOUNT, 699184989Srafan tp->ext_Strings, 700184989Srafan offsets); 70162449Speter TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree)); 702184989Srafan 703184989Srafan if (tp->ext_Strings >= SIZEOF(offsets)) 704184989Srafan return (ERR); 705184989Srafan 706184989Srafan nextfree += compute_offsets(tp->ext_Names, 707184989Srafan extcnt, 708184989Srafan offsets + tp->ext_Strings); 70962449Speter TRACE_OUT(("after extended capnames, nextfree=%d", nextfree)); 71062449Speter strmax = tp->ext_Strings + extcnt; 71150276Speter 71262449Speter /* 71362449Speter * Write the extended header 71462449Speter */ 71562449Speter LITTLE_ENDIAN(buf + 0, tp->ext_Booleans); 71662449Speter LITTLE_ENDIAN(buf + 2, tp->ext_Numbers); 71762449Speter LITTLE_ENDIAN(buf + 4, tp->ext_Strings); 71862449Speter LITTLE_ENDIAN(buf + 6, strmax); 71962449Speter LITTLE_ENDIAN(buf + 8, nextfree); 720166124Srafan TRACE_OUT(("WRITE extended-header @%d", *offset)); 721166124Srafan if (Write(buf, 10, 1) != 1) 72262449Speter return (ERR); 72350276Speter 724166124Srafan TRACE_OUT(("WRITE %d booleans @%d", tp->ext_Booleans, *offset)); 72562449Speter if (tp->ext_Booleans 726166124Srafan && Write(tp->Booleans + BOOLCOUNT, sizeof(char), 727166124Srafan tp->ext_Booleans) != tp->ext_Booleans) 72862449Speter return (ERR); 72950276Speter 73062449Speter if (even_boundary(tp->ext_Booleans)) 73162449Speter return (ERR); 73250276Speter 733166124Srafan TRACE_OUT(("WRITE %d numbers @%d", tp->ext_Numbers, *offset)); 73462449Speter if (tp->ext_Numbers) { 73562449Speter convert_shorts(buf, tp->Numbers + NUMCOUNT, tp->ext_Numbers); 736166124Srafan if (Write(buf, 2, tp->ext_Numbers) != tp->ext_Numbers) 73762449Speter return (ERR); 73862449Speter } 73950276Speter 74062449Speter /* 74162449Speter * Convert the offsets for the ext_Strings and ext_Names tables, 74262449Speter * in that order. 74362449Speter */ 74462449Speter convert_shorts(buf, offsets, strmax); 745166124Srafan TRACE_OUT(("WRITE offsets @%d", *offset)); 746166124Srafan if (Write(buf, 2, strmax) != strmax) 74762449Speter return (ERR); 74850276Speter 74962449Speter /* 75062449Speter * Write the string table after the offset tables so we do not 75162449Speter * have to do anything about alignment. 75262449Speter */ 75362449Speter for (i = 0; i < tp->ext_Strings; i++) { 75462449Speter if (VALID_STRING(tp->Strings[i + STRCOUNT])) { 755174993Srafan TRACE_OUT(("WRITE ext_Strings[%d]=%s", (int) i, 75676726Speter _nc_visbuf(tp->Strings[i + STRCOUNT]))); 75762449Speter if (!WRITE_STRING(tp->Strings[i + STRCOUNT])) 75862449Speter return (ERR); 75950276Speter } 76062449Speter } 76150276Speter 76262449Speter /* 76362449Speter * Write the extended names 76462449Speter */ 76562449Speter for (i = 0; i < extcnt; i++) { 766174993Srafan TRACE_OUT(("WRITE ext_Names[%d]=%s", (int) i, tp->ext_Names[i])); 76762449Speter if (!WRITE_STRING(tp->ext_Names[i])) 76862449Speter return (ERR); 76962449Speter } 77050276Speter 77162449Speter } 77250276Speter#endif /* NCURSES_XNAMES */ 77350276Speter 77462449Speter total_written++; 77562449Speter return (OK); 77650276Speter} 77750276Speter 77850276Speter/* 77950276Speter * Returns the total number of entries written by this process 78050276Speter */ 78176726SpeterNCURSES_EXPORT(int) 78262449Speter_nc_tic_written(void) 78350276Speter{ 78462449Speter return total_written; 78550276Speter} 786