]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/tinfo/write_entry.c
ncurses 5.0
[ncurses.git] / ncurses / tinfo / write_entry.c
similarity index 61%
rename from ncurses/write_entry.c
rename to ncurses/tinfo/write_entry.c
index c0b245479b2fcbc24675065fe62297e1e73da3b2..4829fa936d016d1bb326ea14f17a67b63510b891 100644 (file)
 #include <sys/stat.h>
 
 #include <tic.h>
-#include <term.h>
 #include <term_entry.h>
 
 #ifndef S_ISDIR
 #define S_ISDIR(mode) ((mode & S_IFMT) == S_IFDIR)
 #endif
 
-MODULE_ID("$Id: write_entry.c,v 1.22 1998/02/11 12:13:59 tom Exp $")
+#if 0
+#define TRACE_OUT(p) DEBUG(2, p)
+#else
+#define TRACE_OUT(p) /*nothing*/
+#endif
+
+MODULE_ID("$Id: write_entry.c,v 1.47 1999/07/10 20:29:22 tom Exp $")
 
 static int total_written;
 
@@ -57,7 +62,7 @@ static int write_object(FILE *, TERMTYPE *);
 
 static void write_file(char *filename, TERMTYPE *tp)
 {
-       FILE *fp = fopen(filename, "wb");
+       FILE *fp = (_nc_access(filename, W_OK) == 0) ? fopen(filename, "wb") : 0;
        if (fp == 0) {
                perror(filename);
                _nc_syserr_abort("can't open %s/%s", _nc_tic_dir(0), filename);
@@ -82,15 +87,20 @@ struct      stat    statbuf;
 char   fullpath[PATH_MAX];
 const char *destination = _nc_tic_dir(0);
 
-       if (path == destination || *path == '/')
+       if (path == destination || *path == '/') {
+               if (strlen(path) + 1 > sizeof(fullpath))
+                       return(-1);
                (void)strcpy(fullpath, path);
-       else
+       } else {
+               if (strlen(destination) + strlen(path) + 2 > sizeof(fullpath))
+                       return(-1);
                (void)sprintf(fullpath, "%s/%s", destination, path);
+       }
 
        if ((rc = stat(path, &statbuf)) < 0) {
                rc = mkdir(path, 0777);
        } else {
-               if (access(path, R_OK|W_OK|X_OK) < 0) {
+               if (_nc_access(path, R_OK|W_OK|X_OK) < 0) {
                        rc = -1;        /* permission denied */
                } else if (!(S_ISDIR(statbuf.st_mode))) {
                        rc = -1;        /* not a directory */
@@ -103,6 +113,7 @@ void  _nc_set_writedir(char *dir)
 /* set the write directory for compiled entries */
 {
     const char *destination;
+    char actual[PATH_MAX];
 
     if (dir != 0)
        (void) _nc_tic_dir(dir);
@@ -112,15 +123,10 @@ void  _nc_set_writedir(char *dir)
     destination = _nc_tic_dir(0);
     if (make_directory(destination) < 0)
     {
-       char    *home;
-
-       /* ncurses extension...fall back on user's private directory */
-       if ((home = getenv("HOME")) != (char *)NULL)
-       {
-           char *temp = malloc(sizeof(PRIVATE_INFO) + strlen(home));
-           (void) sprintf(temp, PRIVATE_INFO, home);
-           destination = temp;
+       char    *home = _nc_home_terminfo();
 
+       if (home != 0) {
+           destination = home;
            if (make_directory(destination) < 0)
                _nc_err_abort("%s: permission denied (errno %d)",
                        destination, errno);
@@ -131,8 +137,10 @@ void  _nc_set_writedir(char *dir)
      * Note: because of this code, this logic should be exercised
      * *once only* per run.
      */
-    if (chdir(_nc_tic_dir(destination)) < 0)
+    if (chdir(_nc_tic_dir(destination)) < 0
+     || getcwd(actual, sizeof(actual)) == 0)
        _nc_err_abort("%s: not a directory", destination);
+    _nc_keep_tic_dir(strdup(actual));
 }
 
 /*
@@ -279,6 +287,10 @@ static time_t      start_time;             /* time at start of writes */
                        _nc_warning("terminal alias %s too long.", ptr);
                        continue;
                }
+               if (strchr(ptr, '/') != 0) {
+                       _nc_warning("cannot link alias %s.", ptr);
+                       continue;
+               }
 
                check_writeable(ptr[0]);
                sprintf(linkname, "%c/%s", ptr[0], ptr);
@@ -291,25 +303,45 @@ static time_t     start_time;             /* time at start of writes */
                {
                        _nc_warning("alias %s multiply defined.", ptr);
                }
-               else
+               else if (_nc_access(linkname, W_OK) == 0)
 #if HAVE_LINK
                {
+                       int code;
 #if USE_SYMLINKS
                        strcpy(symlinkname, "../");
-                       strcat(symlinkname, filename);
+                       strncat(symlinkname, filename, sizeof(symlinkname) - 4);
+                       symlinkname[sizeof(symlinkname) - 1] = '\0';
 #endif /* USE_SYMLINKS */
 #if HAVE_REMOVE
-                       remove(linkname);
+                       code = remove(linkname);
 #else
-                       unlink(linkname);
+                       code = unlink(linkname);
 #endif
+                       if (code != 0 && errno == ENOENT)
+                               code = 0;
 #if USE_SYMLINKS
                        if (symlink(symlinkname, linkname) < 0)
 #else
                        if (link(filename, linkname) < 0)
 #endif /* USE_SYMLINKS */
-                           _nc_syserr_abort("can't link %s to %s", filename, linkname);
-                       DEBUG(1, ("Linked %s", linkname));
+                       {
+                           /*
+                            * If there wasn't anything there, and we cannot
+                            * link to the target because it is the same as the
+                            * target, then the source must be on a filesystem
+                            * that uses caseless filenames, such as Win32, etc.
+                            */
+                           if (code == 0 && errno == EEXIST)
+                               _nc_warning("can't link %s to %s", filename, linkname);
+                           else if (code == 0 && errno == EPERM)
+                               write_file(linkname, tp);
+                           else
+                               _nc_syserr_abort("can't link %s to %s", filename, linkname);
+                       }
+                       else
+                       {
+                           DEBUG(1, ("Linked %s", linkname));
+                       }
                }
 #else /* just make copies */
                write_file(linkname, tp);
@@ -322,6 +354,46 @@ static time_t      start_time;             /* time at start of writes */
 #define LO(x)                  ((x) % 256)
 #define LITTLE_ENDIAN(p, x)    (p)[0] = LO(x), (p)[1] = HI(x)
 
+#define WRITE_STRING(str) (fwrite(str, sizeof(char), strlen(str) + 1, fp) == strlen(str) + 1)
+
+static int compute_offsets(char **Strings, int strmax, short *offsets)
+{
+    size_t nextfree = 0;
+    int i;
+
+    for (i = 0; i < strmax; i++) {
+       if (Strings[i] == ABSENT_STRING) {
+           offsets[i] = -1;
+       } else if (Strings[i] == CANCELLED_STRING) {
+           offsets[i] = -2;
+       } else {
+           offsets[i] = nextfree;
+           nextfree += strlen(Strings[i]) + 1;
+           TRACE_OUT(("put Strings[%d]=%s(%d)", i, _nc_visbuf(Strings[i]), nextfree));
+       }
+    }
+    return nextfree;
+}
+
+static void convert_shorts(unsigned char *buf, short *Numbers, int count)
+{
+    int i;
+    for (i = 0; i < count; i++) {
+       if (Numbers[i] == -1) {         /* HI/LO won't work */
+           buf[2*i] = buf[2*i + 1] = 0377;
+       } else if (Numbers[i] == -2) {  /* HI/LO won't work */
+           buf[2*i] = 0376;
+           buf[2*i + 1] = 0377;
+       } else {
+           LITTLE_ENDIAN(buf + 2*i, Numbers[i]);
+           TRACE_OUT(("put Numbers[%d]=%d", i, Numbers[i]));
+       }
+    }
+}
+
+#define even_boundary(value) \
+           ((value) % 2 != 0 && fwrite(&zero, sizeof(char), 1, fp) != 1)
+
 static int write_object(FILE *fp, TERMTYPE *tp)
 {
 char           *namelist;
@@ -329,38 +401,35 @@ size_t            namelen, boolmax, nummax, strmax;
 char           zero = '\0';
 size_t         i;
 short          nextfree;
-short          offsets[STRCOUNT];
+short          offsets[MAX_ENTRY_SIZE/2];
 unsigned char  buf[MAX_ENTRY_SIZE];
 
        namelist = tp->term_names;
        namelen = strlen(namelist) + 1;
 
+       /*
+        * BOOLWRITE, etc., are less than BOOLCOUNT because we store some
+        * values internally.
+        */
        boolmax = 0;
-       for (i = 0; i < BOOLWRITE; i++)
-               if (tp->Booleans[i])
-                       boolmax = i+1;
+       for (i = 0; i < BOOLWRITE; i++) {
+           if (tp->Booleans[i])
+               boolmax = i+1;
+       }
 
        nummax = 0;
-       for (i = 0; i < NUMWRITE; i++)
-               if (tp->Numbers[i] != ABSENT_NUMERIC)
-                       nummax = i+1;
+       for (i = 0; i < NUMWRITE; i++) {
+           if (tp->Numbers[i] != ABSENT_NUMERIC)
+               nummax = i+1;
+       }
 
        strmax = 0;
-       for (i = 0; i < STRWRITE; i++)
-               if (tp->Strings[i] != ABSENT_STRING)
-                       strmax = i+1;
+       for (i = 0; i < STRWRITE; i++) {
+           if (tp->Strings[i] != ABSENT_STRING)
+               strmax = i+1;
+       }
 
-       nextfree = 0;
-       for (i = 0; i < strmax; i++)
-           if (tp->Strings[i] == ABSENT_STRING)
-               offsets[i] = -1;
-           else if (tp->Strings[i] == CANCELLED_STRING)
-               offsets[i] = -2;
-           else
-           {
-               offsets[i] = nextfree;
-               nextfree += strlen(tp->Strings[i]) + 1;
-           }
+       nextfree = compute_offsets(tp->Strings, strmax, offsets);
 
        /* fill in the header */
        LITTLE_ENDIAN(buf,    MAGIC);
@@ -371,60 +440,112 @@ unsigned char    buf[MAX_ENTRY_SIZE];
        LITTLE_ENDIAN(buf+10, nextfree);
 
        /* write out the header */
+       TRACE_OUT(("Header of %s @%ld", namelist, ftell(fp)));
        if (fwrite(buf, 12, 1, fp) != 1
-               ||  fwrite(namelist, sizeof(char), (size_t)namelen, fp) != namelen
-               ||  fwrite(tp->Booleans, sizeof(char), (size_t)boolmax, fp) != boolmax)
-               return(ERR);
+           ||  fwrite(namelist, sizeof(char), namelen, fp) != namelen
+           ||  fwrite(tp->Booleans, sizeof(char), boolmax, fp) != boolmax)
+           return(ERR);
 
-       /* the even-boundary padding byte */
-       if ((namelen+boolmax) % 2 != 0 &&  fwrite(&zero, sizeof(char), 1, fp) != 1)
-               return(ERR);
+       if (even_boundary(namelen+boolmax))
+           return(ERR);
 
-#ifdef SHOWOFFSET
-       (void) fprintf(stderr, "Numerics begin at %04lx\n", ftell(fp));
-#endif /* SHOWOFFSET */
+       TRACE_OUT(("Numerics begin at %04lx", ftell(fp)));
 
        /* the numerics */
-       for (i = 0; i < nummax; i++)
-       {
-               if (tp->Numbers[i] == -1)       /* HI/LO won't work */
-                       buf[2*i] = buf[2*i + 1] = 0377;
-               else
-                       LITTLE_ENDIAN(buf + 2*i, tp->Numbers[i]);
-       }
-       if (fwrite(buf, 2, (size_t)nummax, fp) != nummax)
-               return(ERR);
+       convert_shorts(buf, tp->Numbers, nummax);
+       if (fwrite(buf, 2, nummax, fp) != nummax)
+           return(ERR);
 
-#ifdef SHOWOFFSET
-       (void) fprintf(stderr, "String offets begin at %04lx\n", ftell(fp));
-#endif /* SHOWOFFSET */
+       TRACE_OUT(("String offsets begin at %04lx", ftell(fp)));
 
        /* the string offsets */
-       for (i = 0; i < strmax; i++)
-               if (offsets[i] == -1)   /* HI/LO won't work */
-                       buf[2*i] = buf[2*i + 1] = 0377;
-               else if (offsets[i] == -2)      /* HI/LO won't work */
-               {
-                       buf[2*i] = 0376;
-                       buf[2*i + 1] = 0377;
-               }
-               else
-                       LITTLE_ENDIAN(buf + 2*i, offsets[i]);
-       if (fwrite(buf, 2, (size_t)strmax, fp) != strmax)
-               return(ERR);
+       convert_shorts(buf, offsets, strmax);
+       if (fwrite(buf, 2, strmax, fp) != strmax)
+           return(ERR);
 
-#ifdef SHOWOFFSET
-       (void) fprintf(stderr, "String table begins at %04lx\n", ftell(fp));
-#endif /* SHOWOFFSET */
+       TRACE_OUT(("String table begins at %04lx", ftell(fp)));
 
        /* the strings */
        for (i = 0; i < strmax; i++)
-           if (tp->Strings[i] != ABSENT_STRING && tp->Strings[i] != CANCELLED_STRING)
-               if (fwrite(tp->Strings[i], sizeof(char), strlen(tp->Strings[i]) + 1, fp) != strlen(tp->Strings[i]) + 1)
+           if (VALID_STRING(tp->Strings[i]))
+               if (!WRITE_STRING(tp->Strings[i]))
+                   return(ERR);
+
+#if NCURSES_XNAMES
+       if (NUM_EXT_NAMES(tp)) {
+           unsigned extcnt = NUM_EXT_NAMES(tp);
+
+           if (even_boundary(nextfree))
+               return(ERR);
+
+           nextfree = compute_offsets(tp->Strings + STRCOUNT, tp->ext_Strings, offsets);
+           TRACE_OUT(("after extended string capabilities, nextfree=%d", nextfree));
+           nextfree += compute_offsets(tp->ext_Names, extcnt, offsets + tp->ext_Strings);
+           TRACE_OUT(("after extended capnames, nextfree=%d", nextfree));
+           strmax = tp->ext_Strings + extcnt;
+
+           /*
+            * Write the extended header
+            */
+           LITTLE_ENDIAN(buf+0, tp->ext_Booleans);
+           LITTLE_ENDIAN(buf+2, tp->ext_Numbers);
+           LITTLE_ENDIAN(buf+4, tp->ext_Strings);
+           LITTLE_ENDIAN(buf+6, strmax);
+           LITTLE_ENDIAN(buf+8, nextfree);
+           TRACE_OUT(("WRITE extended-header @%ld", ftell(fp)));
+           if (fwrite(buf, 10, 1, fp) != 1)
+               return(ERR);
+
+           TRACE_OUT(("WRITE %d booleans @%ld", tp->ext_Booleans, ftell(fp)));
+           if (tp->ext_Booleans
+            && fwrite(tp->Booleans + BOOLCOUNT, sizeof(char), tp->ext_Booleans, fp) != tp->ext_Booleans)
+               return(ERR);
+
+           if (even_boundary(tp->ext_Booleans))
+               return(ERR);
+
+           TRACE_OUT(("WRITE %d numbers @%ld", tp->ext_Numbers, ftell(fp)));
+           if (tp->ext_Numbers) {
+               convert_shorts(buf, tp->Numbers + NUMCOUNT, tp->ext_Numbers);
+               if (fwrite(buf, 2, tp->ext_Numbers, fp) != tp->ext_Numbers)
                    return(ERR);
+           }
+
+           /*
+            * Convert the offsets for the ext_Strings and ext_Names tables,
+            * in that order.
+            */
+           convert_shorts(buf, offsets, strmax);
+           TRACE_OUT(("WRITE offsets @%ld", ftell(fp)));
+           if (fwrite(buf, 2, strmax, fp) != strmax)
+               return(ERR);
+
+           /*
+            * Write the string table after the offset tables so we do not
+            * have to do anything about alignment.
+            */
+           for (i = 0; i < tp->ext_Strings; i++) {
+               if (VALID_STRING(tp->Strings[i+STRCOUNT])) {
+                   TRACE_OUT(("WRITE ext_Strings[%d]=%s", i, _nc_visbuf(tp->Strings[i+STRCOUNT])));
+                   if (!WRITE_STRING(tp->Strings[i+STRCOUNT]))
+                       return(ERR);
+               }
+           }
+
+           /*
+            * Write the extended names
+            */
+           for (i = 0; i < extcnt; i++) {
+               TRACE_OUT(("WRITE ext_Names[%d]=%s", i, tp->ext_Names[i]));
+               if (!WRITE_STRING(tp->ext_Names[i]))
+                   return(ERR);
+           }
+
+       }
+#endif /* NCURSES_XNAMES */
 
        total_written++;
-        return(OK);
+       return(OK);
 }
 
 /*