1fdd4e1e0SJan Lentfer /****************************************************************************
2*32bb5217SDaniel Fojt  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
3*32bb5217SDaniel Fojt  * Copyright 1998-2016,2017 Free Software Foundation, Inc.                  *
4fdd4e1e0SJan Lentfer  *                                                                          *
5fdd4e1e0SJan Lentfer  * Permission is hereby granted, free of charge, to any person obtaining a  *
6fdd4e1e0SJan Lentfer  * copy of this software and associated documentation files (the            *
7fdd4e1e0SJan Lentfer  * "Software"), to deal in the Software without restriction, including      *
8fdd4e1e0SJan Lentfer  * without limitation the rights to use, copy, modify, merge, publish,      *
9fdd4e1e0SJan Lentfer  * distribute, distribute with modifications, sublicense, and/or sell       *
10fdd4e1e0SJan Lentfer  * copies of the Software, and to permit persons to whom the Software is    *
11fdd4e1e0SJan Lentfer  * furnished to do so, subject to the following conditions:                 *
12fdd4e1e0SJan Lentfer  *                                                                          *
13fdd4e1e0SJan Lentfer  * The above copyright notice and this permission notice shall be included  *
14fdd4e1e0SJan Lentfer  * in all copies or substantial portions of the Software.                   *
15fdd4e1e0SJan Lentfer  *                                                                          *
16fdd4e1e0SJan Lentfer  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17fdd4e1e0SJan Lentfer  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18fdd4e1e0SJan Lentfer  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19fdd4e1e0SJan Lentfer  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20fdd4e1e0SJan Lentfer  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21fdd4e1e0SJan Lentfer  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22fdd4e1e0SJan Lentfer  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23fdd4e1e0SJan Lentfer  *                                                                          *
24fdd4e1e0SJan Lentfer  * Except as contained in this notice, the name(s) of the above copyright   *
25fdd4e1e0SJan Lentfer  * holders shall not be used in advertising or otherwise to promote the     *
26fdd4e1e0SJan Lentfer  * sale, use or other dealings in this Software without prior written       *
27fdd4e1e0SJan Lentfer  * authorization.                                                           *
28fdd4e1e0SJan Lentfer  ****************************************************************************/
29fdd4e1e0SJan Lentfer 
30fdd4e1e0SJan Lentfer /****************************************************************************
31fdd4e1e0SJan Lentfer  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
32fdd4e1e0SJan Lentfer  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
331d102085SJan Lentfer  *     and: Thomas E. Dickey                        1996-on                 *
34fdd4e1e0SJan Lentfer  ****************************************************************************/
35fdd4e1e0SJan Lentfer 
36fdd4e1e0SJan Lentfer /*
37fdd4e1e0SJan Lentfer  *	write_entry.c -- write a terminfo structure onto the file system
38fdd4e1e0SJan Lentfer  */
39fdd4e1e0SJan Lentfer 
40fdd4e1e0SJan Lentfer #include <curses.priv.h>
411d102085SJan Lentfer #include <hashed_db.h>
42fdd4e1e0SJan Lentfer 
43fdd4e1e0SJan Lentfer #include <tic.h>
44fdd4e1e0SJan Lentfer 
451d102085SJan Lentfer #if 1
46fdd4e1e0SJan Lentfer #define TRACE_OUT(p) DEBUG(2, p)
47*32bb5217SDaniel Fojt #define TRACE_NUM(n) if (VALID_NUMERIC(Numbers[n])) { \
48*32bb5217SDaniel Fojt 	TRACE_OUT(("put Numbers[%u]=%d", (unsigned) (n), Numbers[n])); }
49fdd4e1e0SJan Lentfer #else
50fdd4e1e0SJan Lentfer #define TRACE_OUT(p)		/*nothing */
51*32bb5217SDaniel Fojt #define TRACE_NUM(n)		/* nothing */
52fdd4e1e0SJan Lentfer #endif
53fdd4e1e0SJan Lentfer 
54*32bb5217SDaniel Fojt MODULE_ID("$Id: write_entry.c,v 1.115 2020/02/02 23:34:34 tom Exp $")
55fdd4e1e0SJan Lentfer 
56fdd4e1e0SJan Lentfer static int total_written;
57*32bb5217SDaniel Fojt static int total_parts;
58*32bb5217SDaniel Fojt static int total_size;
59fdd4e1e0SJan Lentfer 
601d102085SJan Lentfer static int make_db_root(const char *);
61fdd4e1e0SJan Lentfer 
621d102085SJan Lentfer #if !USE_HASHED_DB
63fdd4e1e0SJan Lentfer static void
write_file(char * filename,TERMTYPE2 * tp)64*32bb5217SDaniel Fojt write_file(char *filename, TERMTYPE2 *tp)
65fdd4e1e0SJan Lentfer {
661d102085SJan Lentfer     char buffer[MAX_ENTRY_SIZE];
671d102085SJan Lentfer     unsigned limit = sizeof(buffer);
681d102085SJan Lentfer     unsigned offset = 0;
691d102085SJan Lentfer 
70*32bb5217SDaniel Fojt     if (_nc_write_object(tp, buffer, &offset, limit) == ERR) {
71*32bb5217SDaniel Fojt 	_nc_warning("entry is larger than %u bytes", limit);
72*32bb5217SDaniel Fojt     } else {
73*32bb5217SDaniel Fojt 	FILE *fp = ((_nc_access(filename, W_OK) == 0)
74*32bb5217SDaniel Fojt 		    ? fopen(filename, BIN_W)
75*32bb5217SDaniel Fojt 		    : 0);
76*32bb5217SDaniel Fojt 	size_t actual;
77*32bb5217SDaniel Fojt 
78fdd4e1e0SJan Lentfer 	if (fp == 0) {
79fdd4e1e0SJan Lentfer 	    perror(filename);
80fdd4e1e0SJan Lentfer 	    _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename);
81fdd4e1e0SJan Lentfer 	}
82fdd4e1e0SJan Lentfer 
83*32bb5217SDaniel Fojt 	actual = fwrite(buffer, sizeof(char), (size_t) offset, fp);
84*32bb5217SDaniel Fojt 	if (actual != offset) {
85*32bb5217SDaniel Fojt 	    int myerr = ferror(fp) ? errno : 0;
86*32bb5217SDaniel Fojt 	    if (myerr) {
87*32bb5217SDaniel Fojt 		_nc_syserr_abort("error writing %s/%s: %s",
88*32bb5217SDaniel Fojt 				 _nc_tic_dir(0),
89*32bb5217SDaniel Fojt 				 filename,
90*32bb5217SDaniel Fojt 				 strerror(myerr));
91*32bb5217SDaniel Fojt 	    } else {
92*32bb5217SDaniel Fojt 		_nc_syserr_abort("error writing %s/%s: %u bytes vs actual %lu",
93*32bb5217SDaniel Fojt 				 _nc_tic_dir(0),
94*32bb5217SDaniel Fojt 				 filename,
95*32bb5217SDaniel Fojt 				 offset,
96*32bb5217SDaniel Fojt 				 (unsigned long) actual);
97fdd4e1e0SJan Lentfer 	    }
98*32bb5217SDaniel Fojt 	} else {
99fdd4e1e0SJan Lentfer 	    fclose(fp);
100*32bb5217SDaniel Fojt 	    DEBUG(1, ("Created %s", filename));
101*32bb5217SDaniel Fojt 	}
102*32bb5217SDaniel Fojt     }
103fdd4e1e0SJan Lentfer }
104fdd4e1e0SJan Lentfer 
105fdd4e1e0SJan Lentfer /*
1061d102085SJan Lentfer  * Check for access rights to destination directories
1071d102085SJan Lentfer  * Create any directories which don't exist.
108fdd4e1e0SJan Lentfer  *
1091d102085SJan Lentfer  * Note:  there's no reason to return the result of make_db_root(), since
1101d102085SJan Lentfer  * this function is called only in instances where that has to succeed.
1111d102085SJan Lentfer  */
1121d102085SJan Lentfer static void
check_writeable(int code)1131d102085SJan Lentfer check_writeable(int code)
1141d102085SJan Lentfer {
1151d102085SJan Lentfer     static const char dirnames[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
1161d102085SJan Lentfer     static bool verified[sizeof(dirnames)];
1171d102085SJan Lentfer 
1181d102085SJan Lentfer     char dir[sizeof(LEAF_FMT)];
1191d102085SJan Lentfer     char *s = 0;
1201d102085SJan Lentfer 
1213468e90cSJohn Marino     if (code == 0 || (s = (strchr) (dirnames, code)) == 0)
1221d102085SJan Lentfer 	_nc_err_abort("Illegal terminfo subdirectory \"" LEAF_FMT "\"", code);
1231d102085SJan Lentfer 
1241d102085SJan Lentfer     if (verified[s - dirnames])
1251d102085SJan Lentfer 	return;
1261d102085SJan Lentfer 
1273468e90cSJohn Marino     _nc_SPRINTF(dir, _nc_SLIMIT(sizeof(dir)) LEAF_FMT, code);
1281d102085SJan Lentfer     if (make_db_root(dir) < 0) {
1291d102085SJan Lentfer 	_nc_err_abort("%s/%s: permission denied", _nc_tic_dir(0), dir);
1301d102085SJan Lentfer     }
1311d102085SJan Lentfer 
1321d102085SJan Lentfer     verified[s - dirnames] = TRUE;
1331d102085SJan Lentfer }
1341d102085SJan Lentfer #endif /* !USE_HASHED_DB */
1351d102085SJan Lentfer 
1361d102085SJan Lentfer static int
make_db_path(char * dst,const char * src,size_t limit)1373468e90cSJohn Marino make_db_path(char *dst, const char *src, size_t limit)
1381d102085SJan Lentfer {
1391d102085SJan Lentfer     int rc = -1;
1401d102085SJan Lentfer     const char *top = _nc_tic_dir(0);
1411d102085SJan Lentfer 
1421d102085SJan Lentfer     if (src == top || _nc_is_abs_path(src)) {
1431d102085SJan Lentfer 	if (strlen(src) + 1 <= limit) {
1443468e90cSJohn Marino 	    _nc_STRCPY(dst, src, limit);
1451d102085SJan Lentfer 	    rc = 0;
1461d102085SJan Lentfer 	}
1471d102085SJan Lentfer     } else {
1481d102085SJan Lentfer 	if (strlen(top) + strlen(src) + 2 <= limit) {
1493468e90cSJohn Marino 	    _nc_SPRINTF(dst, _nc_SLIMIT(limit) "%s/%s", top, src);
1501d102085SJan Lentfer 	    rc = 0;
1511d102085SJan Lentfer 	}
1521d102085SJan Lentfer     }
1531d102085SJan Lentfer #if USE_HASHED_DB
1541d102085SJan Lentfer     if (rc == 0) {
15500d8f3c4SJohn Marino 	static const char suffix[] = DBM_SUFFIX;
1563468e90cSJohn Marino 	size_t have = strlen(dst);
1573468e90cSJohn Marino 	size_t need = strlen(suffix);
1583468e90cSJohn Marino 	if (have > need && strcmp(dst + (int) (have - need), suffix)) {
1593468e90cSJohn Marino 	    if (have + need <= limit) {
1603468e90cSJohn Marino 		_nc_STRCAT(dst, suffix, limit);
1613468e90cSJohn Marino 	    } else {
1621d102085SJan Lentfer 		rc = -1;
1631d102085SJan Lentfer 	    }
1643468e90cSJohn Marino 	} else if (_nc_is_dir_path(dst)) {
1653468e90cSJohn Marino 	    rc = -1;
1661d102085SJan Lentfer 	}
1671d102085SJan Lentfer     }
1681d102085SJan Lentfer #endif
1691d102085SJan Lentfer     return rc;
1701d102085SJan Lentfer }
1711d102085SJan Lentfer 
1721d102085SJan Lentfer /*
1731d102085SJan Lentfer  * Make a database-root if it doesn't exist.
174fdd4e1e0SJan Lentfer  */
175fdd4e1e0SJan Lentfer static int
make_db_root(const char * path)1761d102085SJan Lentfer make_db_root(const char *path)
177fdd4e1e0SJan Lentfer {
178fdd4e1e0SJan Lentfer     int rc;
179fdd4e1e0SJan Lentfer     char fullpath[PATH_MAX];
180fdd4e1e0SJan Lentfer 
1811d102085SJan Lentfer     if ((rc = make_db_path(fullpath, path, sizeof(fullpath))) == 0) {
1821d102085SJan Lentfer #if USE_HASHED_DB
1831d102085SJan Lentfer 	DB *capdbp;
1841d102085SJan Lentfer 
1853468e90cSJohn Marino 	if ((capdbp = _nc_db_open(fullpath, TRUE)) == NULL) {
1861d102085SJan Lentfer 	    rc = -1;
1873468e90cSJohn Marino 	} else if (_nc_db_close(capdbp) < 0) {
1881d102085SJan Lentfer 	    rc = -1;
1893468e90cSJohn Marino 	}
1901d102085SJan Lentfer #else
1911d102085SJan Lentfer 	struct stat statbuf;
192fdd4e1e0SJan Lentfer 
193fdd4e1e0SJan Lentfer 	if ((rc = stat(path, &statbuf)) < 0) {
19400d8f3c4SJohn Marino 	    rc = mkdir(path
195*32bb5217SDaniel Fojt #if !defined(_WIN32)
19600d8f3c4SJohn Marino 		       ,0777
19700d8f3c4SJohn Marino #endif
19800d8f3c4SJohn Marino 		);
1991d102085SJan Lentfer 	} else if (_nc_access(path, R_OK | W_OK | X_OK) < 0) {
200fdd4e1e0SJan Lentfer 	    rc = -1;		/* permission denied */
201fdd4e1e0SJan Lentfer 	} else if (!(S_ISDIR(statbuf.st_mode))) {
202fdd4e1e0SJan Lentfer 	    rc = -1;		/* not a directory */
203fdd4e1e0SJan Lentfer 	}
2041d102085SJan Lentfer #endif
205fdd4e1e0SJan Lentfer     }
206fdd4e1e0SJan Lentfer     return rc;
207fdd4e1e0SJan Lentfer }
208fdd4e1e0SJan Lentfer 
2091d102085SJan Lentfer /*
2101d102085SJan Lentfer  * Set the write directory for compiled entries.
2111d102085SJan Lentfer  */
212fdd4e1e0SJan Lentfer NCURSES_EXPORT(void)
_nc_set_writedir(const char * dir)2133468e90cSJohn Marino _nc_set_writedir(const char *dir)
214fdd4e1e0SJan Lentfer {
215fdd4e1e0SJan Lentfer     const char *destination;
216fdd4e1e0SJan Lentfer     char actual[PATH_MAX];
217fdd4e1e0SJan Lentfer 
218fdd4e1e0SJan Lentfer     if (dir == 0
2193468e90cSJohn Marino #ifndef USE_ROOT_ENVIRON
2203468e90cSJohn Marino 	&& use_terminfo_vars()
2213468e90cSJohn Marino #endif
2223468e90cSJohn Marino 	)
223fdd4e1e0SJan Lentfer 	dir = getenv("TERMINFO");
224fdd4e1e0SJan Lentfer 
225fdd4e1e0SJan Lentfer     if (dir != 0)
226fdd4e1e0SJan Lentfer 	(void) _nc_tic_dir(dir);
227fdd4e1e0SJan Lentfer 
228fdd4e1e0SJan Lentfer     destination = _nc_tic_dir(0);
2291d102085SJan Lentfer     if (make_db_root(destination) < 0) {
230fdd4e1e0SJan Lentfer 	char *home = _nc_home_terminfo();
231fdd4e1e0SJan Lentfer 
232fdd4e1e0SJan Lentfer 	if (home != 0) {
233fdd4e1e0SJan Lentfer 	    destination = home;
2341d102085SJan Lentfer 	    if (make_db_root(destination) < 0)
235fdd4e1e0SJan Lentfer 		_nc_err_abort("%s: permission denied (errno %d)",
236fdd4e1e0SJan Lentfer 			      destination, errno);
237fdd4e1e0SJan Lentfer 	}
238fdd4e1e0SJan Lentfer     }
239fdd4e1e0SJan Lentfer 
240fdd4e1e0SJan Lentfer     /*
241fdd4e1e0SJan Lentfer      * Note: because of this code, this logic should be exercised
242fdd4e1e0SJan Lentfer      * *once only* per run.
243fdd4e1e0SJan Lentfer      */
2441d102085SJan Lentfer #if USE_HASHED_DB
2451d102085SJan Lentfer     make_db_path(actual, destination, sizeof(actual));
2461d102085SJan Lentfer #else
247fdd4e1e0SJan Lentfer     if (chdir(_nc_tic_dir(destination)) < 0
248fdd4e1e0SJan Lentfer 	|| getcwd(actual, sizeof(actual)) == 0)
249fdd4e1e0SJan Lentfer 	_nc_err_abort("%s: not a directory", destination);
2501d102085SJan Lentfer #endif
251fdd4e1e0SJan Lentfer     _nc_keep_tic_dir(strdup(actual));
252fdd4e1e0SJan Lentfer }
253fdd4e1e0SJan Lentfer 
254fdd4e1e0SJan Lentfer /*
255fdd4e1e0SJan Lentfer  *	Save the compiled version of a description in the filesystem.
256fdd4e1e0SJan Lentfer  *
257fdd4e1e0SJan Lentfer  *	make a copy of the name-list
258fdd4e1e0SJan Lentfer  *	break it up into first-name and all-but-last-name
259fdd4e1e0SJan Lentfer  *	creat(first-name)
260fdd4e1e0SJan Lentfer  *	write object information to first-name
261fdd4e1e0SJan Lentfer  *	close(first-name)
262fdd4e1e0SJan Lentfer  *      for each name in all-but-last-name
263fdd4e1e0SJan Lentfer  *	    link to first-name
264fdd4e1e0SJan Lentfer  *
265fdd4e1e0SJan Lentfer  *	Using 'time()' to obtain a reference for file timestamps is unreliable,
266fdd4e1e0SJan Lentfer  *	e.g., with NFS, because the filesystem may have a different time
267fdd4e1e0SJan Lentfer  *	reference.  We check for pre-existence of links by latching the first
268fdd4e1e0SJan Lentfer  *	timestamp from a file that we create.
269fdd4e1e0SJan Lentfer  *
270fdd4e1e0SJan Lentfer  *	The _nc_warning() calls will report a correct line number only if
271fdd4e1e0SJan Lentfer  *	_nc_curr_line is properly set before the write_entry() call.
272fdd4e1e0SJan Lentfer  */
273fdd4e1e0SJan Lentfer 
2741d102085SJan Lentfer NCURSES_EXPORT(void)
_nc_write_entry(TERMTYPE2 * const tp)275*32bb5217SDaniel Fojt _nc_write_entry(TERMTYPE2 *const tp)
276fdd4e1e0SJan Lentfer {
2771d102085SJan Lentfer #if USE_HASHED_DB
2781d102085SJan Lentfer 
2791d102085SJan Lentfer     char buffer[MAX_ENTRY_SIZE + 1];
2801d102085SJan Lentfer     unsigned limit = sizeof(buffer);
2811d102085SJan Lentfer     unsigned offset = 0;
2821d102085SJan Lentfer 
2831d102085SJan Lentfer #else /* !USE_HASHED_DB */
2841d102085SJan Lentfer 
285fdd4e1e0SJan Lentfer     struct stat statbuf;
286fdd4e1e0SJan Lentfer     char filename[PATH_MAX];
287fdd4e1e0SJan Lentfer     char linkname[PATH_MAX];
288fdd4e1e0SJan Lentfer #if USE_SYMLINKS
289fdd4e1e0SJan Lentfer     char symlinkname[PATH_MAX];
290fdd4e1e0SJan Lentfer #if !HAVE_LINK
291fdd4e1e0SJan Lentfer #undef HAVE_LINK
292fdd4e1e0SJan Lentfer #define HAVE_LINK 1
293fdd4e1e0SJan Lentfer #endif
294fdd4e1e0SJan Lentfer #endif /* USE_SYMLINKS */
2951d102085SJan Lentfer 
296*32bb5217SDaniel Fojt     unsigned limit2 = sizeof(filename) - (2 + LEAF_LEN);
297*32bb5217SDaniel Fojt     char saved = '\0';
298*32bb5217SDaniel Fojt 
299fdd4e1e0SJan Lentfer     static int call_count;
300fdd4e1e0SJan Lentfer     static time_t start_time;	/* time at start of writes */
301fdd4e1e0SJan Lentfer 
3021d102085SJan Lentfer #endif /* USE_HASHED_DB */
3031d102085SJan Lentfer 
3041d102085SJan Lentfer     char name_list[MAX_TERMINFO_LENGTH];
3051d102085SJan Lentfer     char *first_name, *other_names;
3061d102085SJan Lentfer     char *ptr;
3073468e90cSJohn Marino     char *term_names = tp->term_names;
3083468e90cSJohn Marino     size_t name_size = strlen(term_names);
3091d102085SJan Lentfer 
3103468e90cSJohn Marino     if (name_size == 0) {
3113468e90cSJohn Marino 	_nc_syserr_abort("no terminal name found.");
3123468e90cSJohn Marino     } else if (name_size >= sizeof(name_list) - 1) {
3133468e90cSJohn Marino 	_nc_syserr_abort("terminal name too long: %s", term_names);
3143468e90cSJohn Marino     }
315fdd4e1e0SJan Lentfer 
3163468e90cSJohn Marino     _nc_STRCPY(name_list, term_names, sizeof(name_list));
317fdd4e1e0SJan Lentfer     DEBUG(7, ("Name list = '%s'", name_list));
318fdd4e1e0SJan Lentfer 
319fdd4e1e0SJan Lentfer     first_name = name_list;
320fdd4e1e0SJan Lentfer 
3213468e90cSJohn Marino     ptr = &name_list[name_size - 1];
322fdd4e1e0SJan Lentfer     other_names = ptr + 1;
323fdd4e1e0SJan Lentfer 
324fdd4e1e0SJan Lentfer     while (ptr > name_list && *ptr != '|')
325fdd4e1e0SJan Lentfer 	ptr--;
326fdd4e1e0SJan Lentfer 
327fdd4e1e0SJan Lentfer     if (ptr != name_list) {
328fdd4e1e0SJan Lentfer 	*ptr = '\0';
329fdd4e1e0SJan Lentfer 
330fdd4e1e0SJan Lentfer 	for (ptr = name_list; *ptr != '\0' && *ptr != '|'; ptr++)
331fdd4e1e0SJan Lentfer 	    continue;
332fdd4e1e0SJan Lentfer 
333fdd4e1e0SJan Lentfer 	if (*ptr == '\0')
334fdd4e1e0SJan Lentfer 	    other_names = ptr;
335fdd4e1e0SJan Lentfer 	else {
336fdd4e1e0SJan Lentfer 	    *ptr = '\0';
337fdd4e1e0SJan Lentfer 	    other_names = ptr + 1;
338fdd4e1e0SJan Lentfer 	}
339fdd4e1e0SJan Lentfer     }
340fdd4e1e0SJan Lentfer 
341fdd4e1e0SJan Lentfer     DEBUG(7, ("First name = '%s'", first_name));
342fdd4e1e0SJan Lentfer     DEBUG(7, ("Other names = '%s'", other_names));
343fdd4e1e0SJan Lentfer 
344fdd4e1e0SJan Lentfer     _nc_set_type(first_name);
345fdd4e1e0SJan Lentfer 
3461d102085SJan Lentfer #if USE_HASHED_DB
3473468e90cSJohn Marino     if (_nc_write_object(tp, buffer + 1, &offset, limit - 1) != ERR) {
3481d102085SJan Lentfer 	DB *capdb = _nc_db_open(_nc_tic_dir(0), TRUE);
3491d102085SJan Lentfer 	DBT key, data;
3501d102085SJan Lentfer 
3511d102085SJan Lentfer 	if (capdb != 0) {
3521d102085SJan Lentfer 	    buffer[0] = 0;
3531d102085SJan Lentfer 
3541d102085SJan Lentfer 	    memset(&key, 0, sizeof(key));
3553468e90cSJohn Marino 	    key.data = term_names;
3563468e90cSJohn Marino 	    key.size = name_size;
3571d102085SJan Lentfer 
3581d102085SJan Lentfer 	    memset(&data, 0, sizeof(data));
3591d102085SJan Lentfer 	    data.data = buffer;
3601d102085SJan Lentfer 	    data.size = offset + 1;
3611d102085SJan Lentfer 
3621d102085SJan Lentfer 	    _nc_db_put(capdb, &key, &data);
3631d102085SJan Lentfer 
3641d102085SJan Lentfer 	    buffer[0] = 2;
3651d102085SJan Lentfer 
3661d102085SJan Lentfer 	    key.data = name_list;
3671d102085SJan Lentfer 	    key.size = strlen(name_list);
3681d102085SJan Lentfer 
3693468e90cSJohn Marino 	    _nc_STRCPY(buffer + 1,
3703468e90cSJohn Marino 		       term_names,
3713468e90cSJohn Marino 		       sizeof(buffer) - 1);
3723468e90cSJohn Marino 	    data.size = name_size + 1;
3731d102085SJan Lentfer 
374*32bb5217SDaniel Fojt 	    total_size += data.size;
375*32bb5217SDaniel Fojt 	    total_parts++;
3761d102085SJan Lentfer 	    _nc_db_put(capdb, &key, &data);
3771d102085SJan Lentfer 
3781d102085SJan Lentfer 	    while (*other_names != '\0') {
3791d102085SJan Lentfer 		ptr = other_names++;
38000d8f3c4SJohn Marino 		assert(ptr < buffer + sizeof(buffer) - 1);
3811d102085SJan Lentfer 		while (*other_names != '|' && *other_names != '\0')
3821d102085SJan Lentfer 		    other_names++;
3831d102085SJan Lentfer 
3841d102085SJan Lentfer 		if (*other_names != '\0')
3851d102085SJan Lentfer 		    *(other_names++) = '\0';
3861d102085SJan Lentfer 
3871d102085SJan Lentfer 		key.data = ptr;
3881d102085SJan Lentfer 		key.size = strlen(ptr);
3891d102085SJan Lentfer 
390*32bb5217SDaniel Fojt 		total_size += data.size;
391*32bb5217SDaniel Fojt 		total_parts++;
3921d102085SJan Lentfer 		_nc_db_put(capdb, &key, &data);
3931d102085SJan Lentfer 	    }
3941d102085SJan Lentfer 	}
3951d102085SJan Lentfer     }
3961d102085SJan Lentfer #else /* !USE_HASHED_DB */
3971d102085SJan Lentfer     if (call_count++ == 0) {
3981d102085SJan Lentfer 	start_time = 0;
3991d102085SJan Lentfer     }
4001d102085SJan Lentfer 
401*32bb5217SDaniel Fojt     if (strlen(first_name) >= limit2) {
402fdd4e1e0SJan Lentfer 	_nc_warning("terminal name too long.");
403*32bb5217SDaniel Fojt 	saved = first_name[limit2];
404*32bb5217SDaniel Fojt 	first_name[limit2] = '\0';
405*32bb5217SDaniel Fojt     }
406fdd4e1e0SJan Lentfer 
4073468e90cSJohn Marino     _nc_SPRINTF(filename, _nc_SLIMIT(sizeof(filename))
408*32bb5217SDaniel Fojt 		LEAF_FMT "/%.*s", UChar(first_name[0]),
409*32bb5217SDaniel Fojt 		(int) (sizeof(filename) - (LEAF_LEN + 2)),
410*32bb5217SDaniel Fojt 		first_name);
411*32bb5217SDaniel Fojt 
412*32bb5217SDaniel Fojt     if (saved)
413*32bb5217SDaniel Fojt 	first_name[limit2] = saved;
414fdd4e1e0SJan Lentfer 
415fdd4e1e0SJan Lentfer     /*
416fdd4e1e0SJan Lentfer      * Has this primary name been written since the first call to
417fdd4e1e0SJan Lentfer      * write_entry()?  If so, the newer write will step on the older,
418fdd4e1e0SJan Lentfer      * so warn the user.
419fdd4e1e0SJan Lentfer      */
420fdd4e1e0SJan Lentfer     if (start_time > 0 &&
421fdd4e1e0SJan Lentfer 	stat(filename, &statbuf) >= 0
422fdd4e1e0SJan Lentfer 	&& statbuf.st_mtime >= start_time) {
4233468e90cSJohn Marino #if HAVE_LINK && !USE_SYMLINKS
4243468e90cSJohn Marino 	/*
4253468e90cSJohn Marino 	 * If the file has more than one link, the reason for the previous
4263468e90cSJohn Marino 	 * write could be that the current primary name used to be an alias for
4273468e90cSJohn Marino 	 * the previous entry.  In that case, unlink the file so that we will
4283468e90cSJohn Marino 	 * not modify the previous entry as we write this one.
4293468e90cSJohn Marino 	 */
4303468e90cSJohn Marino 	if (statbuf.st_nlink > 1) {
4313468e90cSJohn Marino 	    _nc_warning("name redefined.");
4323468e90cSJohn Marino 	    unlink(filename);
4333468e90cSJohn Marino 	} else {
434fdd4e1e0SJan Lentfer 	    _nc_warning("name multiply defined.");
435fdd4e1e0SJan Lentfer 	}
4363468e90cSJohn Marino #else
4373468e90cSJohn Marino 	_nc_warning("name multiply defined.");
4383468e90cSJohn Marino #endif
4393468e90cSJohn Marino     }
440fdd4e1e0SJan Lentfer 
441fdd4e1e0SJan Lentfer     check_writeable(first_name[0]);
442fdd4e1e0SJan Lentfer     write_file(filename, tp);
443fdd4e1e0SJan Lentfer 
444fdd4e1e0SJan Lentfer     if (start_time == 0) {
445fdd4e1e0SJan Lentfer 	if (stat(filename, &statbuf) < 0
446fdd4e1e0SJan Lentfer 	    || (start_time = statbuf.st_mtime) == 0) {
447fdd4e1e0SJan Lentfer 	    _nc_syserr_abort("error obtaining time from %s/%s",
448fdd4e1e0SJan Lentfer 			     _nc_tic_dir(0), filename);
449fdd4e1e0SJan Lentfer 	}
450fdd4e1e0SJan Lentfer     }
451fdd4e1e0SJan Lentfer     while (*other_names != '\0') {
452fdd4e1e0SJan Lentfer 	ptr = other_names++;
453fdd4e1e0SJan Lentfer 	while (*other_names != '|' && *other_names != '\0')
454fdd4e1e0SJan Lentfer 	    other_names++;
455fdd4e1e0SJan Lentfer 
456fdd4e1e0SJan Lentfer 	if (*other_names != '\0')
457fdd4e1e0SJan Lentfer 	    *(other_names++) = '\0';
458fdd4e1e0SJan Lentfer 
45900d8f3c4SJohn Marino 	if (strlen(ptr) > sizeof(linkname) - (2 + LEAF_LEN)) {
460fdd4e1e0SJan Lentfer 	    _nc_warning("terminal alias %s too long.", ptr);
461fdd4e1e0SJan Lentfer 	    continue;
462fdd4e1e0SJan Lentfer 	}
463fdd4e1e0SJan Lentfer 	if (strchr(ptr, '/') != 0) {
464fdd4e1e0SJan Lentfer 	    _nc_warning("cannot link alias %s.", ptr);
465fdd4e1e0SJan Lentfer 	    continue;
466fdd4e1e0SJan Lentfer 	}
467fdd4e1e0SJan Lentfer 
468fdd4e1e0SJan Lentfer 	check_writeable(ptr[0]);
4693468e90cSJohn Marino 	_nc_SPRINTF(linkname, _nc_SLIMIT(sizeof(linkname))
470*32bb5217SDaniel Fojt 		    LEAF_FMT "/%.*s", ptr[0],
471*32bb5217SDaniel Fojt 		    (int) sizeof(linkname) - (2 + LEAF_LEN), ptr);
472fdd4e1e0SJan Lentfer 
473fdd4e1e0SJan Lentfer 	if (strcmp(filename, linkname) == 0) {
474fdd4e1e0SJan Lentfer 	    _nc_warning("self-synonym ignored");
475fdd4e1e0SJan Lentfer 	} else if (stat(linkname, &statbuf) >= 0 &&
476fdd4e1e0SJan Lentfer 		   statbuf.st_mtime < start_time) {
477fdd4e1e0SJan Lentfer 	    _nc_warning("alias %s multiply defined.", ptr);
478fdd4e1e0SJan Lentfer 	} else if (_nc_access(linkname, W_OK) == 0)
479fdd4e1e0SJan Lentfer #if HAVE_LINK
480fdd4e1e0SJan Lentfer 	{
481fdd4e1e0SJan Lentfer 	    int code;
482fdd4e1e0SJan Lentfer #if USE_SYMLINKS
483*32bb5217SDaniel Fojt #define MY_SIZE sizeof(symlinkname) - 1
484*32bb5217SDaniel Fojt 	    if (first_name[0] == linkname[0]) {
485*32bb5217SDaniel Fojt 		_nc_STRNCPY(symlinkname, first_name, MY_SIZE);
486*32bb5217SDaniel Fojt 	    } else {
487*32bb5217SDaniel Fojt 		_nc_STRCPY(symlinkname, "../", sizeof(symlinkname));
488*32bb5217SDaniel Fojt 		_nc_STRNCPY(symlinkname + 3, filename, MY_SIZE - 3);
48900d8f3c4SJohn Marino 	    }
490*32bb5217SDaniel Fojt 	    symlinkname[MY_SIZE] = '\0';
491fdd4e1e0SJan Lentfer #endif /* USE_SYMLINKS */
492fdd4e1e0SJan Lentfer #if HAVE_REMOVE
493fdd4e1e0SJan Lentfer 	    code = remove(linkname);
494fdd4e1e0SJan Lentfer #else
495fdd4e1e0SJan Lentfer 	    code = unlink(linkname);
496fdd4e1e0SJan Lentfer #endif
497fdd4e1e0SJan Lentfer 	    if (code != 0 && errno == ENOENT)
498fdd4e1e0SJan Lentfer 		code = 0;
499fdd4e1e0SJan Lentfer #if USE_SYMLINKS
500fdd4e1e0SJan Lentfer 	    if (symlink(symlinkname, linkname) < 0)
501fdd4e1e0SJan Lentfer #else
502fdd4e1e0SJan Lentfer 	    if (link(filename, linkname) < 0)
503fdd4e1e0SJan Lentfer #endif /* USE_SYMLINKS */
504fdd4e1e0SJan Lentfer 	    {
505fdd4e1e0SJan Lentfer 		/*
506fdd4e1e0SJan Lentfer 		 * If there wasn't anything there, and we cannot
507fdd4e1e0SJan Lentfer 		 * link to the target because it is the same as the
508fdd4e1e0SJan Lentfer 		 * target, then the source must be on a filesystem
509fdd4e1e0SJan Lentfer 		 * that uses caseless filenames, such as Win32, etc.
510fdd4e1e0SJan Lentfer 		 */
511fdd4e1e0SJan Lentfer 		if (code == 0 && errno == EEXIST)
512fdd4e1e0SJan Lentfer 		    _nc_warning("can't link %s to %s", filename, linkname);
513fdd4e1e0SJan Lentfer 		else if (code == 0 && (errno == EPERM || errno == ENOENT))
514fdd4e1e0SJan Lentfer 		    write_file(linkname, tp);
515fdd4e1e0SJan Lentfer 		else {
516fdd4e1e0SJan Lentfer #if MIXEDCASE_FILENAMES
517fdd4e1e0SJan Lentfer 		    _nc_syserr_abort("can't link %s to %s", filename, linkname);
518fdd4e1e0SJan Lentfer #else
519fdd4e1e0SJan Lentfer 		    _nc_warning("can't link %s to %s (errno=%d)", filename,
520fdd4e1e0SJan Lentfer 				linkname, errno);
521fdd4e1e0SJan Lentfer #endif
522fdd4e1e0SJan Lentfer 		}
523fdd4e1e0SJan Lentfer 	    } else {
524fdd4e1e0SJan Lentfer 		DEBUG(1, ("Linked %s", linkname));
525fdd4e1e0SJan Lentfer 	    }
526fdd4e1e0SJan Lentfer 	}
527fdd4e1e0SJan Lentfer #else /* just make copies */
528fdd4e1e0SJan Lentfer 	    write_file(linkname, tp);
529fdd4e1e0SJan Lentfer #endif /* HAVE_LINK */
530fdd4e1e0SJan Lentfer     }
5311d102085SJan Lentfer #endif /* USE_HASHED_DB */
532fdd4e1e0SJan Lentfer }
533fdd4e1e0SJan Lentfer 
53400d8f3c4SJohn Marino static size_t
fake_write(char * dst,unsigned * offset,size_t limit,char * src,size_t want,size_t size)5351d102085SJan Lentfer fake_write(char *dst,
5361d102085SJan Lentfer 	   unsigned *offset,
53700d8f3c4SJohn Marino 	   size_t limit,
5381d102085SJan Lentfer 	   char *src,
53900d8f3c4SJohn Marino 	   size_t want,
54000d8f3c4SJohn Marino 	   size_t size)
5411d102085SJan Lentfer {
54200d8f3c4SJohn Marino     size_t have = (limit - *offset);
5431d102085SJan Lentfer 
5441d102085SJan Lentfer     want *= size;
5451d102085SJan Lentfer     if (have > 0) {
54600d8f3c4SJohn Marino 	if (want > have)
5471d102085SJan Lentfer 	    want = have;
5481d102085SJan Lentfer 	memcpy(dst + *offset, src, want);
54900d8f3c4SJohn Marino 	*offset += (unsigned) want;
5501d102085SJan Lentfer     } else {
5511d102085SJan Lentfer 	want = 0;
5521d102085SJan Lentfer     }
55300d8f3c4SJohn Marino     return (want / size);
5541d102085SJan Lentfer }
5551d102085SJan Lentfer 
5563468e90cSJohn Marino #define Write(buf, size, count) fake_write(buffer, offset, (size_t) limit, (char *) buf, (size_t) count, (size_t) size)
5571d102085SJan Lentfer 
558fdd4e1e0SJan Lentfer #undef LITTLE_ENDIAN		/* BSD/OS defines this as a feature macro */
559fdd4e1e0SJan Lentfer #define HI(x)			((x) / 256)
560fdd4e1e0SJan Lentfer #define LO(x)			((x) % 256)
56100d8f3c4SJohn Marino #define LITTLE_ENDIAN(p, x)	(p)[0] = (unsigned char)LO(x),  \
56200d8f3c4SJohn Marino                                 (p)[1] = (unsigned char)HI(x)
563fdd4e1e0SJan Lentfer 
5641d102085SJan Lentfer #define WRITE_STRING(str) (Write(str, sizeof(char), strlen(str) + 1) == strlen(str) + 1)
565fdd4e1e0SJan Lentfer 
566fdd4e1e0SJan Lentfer static int
compute_offsets(char ** Strings,size_t strmax,short * offsets)56700d8f3c4SJohn Marino compute_offsets(char **Strings, size_t strmax, short *offsets)
568fdd4e1e0SJan Lentfer {
56900d8f3c4SJohn Marino     int nextfree = 0;
57000d8f3c4SJohn Marino     size_t i;
571fdd4e1e0SJan Lentfer 
572fdd4e1e0SJan Lentfer     for (i = 0; i < strmax; i++) {
573fdd4e1e0SJan Lentfer 	if (Strings[i] == ABSENT_STRING) {
574fdd4e1e0SJan Lentfer 	    offsets[i] = -1;
575fdd4e1e0SJan Lentfer 	} else if (Strings[i] == CANCELLED_STRING) {
576fdd4e1e0SJan Lentfer 	    offsets[i] = -2;
577fdd4e1e0SJan Lentfer 	} else {
57800d8f3c4SJohn Marino 	    offsets[i] = (short) nextfree;
57900d8f3c4SJohn Marino 	    nextfree += (int) strlen(Strings[i]) + 1;
5801d102085SJan Lentfer 	    TRACE_OUT(("put Strings[%d]=%s(%d)", (int) i,
5811d102085SJan Lentfer 		       _nc_visbuf(Strings[i]), (int) nextfree));
582fdd4e1e0SJan Lentfer 	}
583fdd4e1e0SJan Lentfer     }
584fdd4e1e0SJan Lentfer     return nextfree;
585fdd4e1e0SJan Lentfer }
586fdd4e1e0SJan Lentfer 
587*32bb5217SDaniel Fojt static size_t
convert_shorts(unsigned char * buf,short * Numbers,size_t count)58800d8f3c4SJohn Marino convert_shorts(unsigned char *buf, short *Numbers, size_t count)
589fdd4e1e0SJan Lentfer {
59000d8f3c4SJohn Marino     size_t i;
591fdd4e1e0SJan Lentfer     for (i = 0; i < count; i++) {
592fdd4e1e0SJan Lentfer 	if (Numbers[i] == ABSENT_NUMERIC) {	/* HI/LO won't work */
593fdd4e1e0SJan Lentfer 	    buf[2 * i] = buf[2 * i + 1] = 0377;
594fdd4e1e0SJan Lentfer 	} else if (Numbers[i] == CANCELLED_NUMERIC) {	/* HI/LO won't work */
595fdd4e1e0SJan Lentfer 	    buf[2 * i] = 0376;
596fdd4e1e0SJan Lentfer 	    buf[2 * i + 1] = 0377;
597fdd4e1e0SJan Lentfer 	} else {
598fdd4e1e0SJan Lentfer 	    LITTLE_ENDIAN(buf + 2 * i, Numbers[i]);
59900d8f3c4SJohn Marino 	    TRACE_OUT(("put Numbers[%u]=%d", (unsigned) i, Numbers[i]));
600fdd4e1e0SJan Lentfer 	}
601fdd4e1e0SJan Lentfer     }
602*32bb5217SDaniel Fojt     return SIZEOF_SHORT;
603fdd4e1e0SJan Lentfer }
604fdd4e1e0SJan Lentfer 
605*32bb5217SDaniel Fojt #if NCURSES_EXT_NUMBERS
606*32bb5217SDaniel Fojt static size_t
convert_16bit(unsigned char * buf,NCURSES_INT2 * Numbers,size_t count)607*32bb5217SDaniel Fojt convert_16bit(unsigned char *buf, NCURSES_INT2 *Numbers, size_t count)
608*32bb5217SDaniel Fojt {
609*32bb5217SDaniel Fojt     size_t i, j;
610*32bb5217SDaniel Fojt     size_t size = SIZEOF_SHORT;
611*32bb5217SDaniel Fojt     for (i = 0; i < count; i++) {
612*32bb5217SDaniel Fojt 	unsigned value = (unsigned) Numbers[i];
613*32bb5217SDaniel Fojt 	TRACE_NUM(i);
614*32bb5217SDaniel Fojt 	for (j = 0; j < size; ++j) {
615*32bb5217SDaniel Fojt 	    *buf++ = value & 0xff;
616*32bb5217SDaniel Fojt 	    value >>= 8;
617*32bb5217SDaniel Fojt 	}
618*32bb5217SDaniel Fojt     }
619*32bb5217SDaniel Fojt     return size;
620*32bb5217SDaniel Fojt }
621*32bb5217SDaniel Fojt 
622*32bb5217SDaniel Fojt static size_t
convert_32bit(unsigned char * buf,NCURSES_INT2 * Numbers,size_t count)623*32bb5217SDaniel Fojt convert_32bit(unsigned char *buf, NCURSES_INT2 *Numbers, size_t count)
624*32bb5217SDaniel Fojt {
625*32bb5217SDaniel Fojt     size_t i, j;
626*32bb5217SDaniel Fojt     size_t size = SIZEOF_INT2;
627*32bb5217SDaniel Fojt     for (i = 0; i < count; i++) {
628*32bb5217SDaniel Fojt 	unsigned value = (unsigned) Numbers[i];
629*32bb5217SDaniel Fojt 	TRACE_NUM(i);
630*32bb5217SDaniel Fojt 	for (j = 0; j < size; ++j) {
631*32bb5217SDaniel Fojt 	    *buf++ = value & 0xff;
632*32bb5217SDaniel Fojt 	    value >>= 8;
633*32bb5217SDaniel Fojt 	}
634*32bb5217SDaniel Fojt     }
635*32bb5217SDaniel Fojt     return size;
636*32bb5217SDaniel Fojt }
637*32bb5217SDaniel Fojt #endif
638*32bb5217SDaniel Fojt 
639fdd4e1e0SJan Lentfer #define even_boundary(value) \
6401d102085SJan Lentfer 	    ((value) % 2 != 0 && Write(&zero, sizeof(char), 1) != 1)
6411d102085SJan Lentfer 
6421d102085SJan Lentfer #if NCURSES_XNAMES
6431d102085SJan Lentfer static unsigned
extended_Booleans(TERMTYPE2 * tp)644*32bb5217SDaniel Fojt extended_Booleans(TERMTYPE2 *tp)
6451d102085SJan Lentfer {
64600d8f3c4SJohn Marino     unsigned result = 0;
64700d8f3c4SJohn Marino     unsigned i;
6481d102085SJan Lentfer 
6491d102085SJan Lentfer     for (i = 0; i < tp->ext_Booleans; ++i) {
6501d102085SJan Lentfer 	if (tp->Booleans[BOOLCOUNT + i] == TRUE)
6511d102085SJan Lentfer 	    result = (i + 1);
6521d102085SJan Lentfer     }
6531d102085SJan Lentfer     return result;
6541d102085SJan Lentfer }
6551d102085SJan Lentfer 
6561d102085SJan Lentfer static unsigned
extended_Numbers(TERMTYPE2 * tp)657*32bb5217SDaniel Fojt extended_Numbers(TERMTYPE2 *tp)
6581d102085SJan Lentfer {
65900d8f3c4SJohn Marino     unsigned result = 0;
66000d8f3c4SJohn Marino     unsigned i;
6611d102085SJan Lentfer 
6621d102085SJan Lentfer     for (i = 0; i < tp->ext_Numbers; ++i) {
6631d102085SJan Lentfer 	if (tp->Numbers[NUMCOUNT + i] != ABSENT_NUMERIC)
6641d102085SJan Lentfer 	    result = (i + 1);
6651d102085SJan Lentfer     }
6661d102085SJan Lentfer     return result;
6671d102085SJan Lentfer }
6681d102085SJan Lentfer 
6691d102085SJan Lentfer static unsigned
extended_Strings(TERMTYPE2 * tp)670*32bb5217SDaniel Fojt extended_Strings(TERMTYPE2 *tp)
6711d102085SJan Lentfer {
6721d102085SJan Lentfer     unsigned short result = 0;
6731d102085SJan Lentfer     unsigned short i;
6741d102085SJan Lentfer 
6751d102085SJan Lentfer     for (i = 0; i < tp->ext_Strings; ++i) {
6761d102085SJan Lentfer 	if (tp->Strings[STRCOUNT + i] != ABSENT_STRING)
67700d8f3c4SJohn Marino 	    result = (unsigned short) (i + 1);
6781d102085SJan Lentfer     }
6791d102085SJan Lentfer     return result;
6801d102085SJan Lentfer }
6811d102085SJan Lentfer 
6821d102085SJan Lentfer /*
6831d102085SJan Lentfer  * _nc_align_termtype() will extend entries that are referenced in a use=
6841d102085SJan Lentfer  * clause - discard the unneeded data.
6851d102085SJan Lentfer  */
6861d102085SJan Lentfer static bool
extended_object(TERMTYPE2 * tp)687*32bb5217SDaniel Fojt extended_object(TERMTYPE2 *tp)
6881d102085SJan Lentfer {
6891d102085SJan Lentfer     bool result = FALSE;
6901d102085SJan Lentfer 
6911d102085SJan Lentfer     if (_nc_user_definable) {
6921d102085SJan Lentfer 	result = ((extended_Booleans(tp)
6931d102085SJan Lentfer 		   + extended_Numbers(tp)
6941d102085SJan Lentfer 		   + extended_Strings(tp)) != 0);
6951d102085SJan Lentfer     }
6961d102085SJan Lentfer     return result;
6971d102085SJan Lentfer }
6981d102085SJan Lentfer #endif
699fdd4e1e0SJan Lentfer 
7003468e90cSJohn Marino NCURSES_EXPORT(int)
_nc_write_object(TERMTYPE2 * tp,char * buffer,unsigned * offset,unsigned limit)701*32bb5217SDaniel Fojt _nc_write_object(TERMTYPE2 *tp, char *buffer, unsigned *offset, unsigned limit)
702fdd4e1e0SJan Lentfer {
703fdd4e1e0SJan Lentfer     char *namelist;
704*32bb5217SDaniel Fojt     size_t namelen, boolmax, nummax, strmax, numlen;
705fdd4e1e0SJan Lentfer     char zero = '\0';
706fdd4e1e0SJan Lentfer     size_t i;
70700d8f3c4SJohn Marino     int nextfree;
708fdd4e1e0SJan Lentfer     short offsets[MAX_ENTRY_SIZE / 2];
709fdd4e1e0SJan Lentfer     unsigned char buf[MAX_ENTRY_SIZE];
710fdd4e1e0SJan Lentfer     unsigned last_bool = BOOLWRITE;
711fdd4e1e0SJan Lentfer     unsigned last_num = NUMWRITE;
712fdd4e1e0SJan Lentfer     unsigned last_str = STRWRITE;
713*32bb5217SDaniel Fojt #if NCURSES_EXT_NUMBERS
714*32bb5217SDaniel Fojt     bool need_ints = FALSE;
715*32bb5217SDaniel Fojt     size_t (*convert_numbers) (unsigned char *, NCURSES_INT2 *, size_t) = convert_32bit;
716*32bb5217SDaniel Fojt #else
717*32bb5217SDaniel Fojt #define convert_numbers convert_shorts
718*32bb5217SDaniel Fojt #endif
719fdd4e1e0SJan Lentfer 
720fdd4e1e0SJan Lentfer #if NCURSES_XNAMES
721fdd4e1e0SJan Lentfer     /*
722fdd4e1e0SJan Lentfer      * Normally we limit the list of values to exclude the "obsolete"
723fdd4e1e0SJan Lentfer      * capabilities.  However, if we are accepting extended names, add
724fdd4e1e0SJan Lentfer      * these as well, since they are used for supporting translation
725fdd4e1e0SJan Lentfer      * to/from termcap.
726fdd4e1e0SJan Lentfer      */
727fdd4e1e0SJan Lentfer     if (_nc_user_definable) {
728fdd4e1e0SJan Lentfer 	last_bool = BOOLCOUNT;
729fdd4e1e0SJan Lentfer 	last_num = NUMCOUNT;
730fdd4e1e0SJan Lentfer 	last_str = STRCOUNT;
731fdd4e1e0SJan Lentfer     }
732fdd4e1e0SJan Lentfer #endif
733fdd4e1e0SJan Lentfer 
734fdd4e1e0SJan Lentfer     namelist = tp->term_names;
735fdd4e1e0SJan Lentfer     namelen = strlen(namelist) + 1;
736fdd4e1e0SJan Lentfer 
737fdd4e1e0SJan Lentfer     boolmax = 0;
738fdd4e1e0SJan Lentfer     for (i = 0; i < last_bool; i++) {
739*32bb5217SDaniel Fojt 	if (tp->Booleans[i] == TRUE) {
740fdd4e1e0SJan Lentfer 	    boolmax = i + 1;
741fdd4e1e0SJan Lentfer 	}
742*32bb5217SDaniel Fojt     }
743fdd4e1e0SJan Lentfer 
744fdd4e1e0SJan Lentfer     nummax = 0;
745fdd4e1e0SJan Lentfer     for (i = 0; i < last_num; i++) {
746*32bb5217SDaniel Fojt 	if (tp->Numbers[i] != ABSENT_NUMERIC) {
747fdd4e1e0SJan Lentfer 	    nummax = i + 1;
748*32bb5217SDaniel Fojt #if NCURSES_EXT_NUMBERS
749*32bb5217SDaniel Fojt 	    if (tp->Numbers[i] > MAX_OF_TYPE(NCURSES_COLOR_T)) {
750*32bb5217SDaniel Fojt 		need_ints = TRUE;
751*32bb5217SDaniel Fojt 	    }
752*32bb5217SDaniel Fojt #endif
753*32bb5217SDaniel Fojt 	}
754fdd4e1e0SJan Lentfer     }
755fdd4e1e0SJan Lentfer 
756fdd4e1e0SJan Lentfer     strmax = 0;
757fdd4e1e0SJan Lentfer     for (i = 0; i < last_str; i++) {
758fdd4e1e0SJan Lentfer 	if (tp->Strings[i] != ABSENT_STRING)
759fdd4e1e0SJan Lentfer 	    strmax = i + 1;
760fdd4e1e0SJan Lentfer     }
761fdd4e1e0SJan Lentfer 
762fdd4e1e0SJan Lentfer     nextfree = compute_offsets(tp->Strings, strmax, offsets);
763fdd4e1e0SJan Lentfer 
764fdd4e1e0SJan Lentfer     /* fill in the header */
765*32bb5217SDaniel Fojt #if NCURSES_EXT_NUMBERS
766*32bb5217SDaniel Fojt     if (need_ints) {
767*32bb5217SDaniel Fojt 	convert_numbers = convert_32bit;
768*32bb5217SDaniel Fojt 	LITTLE_ENDIAN(buf, MAGIC2);
769*32bb5217SDaniel Fojt     } else {
770*32bb5217SDaniel Fojt 	convert_numbers = convert_16bit;
771fdd4e1e0SJan Lentfer 	LITTLE_ENDIAN(buf, MAGIC);
772*32bb5217SDaniel Fojt     }
773*32bb5217SDaniel Fojt #else
774*32bb5217SDaniel Fojt     LITTLE_ENDIAN(buf, MAGIC);
775*32bb5217SDaniel Fojt #endif
776fdd4e1e0SJan Lentfer     LITTLE_ENDIAN(buf + 2, min(namelen, MAX_NAME_SIZE + 1));
777fdd4e1e0SJan Lentfer     LITTLE_ENDIAN(buf + 4, boolmax);
778fdd4e1e0SJan Lentfer     LITTLE_ENDIAN(buf + 6, nummax);
779fdd4e1e0SJan Lentfer     LITTLE_ENDIAN(buf + 8, strmax);
780fdd4e1e0SJan Lentfer     LITTLE_ENDIAN(buf + 10, nextfree);
781fdd4e1e0SJan Lentfer 
782fdd4e1e0SJan Lentfer     /* write out the header */
7831d102085SJan Lentfer     TRACE_OUT(("Header of %s @%d", namelist, *offset));
7841d102085SJan Lentfer     if (Write(buf, 12, 1) != 1
785*32bb5217SDaniel Fojt 	|| Write(namelist, sizeof(char), namelen) != namelen) {
786fdd4e1e0SJan Lentfer 	return (ERR);
787*32bb5217SDaniel Fojt     }
788fdd4e1e0SJan Lentfer 
789*32bb5217SDaniel Fojt     for (i = 0; i < boolmax; i++) {
790*32bb5217SDaniel Fojt 	if (tp->Booleans[i] == TRUE) {
791fdd4e1e0SJan Lentfer 	    buf[i] = TRUE;
792*32bb5217SDaniel Fojt 	} else {
793fdd4e1e0SJan Lentfer 	    buf[i] = FALSE;
794*32bb5217SDaniel Fojt 	}
795*32bb5217SDaniel Fojt     }
796*32bb5217SDaniel Fojt     if (Write(buf, sizeof(char), boolmax) != boolmax) {
797fdd4e1e0SJan Lentfer 	return (ERR);
798*32bb5217SDaniel Fojt     }
799fdd4e1e0SJan Lentfer 
800*32bb5217SDaniel Fojt     if (even_boundary(namelen + boolmax)) {
801fdd4e1e0SJan Lentfer 	return (ERR);
802*32bb5217SDaniel Fojt     }
803fdd4e1e0SJan Lentfer 
8041d102085SJan Lentfer     TRACE_OUT(("Numerics begin at %04x", *offset));
805fdd4e1e0SJan Lentfer 
806fdd4e1e0SJan Lentfer     /* the numerics */
807*32bb5217SDaniel Fojt     numlen = convert_numbers(buf, tp->Numbers, nummax);
808*32bb5217SDaniel Fojt     if (Write(buf, numlen, nummax) != nummax) {
809fdd4e1e0SJan Lentfer 	return (ERR);
810*32bb5217SDaniel Fojt     }
811fdd4e1e0SJan Lentfer 
8121d102085SJan Lentfer     TRACE_OUT(("String offsets begin at %04x", *offset));
813fdd4e1e0SJan Lentfer 
814fdd4e1e0SJan Lentfer     /* the string offsets */
815fdd4e1e0SJan Lentfer     convert_shorts(buf, offsets, strmax);
816*32bb5217SDaniel Fojt     if (Write(buf, SIZEOF_SHORT, strmax) != strmax) {
817fdd4e1e0SJan Lentfer 	return (ERR);
818*32bb5217SDaniel Fojt     }
819fdd4e1e0SJan Lentfer 
8201d102085SJan Lentfer     TRACE_OUT(("String table begins at %04x", *offset));
821fdd4e1e0SJan Lentfer 
822fdd4e1e0SJan Lentfer     /* the strings */
823*32bb5217SDaniel Fojt     for (i = 0; i < strmax; i++) {
824*32bb5217SDaniel Fojt 	if (VALID_STRING(tp->Strings[i])) {
825*32bb5217SDaniel Fojt 	    if (!WRITE_STRING(tp->Strings[i])) {
826fdd4e1e0SJan Lentfer 		return (ERR);
827*32bb5217SDaniel Fojt 	    }
828*32bb5217SDaniel Fojt 	}
829*32bb5217SDaniel Fojt     }
830fdd4e1e0SJan Lentfer 
831fdd4e1e0SJan Lentfer #if NCURSES_XNAMES
8321d102085SJan Lentfer     if (extended_object(tp)) {
833*32bb5217SDaniel Fojt 	unsigned ext_total = (unsigned) NUM_EXT_NAMES(tp);
834*32bb5217SDaniel Fojt 	unsigned ext_usage = ext_total;
835fdd4e1e0SJan Lentfer 
836*32bb5217SDaniel Fojt 	if (even_boundary(nextfree)) {
837fdd4e1e0SJan Lentfer 	    return (ERR);
838*32bb5217SDaniel Fojt 	}
839fdd4e1e0SJan Lentfer 
8401d102085SJan Lentfer 	nextfree = compute_offsets(tp->Strings + STRCOUNT,
8413468e90cSJohn Marino 				   (size_t) tp->ext_Strings,
8421d102085SJan Lentfer 				   offsets);
843fdd4e1e0SJan Lentfer 	TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree));
8441d102085SJan Lentfer 
845*32bb5217SDaniel Fojt 	if (tp->ext_Strings >= SIZEOF(offsets)) {
8461d102085SJan Lentfer 	    return (ERR);
847*32bb5217SDaniel Fojt 	}
8481d102085SJan Lentfer 
8491d102085SJan Lentfer 	nextfree += compute_offsets(tp->ext_Names,
850*32bb5217SDaniel Fojt 				    (size_t) ext_total,
8511d102085SJan Lentfer 				    offsets + tp->ext_Strings);
852fdd4e1e0SJan Lentfer 	TRACE_OUT(("after extended capnames, nextfree=%d", nextfree));
853*32bb5217SDaniel Fojt 	strmax = tp->ext_Strings + ext_total;
854*32bb5217SDaniel Fojt 	for (i = 0; i < tp->ext_Strings; ++i) {
855*32bb5217SDaniel Fojt 	    if (VALID_STRING(tp->Strings[i + STRCOUNT])) {
856*32bb5217SDaniel Fojt 		ext_usage++;
857*32bb5217SDaniel Fojt 	    }
858*32bb5217SDaniel Fojt 	}
859*32bb5217SDaniel Fojt 	TRACE_OUT(("will write %u/%lu strings", ext_usage, (unsigned long) strmax));
860fdd4e1e0SJan Lentfer 
861fdd4e1e0SJan Lentfer 	/*
862fdd4e1e0SJan Lentfer 	 * Write the extended header
863fdd4e1e0SJan Lentfer 	 */
864fdd4e1e0SJan Lentfer 	LITTLE_ENDIAN(buf + 0, tp->ext_Booleans);
865fdd4e1e0SJan Lentfer 	LITTLE_ENDIAN(buf + 2, tp->ext_Numbers);
866fdd4e1e0SJan Lentfer 	LITTLE_ENDIAN(buf + 4, tp->ext_Strings);
867*32bb5217SDaniel Fojt 	LITTLE_ENDIAN(buf + 6, ext_usage);
868fdd4e1e0SJan Lentfer 	LITTLE_ENDIAN(buf + 8, nextfree);
8691d102085SJan Lentfer 	TRACE_OUT(("WRITE extended-header @%d", *offset));
870*32bb5217SDaniel Fojt 	if (Write(buf, 10, 1) != 1) {
871fdd4e1e0SJan Lentfer 	    return (ERR);
872*32bb5217SDaniel Fojt 	}
873fdd4e1e0SJan Lentfer 
8741d102085SJan Lentfer 	TRACE_OUT(("WRITE %d booleans @%d", tp->ext_Booleans, *offset));
875fdd4e1e0SJan Lentfer 	if (tp->ext_Booleans
8761d102085SJan Lentfer 	    && Write(tp->Booleans + BOOLCOUNT, sizeof(char),
877*32bb5217SDaniel Fojt 		     tp->ext_Booleans) != tp->ext_Booleans) {
878fdd4e1e0SJan Lentfer 	    return (ERR);
879*32bb5217SDaniel Fojt 	}
880fdd4e1e0SJan Lentfer 
881*32bb5217SDaniel Fojt 	if (even_boundary(tp->ext_Booleans)) {
882fdd4e1e0SJan Lentfer 	    return (ERR);
883*32bb5217SDaniel Fojt 	}
884fdd4e1e0SJan Lentfer 
8851d102085SJan Lentfer 	TRACE_OUT(("WRITE %d numbers @%d", tp->ext_Numbers, *offset));
886fdd4e1e0SJan Lentfer 	if (tp->ext_Numbers) {
887*32bb5217SDaniel Fojt 	    numlen = convert_numbers(buf, tp->Numbers + NUMCOUNT, (size_t) tp->ext_Numbers);
888*32bb5217SDaniel Fojt 	    if (Write(buf, numlen, tp->ext_Numbers) != tp->ext_Numbers) {
889fdd4e1e0SJan Lentfer 		return (ERR);
890fdd4e1e0SJan Lentfer 	    }
891*32bb5217SDaniel Fojt 	}
892fdd4e1e0SJan Lentfer 
893fdd4e1e0SJan Lentfer 	/*
894fdd4e1e0SJan Lentfer 	 * Convert the offsets for the ext_Strings and ext_Names tables,
895fdd4e1e0SJan Lentfer 	 * in that order.
896fdd4e1e0SJan Lentfer 	 */
897fdd4e1e0SJan Lentfer 	convert_shorts(buf, offsets, strmax);
8981d102085SJan Lentfer 	TRACE_OUT(("WRITE offsets @%d", *offset));
899*32bb5217SDaniel Fojt 	if (Write(buf, SIZEOF_SHORT, strmax) != strmax) {
900fdd4e1e0SJan Lentfer 	    return (ERR);
901*32bb5217SDaniel Fojt 	}
902fdd4e1e0SJan Lentfer 
903fdd4e1e0SJan Lentfer 	/*
904fdd4e1e0SJan Lentfer 	 * Write the string table after the offset tables so we do not
905fdd4e1e0SJan Lentfer 	 * have to do anything about alignment.
906fdd4e1e0SJan Lentfer 	 */
907fdd4e1e0SJan Lentfer 	for (i = 0; i < tp->ext_Strings; i++) {
908fdd4e1e0SJan Lentfer 	    if (VALID_STRING(tp->Strings[i + STRCOUNT])) {
9091d102085SJan Lentfer 		TRACE_OUT(("WRITE ext_Strings[%d]=%s", (int) i,
910fdd4e1e0SJan Lentfer 			   _nc_visbuf(tp->Strings[i + STRCOUNT])));
911*32bb5217SDaniel Fojt 		if (!WRITE_STRING(tp->Strings[i + STRCOUNT])) {
912fdd4e1e0SJan Lentfer 		    return (ERR);
913fdd4e1e0SJan Lentfer 		}
914fdd4e1e0SJan Lentfer 	    }
915*32bb5217SDaniel Fojt 	}
916fdd4e1e0SJan Lentfer 
917fdd4e1e0SJan Lentfer 	/*
918fdd4e1e0SJan Lentfer 	 * Write the extended names
919fdd4e1e0SJan Lentfer 	 */
920*32bb5217SDaniel Fojt 	for (i = 0; i < ext_total; i++) {
9211d102085SJan Lentfer 	    TRACE_OUT(("WRITE ext_Names[%d]=%s", (int) i, tp->ext_Names[i]));
922*32bb5217SDaniel Fojt 	    if (!WRITE_STRING(tp->ext_Names[i])) {
923fdd4e1e0SJan Lentfer 		return (ERR);
924fdd4e1e0SJan Lentfer 	    }
925*32bb5217SDaniel Fojt 	}
926fdd4e1e0SJan Lentfer 
927fdd4e1e0SJan Lentfer     }
928fdd4e1e0SJan Lentfer #endif /* NCURSES_XNAMES */
929fdd4e1e0SJan Lentfer 
930fdd4e1e0SJan Lentfer     total_written++;
931*32bb5217SDaniel Fojt     total_parts++;
932*32bb5217SDaniel Fojt     total_size = total_size + (int) (*offset + 1);
933fdd4e1e0SJan Lentfer     return (OK);
934fdd4e1e0SJan Lentfer }
935fdd4e1e0SJan Lentfer 
936fdd4e1e0SJan Lentfer /*
937fdd4e1e0SJan Lentfer  * Returns the total number of entries written by this process
938fdd4e1e0SJan Lentfer  */
939fdd4e1e0SJan Lentfer NCURSES_EXPORT(int)
_nc_tic_written(void)940fdd4e1e0SJan Lentfer _nc_tic_written(void)
941fdd4e1e0SJan Lentfer {
942*32bb5217SDaniel Fojt     TR(TRACE_DATABASE, ("_nc_tic_written %d entries, %d parts, %d size",
943*32bb5217SDaniel Fojt 			total_written, total_parts, total_size));
944fdd4e1e0SJan Lentfer     return total_written;
945fdd4e1e0SJan Lentfer }
946