Subversion Repositories Kolibri OS

Rev

Rev 9952 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. #include <sys/stat.h>
  2. #include <stdio.h>
  3. #include <stdint.h>
  4. #include <stdlib.h>
  5. #include <limits.h>
  6. #include <errno.h>
  7. #include <assert.h>
  8. #include <string.h>
  9. #include <dirent.h>
  10. #include <ctype.h>
  11. #ifndef __MINGW32__
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #include <pwd.h>
  15. #include <unistd.h>
  16. #ifdef HAVE_GLOB_H
  17. #include <glob.h>
  18. #endif
  19. #else
  20. #include <io.h>
  21. #include <shlobj.h>
  22. #endif
  23. #ifdef WITH_LIBARCHIVE
  24. #include <archive.h>
  25. /* For backward compatibility. */
  26. #if ARCHIVE_VERSION_NUMBER < 3001000
  27. #define archive_read_free(...) \
  28.         archive_read_finish(__VA_ARGS__)
  29. #define archive_read_support_filter_all(...) \
  30.         archive_read_support_compression_all(__VA_ARGS__)
  31. #endif
  32. #endif
  33. #include "system.h"
  34.  
  35. #ifdef __MINGW32__
  36. #define mkdir(a, b) mkdir(a)
  37. #if MAX_PATH < PATH_MAX
  38. #error MAX_PATH < PATH_MAX. You should use MAX_PATH.
  39. #endif
  40. #endif
  41.  
  42. static const char *fopen_mode(unsigned int mode)
  43. {
  44.         static const char *modes[4][2] = {
  45.                 { "ab", "a" },
  46.                 { "w+b", "w+" },
  47.                 { "rb", "r" },
  48.                 { NULL, NULL }
  49.         };
  50.         const char *(*cmode)[2] = &modes[0];
  51.  
  52.         if (!(mode & DGEN_APPEND)) {
  53.                 ++cmode;
  54.                 if (!(mode & DGEN_WRITE)) {
  55.                         ++cmode;
  56.                         if (!(mode & DGEN_READ))
  57.                                 ++cmode;
  58.                 }
  59.         }
  60.         return (*cmode)[(!!(mode & DGEN_TEXT))];
  61. }
  62.  
  63. enum path_type {
  64.         PATH_TYPE_UNSPECIFIED,
  65.         PATH_TYPE_RELATIVE,
  66.         PATH_TYPE_ABSOLUTE
  67. };
  68.  
  69. #ifdef __MINGW32__
  70.  
  71. /**
  72.  * Check whether a path is absolute or relative.
  73.  *
  74.  * Examples:
  75.  * /foo/bar, \\foo\\bar, c:/foo/bar are absolute,
  76.  * ./foo/bar, ., .., are relative.
  77.  *
  78.  * @param[in] path Path to parse.
  79.  * @param len Length of path.
  80.  * @return Path type (PATH_TYPE_ABSOLUTE, PATH_TYPE_RELATIVE or
  81.  * PATH_TYPE_UNSPECIFIED).
  82.  */
  83. enum path_type path_type(const char *path, size_t len)
  84. {
  85.         if ((len == 0) || (path[0] == '\0'))
  86.                 return PATH_TYPE_UNSPECIFIED;
  87.         if ((path[0] == '\\') || (path[0] == '/'))
  88.                 return PATH_TYPE_ABSOLUTE;
  89.         if ((path[0] == '.') &&
  90.             (((len == 1) ||
  91.               (path[1] == '\0') || (path[1] == '\\') || (path[1] == '/')) ||
  92.              ((path[1] == '.') &&
  93.               ((len == 2) ||
  94.                (path[2] == '\0') || (path[2] == '\\') || (path[2] == '/')))))
  95.                 return PATH_TYPE_RELATIVE;
  96.         do {
  97.                 if (*(++path) == ':')
  98.                         return PATH_TYPE_ABSOLUTE;
  99.                 --len;
  100.         }
  101.         while ((len) && (*path != '\0') && (*path != '\\') && (*path != '/'));
  102.         return PATH_TYPE_UNSPECIFIED;
  103. }
  104.  
  105. #else /* __MINGW32__ */
  106.  
  107. /**
  108.  * Check whether a path is absolute or relative.
  109.  *
  110.  * Examples:
  111.  * /foo/bar, \\foo\\bar are absolute,
  112.  * ./foo/bar, ., .., are relative.
  113.  *
  114.  * @param[in] path Path to parse.
  115.  * @param len Length of path.
  116.  * @return Path type (PATH_TYPE_ABSOLUTE, PATH_TYPE_RELATIVE or
  117.  * PATH_TYPE_UNSPECIFIED).
  118.  */
  119. enum path_type path_type(const char *path, size_t len)
  120. {
  121.         if ((len == 0) || (path[0] == '\0'))
  122.                 return PATH_TYPE_UNSPECIFIED;
  123.         if (path[0] == '/')
  124.                 return PATH_TYPE_ABSOLUTE;
  125.         if ((path[0] == '.') &&
  126.             (((len == 1) || (path[1] == '\0') || (path[1] == '/')) ||
  127.              ((path[1] == '.') &&
  128.               ((len == 2) || (path[2] == '\0') || (path[2] == '/')))))
  129.                 return PATH_TYPE_RELATIVE;
  130.         return PATH_TYPE_UNSPECIFIED;
  131. }
  132.  
  133. #endif /* __MINGW32__ */
  134.  
  135. /**
  136.  * Return user's home directory.
  137.  * The returned string doesn't have a trailing '/' and must be freed using
  138.  * free() (unless "buf" is provided).
  139.  *
  140.  * @param[in,out] buf Used to store path in. If NULL, memory is allocated.
  141.  * @param[in,out] size Size of "buf" when provided, then the returned path
  142.  * size.
  143.  * @return User's home directory (either as "buf" or a new buffer),
  144.  * NULL in case of error.
  145.  */
  146. char *dgen_userdir(char *buf, size_t *size)
  147. {
  148.         char *path;
  149.         size_t sz_dir;
  150.         size_t sz;
  151. #if !defined __MINGW32__ && !defined _KOLIBRI
  152.         struct passwd *pwd = getpwuid(geteuid());
  153.  
  154.         if ((pwd == NULL) || (pwd->pw_dir == NULL))
  155.                 return NULL;
  156.         sz_dir = strlen(pwd->pw_dir);
  157. #elif defined _KOLIBRI
  158.         char *kos_home = getenv("HOME");
  159.         if (!kos_home)
  160.                 return NULL;
  161.         sz_dir = strlen(kos_home);
  162. #endif
  163.         if (buf != NULL) {
  164.                 sz = *size;
  165. #if     defined __MINGW32__ || defined _KOLIBRI
  166.                 if (sz < PATH_MAX)
  167.                         return NULL;
  168. #else
  169.                 if (sz < (sz_dir + 1))
  170.                         return NULL;
  171. #endif
  172.                 path = buf;
  173.         }
  174.         else {
  175. #if defined __MINGW32__ || defined _KOLIBRI
  176.                 sz = PATH_MAX;
  177. #else
  178.                 sz = (sz_dir + 1);
  179. #endif
  180.                 if ((path = malloc(sz)) == NULL)
  181.                         return NULL;
  182.         }
  183. #ifndef __MINGW32__
  184.         #ifdef _KOLIBRI
  185.         strncpy(path, kos_home, sz_dir);
  186.         #else
  187.         strncpy(path, pwd->pw_dir, sz_dir);
  188.         #endif
  189. #else
  190.         if (SHGetFolderPath(NULL, (CSIDL_PROFILE | CSIDL_FLAG_CREATE),
  191.                             0, 0, path) != S_OK) {
  192.                 if (buf == NULL)
  193.                         free(path);
  194.                 return NULL;
  195.         }
  196.         sz_dir = strlen(path);
  197.         if (sz < (sz_dir + 1)) {
  198.                 if (buf == NULL)
  199.                         free(path);
  200.                 return NULL;
  201.         }
  202. #endif
  203.         path[sz_dir] = '\0';
  204.         if (size != NULL)
  205.                 *size = sz_dir;
  206.         return path;
  207. }
  208.  
  209. /**
  210.  * Return DGen's home directory with an optional subdirectory (or file).
  211.  * The returned string doesn't have a trailing '/' and must be freed using
  212.  * free() (unless "buf" is provided).
  213.  *
  214.  * @param[in,out] buf Buffer to store result in. If NULL, memory is allocated.
  215.  * @param[in,out] size Size of "buf" when provided, then the returned path
  216.  * size.
  217.  * @param[in] sub NUL-terminated string to append to the path.
  218.  * @return DGen's home directory (either as "buf" or a new buffer),
  219.  * NULL in case of error.
  220.  */
  221. char *dgen_dir(char *buf, size_t *size, const char *sub)
  222. {
  223.         char *path;
  224.         size_t sz_dir;
  225.         size_t sz_sub;
  226.         const size_t sz_bd = strlen(DGEN_BASEDIR);
  227.         size_t sz;
  228. #ifndef __MINGW32__
  229.         #ifndef _KOLIBRI
  230.         struct passwd *pwd = getpwuid(geteuid());
  231.         if ((pwd == NULL) || (pwd->pw_dir == NULL))
  232.                 return NULL;
  233.         sz_dir = strlen(pwd->pw_dir);
  234.         #else
  235.         char *kos_home = getenv("HOME");
  236.         if (!kos_home)
  237.                 return NULL;
  238.         sz_dir = strlen(kos_home);
  239.         #endif
  240. #endif
  241.  
  242.         if (sub != NULL)
  243.                 sz_sub = strlen(sub);
  244.         else
  245.                 sz_sub = 0;
  246.         if (buf != NULL) {
  247.                 sz = *size;
  248. #if defined(__MINGW32__) || defined(_KOLIBRI)
  249.                 if (sz < PATH_MAX)
  250.                         return NULL;
  251. #else
  252.                 if (sz < (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1))
  253.                         return NULL;
  254. #endif
  255.                 path = buf;
  256.         }
  257.         else {
  258. #if defined(__MINGW32__) || defined(_KOLIBRI)
  259.                 sz = PATH_MAX;
  260. #else
  261.                 sz = (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1);
  262. #endif
  263.                 if ((path = malloc(sz)) == NULL)
  264.                         return NULL;
  265.         }
  266. #ifndef __MINGW32__
  267.         #ifndef _KOLIBRI
  268.         strncpy(path, pwd->pw_dir, sz_dir);
  269.         #else
  270.         strncpy(path, kos_home, sz_dir);
  271.         #endif
  272. #else
  273.         if (SHGetFolderPath(NULL, (CSIDL_APPDATA | CSIDL_FLAG_CREATE),
  274.                             0, 0, path) != S_OK) {
  275.                 if (buf == NULL)
  276.                         free(path);
  277.                 return NULL;
  278.         }
  279.         sz_dir = strlen(path);
  280.         if (sz < (sz_dir + 1 + sz_bd + !!sz_sub + sz_sub + 1)) {
  281.                 if (buf == NULL)
  282.                         free(path);
  283.                 return NULL;
  284.         }
  285. #endif
  286.         path[(sz_dir++)] = DGEN_DIRSEP[0];
  287.         memcpy(&path[sz_dir], DGEN_BASEDIR, sz_bd);
  288.         sz_dir += sz_bd;
  289.         if (sz_sub) {
  290.                 path[(sz_dir++)] = DGEN_DIRSEP[0];
  291.                 memcpy(&path[sz_dir], sub, sz_sub);
  292.                 sz_dir += sz_sub;
  293.         }
  294.         path[sz_dir] = '\0';
  295.         if (size != NULL)
  296.                 *size = sz_dir;
  297.         return path;
  298. }
  299.  
  300. /**
  301.  * Open a file relative to DGen's home directory (when "relative" is NULL or
  302.  * path_type(relative) returns PATH_TYPE_UNSPECIFIED) and create the directory
  303.  * hierarchy if necessary, unless the file name is already relative to
  304.  * something or found in the current directory if mode contains DGEN_CURRENT.
  305.  *
  306.  * @param[in] relative Subdirectory to look in.
  307.  * @param[in] file File name to open.
  308.  * @param mode Mode flags to use (DGEN_READ, DGEN_WRITE and others).
  309.  * @return File pointer, or NULL in case of error.
  310.  * @see dgen_freopen()
  311.  * @see system.h
  312.  */
  313. FILE *dgen_fopen(const char *relative, const char *file, unsigned int mode)
  314. {
  315.         return dgen_freopen(relative, file, mode, NULL);
  316. }
  317.  
  318. /**
  319.  * @see dgen_fopen()
  320.  */
  321. FILE *dgen_freopen(const char *relative, const char *file, unsigned int mode,
  322.                    FILE *f)
  323. {
  324.         size_t size;
  325.         size_t file_size;
  326.         char *tmp;
  327.         int e = errno;
  328.         const char *fmode = fopen_mode(mode);
  329.         char *path = NULL;
  330.  
  331.         if ((file == NULL) || (file[0] == '\0') || (fmode == NULL))
  332.                 goto error;
  333.         /*
  334.           Try to open the file in the current directory if DGEN_CURRENT
  335.           is specified.
  336.         */
  337.         if (mode & DGEN_CURRENT) {
  338.                 FILE *fd;
  339.  
  340.                 if (f == NULL)
  341.                         fd = fopen(file, fmode);
  342.                 else
  343.                         fd = freopen(file, fmode, f);
  344.                 if (fd != NULL)
  345.                         return fd;
  346.         }
  347.         if (path_type(file, ~0u) != PATH_TYPE_UNSPECIFIED)
  348.                 size = 0;
  349.         else if ((relative == NULL) ||
  350.                  (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
  351.                 if ((path = dgen_dir(NULL, &size, relative)) == NULL)
  352.                         goto error;
  353.         }
  354.         else {
  355.                 if ((path = strdup(relative)) == NULL)
  356.                         goto error;
  357.                 size = strlen(path);
  358.         }
  359.  
  360.         if ((mode & (DGEN_WRITE | DGEN_APPEND)) && (path != NULL))
  361.                 mkdir(path, 0777); /* XXX make that recursive */
  362.  
  363.         file_size = strlen(file);
  364.         if ((tmp = realloc(path, (size + !!size + file_size + 1))) == NULL)
  365.                 goto error;
  366.         path = tmp;
  367.         if (size)
  368.                 path[(size++)] = DGEN_DIRSEP[0];
  369.         memcpy(&path[size], file, file_size);
  370.         size += file_size;
  371.         path[size] = '\0';
  372.         errno = e;
  373.         if (f == NULL)
  374.                 f = fopen(path, fmode);
  375.         else
  376.                 f = freopen(path, fmode, f);
  377.         e = errno;
  378.         free(path);
  379.         errno = e;
  380.         return f;
  381. error:
  382.         free(path);
  383.         errno = EACCES;
  384.         return NULL;
  385. }
  386.  
  387. /**
  388.  * Return the base name in path, like basename() but without allocating
  389.  * anything nor modifying the "path" argument.
  390.  *
  391.  * @param[in] path Path to extract the last component from.
  392.  * @return Last component from "path".
  393.  */
  394. const char *dgen_basename(const char *path)
  395. {
  396.         char *tmp;
  397.  
  398.         while ((tmp = strpbrk(path, DGEN_DIRSEP)) != NULL)
  399.                 path = (tmp + 1);
  400.         return path;
  401. }
  402.  
  403. #define CHUNK_SIZE BUFSIZ
  404.  
  405. struct chunk {
  406.         size_t size;
  407.         struct chunk *next;
  408.         struct chunk *prev;
  409.         uint8_t data[];
  410. };
  411.  
  412. /**
  413.  * Unload pointer returned by load().
  414.  *
  415.  * @param[in] data Pointer to unload.
  416.  */
  417. void unload(uint8_t *data)
  418. {
  419.         struct chunk *chunk = ((struct chunk *)data - 1);
  420.  
  421.         assert(chunk->next == chunk);
  422.         assert(chunk->prev == chunk);
  423.         free(chunk);
  424. }
  425.  
  426. #ifdef HAVE_FTELLO
  427. #define FTELL(f) ftello(f)
  428. #define FSEEK(f, o, w) fseeko((f), (o), (w))
  429. #define FOFFT off_t
  430. #else
  431. #define FTELL(f) ftell(f)
  432. #define FSEEK(f, o, w) fseek((f), (o), (w))
  433. #define FOFFT long
  434. #endif
  435.  
  436. /**
  437.  * Call this when you're done with your file.
  438.  *
  439.  * @param[in,out] context Context returned by load().
  440.  */
  441. void load_finish(void **context)
  442. {
  443. #ifdef WITH_LIBARCHIVE
  444.         struct archive *archive = *context;
  445.  
  446.         if (archive != NULL)
  447.                 archive_read_free(archive);
  448. #endif
  449.         *context = NULL;
  450. }
  451.  
  452. /**
  453.  * Return the remaining file size from the current file offset.
  454.  *
  455.  * @param[in] file File pointer.
  456.  */
  457. static size_t load_size(FILE *file)
  458. {
  459.         FOFFT old = FTELL(file);
  460.         FOFFT pos;
  461.         size_t ret = 0;
  462.  
  463.         if ((old == (FOFFT)-1) ||
  464.             (FSEEK(file, 0, SEEK_END) == -1))
  465.                 return 0;
  466.         if (((pos = FTELL(file)) != (FOFFT)-1) && (pos >= old))
  467.                 ret = (size_t)(pos - old);
  468.         FSEEK(file, old, SEEK_SET);
  469.         return ret;
  470. }
  471.  
  472. /**
  473.  * Allocate a buffer and stuff the file inside using transparent decompression
  474.  * if libarchive is available. If file_size is non-NULL, store the final size
  475.  * there. If max_size is nonzero, refuse to load anything larger.
  476.  * In case the returned value is NULL, errno should contain the error.
  477.  *
  478.  * If an error is returned but errno is 0, EOF has been reached.
  479.  *
  480.  * @param[in,out] context On first call of load() this should point to NULL.
  481.  * @param[out] file_size Final size.
  482.  * @param[in] file File pointer to load data from.
  483.  * @param max_size If nonzero, refuse to load anything larger.
  484.  * @return Buffer containing loaded data.
  485.  */
  486. uint8_t *load(void **context,
  487.               size_t *file_size, FILE *file, size_t max_size)
  488. {
  489.         size_t pos;
  490.         size_t size = 0;
  491.         struct chunk *chunk;
  492.         struct chunk head = { 0, &head, &head };
  493.         size_t chunk_size = load_size(file);
  494.         int error = 0;
  495. #ifdef WITH_LIBARCHIVE
  496.         struct archive *archive = *context;
  497.         struct archive_entry *archive_entry;
  498.  
  499.         if (archive != NULL)
  500.                 goto init_ok;
  501.         archive = archive_read_new();
  502.         *context = archive;
  503.         if (archive == NULL) {
  504.                 error = ENOMEM;
  505.                 goto error;
  506.         }
  507.         archive_read_support_filter_all(archive);
  508.         archive_read_support_format_all(archive);
  509.         archive_read_support_format_raw(archive);
  510.         if (archive_read_open_FILE(archive, file) != ARCHIVE_OK) {
  511.                 error = EIO;
  512.                 goto error;
  513.         }
  514. init_ok:
  515.         switch (archive_read_next_header(archive, &archive_entry)) {
  516.         case ARCHIVE_OK:
  517.                 break;
  518.         case ARCHIVE_EOF:
  519.                 error = 0;
  520.                 goto error;
  521.         default:
  522.                 error = EIO;
  523.                 goto error;
  524.         }
  525. #else
  526.         *context = (void *)0xffff;
  527. #endif
  528.         if (chunk_size == 0)
  529.                 chunk_size = CHUNK_SIZE;
  530.         else if ((max_size != 0) && (chunk_size > max_size))
  531.                 chunk_size = max_size;
  532.         while (1) {
  533.                 pos = 0;
  534.                 chunk = malloc(sizeof(*chunk) + chunk_size);
  535.                 if (chunk == NULL) {
  536.                         error = errno;
  537.                         goto error;
  538.                 }
  539.                 chunk->size = chunk_size;
  540.                 chunk->next = &head;
  541.                 chunk->prev = head.prev;
  542.                 chunk->prev->next = chunk;
  543.                 head.prev = chunk;
  544.                 do {
  545.                         size_t i;
  546. #ifdef WITH_LIBARCHIVE
  547.                         ssize_t j;
  548.  
  549.                         j = archive_read_data(archive, &chunk->data[pos],
  550.                                               (chunk->size - pos));
  551.                         /*
  552.                           Don't bother with ARCHIVE_WARN and ARCHIVE_RETRY,
  553.                           consider any negative value an error.
  554.                         */
  555.                         if (j < 0) {
  556.                                 error = EIO;
  557.                                 goto error;
  558.                         }
  559.                         i = (size_t)j;
  560. #else
  561.                         i = fread(&chunk->data[pos], 1, (chunk->size - pos),
  562.                                   file);
  563. #endif
  564.                         if (i == 0) {
  565.                                 chunk->size = pos;
  566. #ifndef WITH_LIBARCHIVE
  567.                                 if (ferror(file)) {
  568.                                         error = EIO;
  569.                                         goto error;
  570.                                 }
  571.                                 assert(feof(file));
  572. #endif
  573.                                 goto process;
  574.                         }
  575.                         pos += i;
  576.                         size += i;
  577.                         if ((max_size != 0) && (size > max_size)) {
  578.                                 error = EFBIG;
  579.                                 goto error;
  580.                         }
  581.                 }
  582.                 while (pos != chunk->size);
  583.                 chunk_size = CHUNK_SIZE;
  584.         }
  585. process:
  586.         chunk = realloc(head.next, (sizeof(*chunk) + size));
  587.         if (chunk == NULL) {
  588.                 error = errno;
  589.                 goto error;
  590.         }
  591.         chunk->next->prev = chunk;
  592.         head.next = chunk;
  593.         pos = chunk->size;
  594.         chunk->size = size;
  595.         chunk = chunk->next;
  596.         while (chunk != &head) {
  597.                 struct chunk *next = chunk->next;
  598.  
  599.                 memcpy(&head.next->data[pos], chunk->data, chunk->size);
  600.                 pos += chunk->size;
  601.                 chunk->next->prev = chunk->prev;
  602.                 chunk->prev->next = chunk->next;
  603.                 free(chunk);
  604.                 chunk = next;
  605.         }
  606.         chunk = head.next;
  607.         chunk->prev = chunk;
  608.         chunk->next = chunk;
  609.         if (file_size != NULL)
  610.                 *file_size = chunk->size;
  611.         return chunk->data;
  612. error:
  613. #ifdef WITH_LIBARCHIVE
  614.         load_finish(context);
  615. #endif
  616.         chunk = head.next;
  617.         while (chunk != &head) {
  618.                 struct chunk *next = chunk->next;
  619.  
  620.                 free(chunk);
  621.                 chunk = next;
  622.         }
  623.         errno = error;
  624.         return NULL;
  625. }
  626.  
  627. /**
  628.  * Free NULL-terminated list of strings and set source pointer to NULL.
  629.  * This function can skip a given number of indices (starting from 0)
  630.  * which won't be freed.
  631.  *
  632.  * @param[in,out] pppc Pointer to an array of strings.
  633.  * @param skip Number of indices to skip in *pppc[].
  634.  */
  635. static void free_pppc(char ***pppc, size_t skip)
  636. {
  637.         char **p = *pppc;
  638.         size_t i;
  639.  
  640.         if (p == NULL)
  641.                 return;
  642.         *pppc = NULL;
  643.         for (i = 0; (p[i] != NULL); ++i) {
  644.                 if (skip == 0)
  645.                         free(p[i]);
  646.                 else
  647.                         --skip;
  648.         }
  649.         free(p);
  650. }
  651.  
  652. /**
  653.  * Return a list of path names that match "len" characters of "path" on the
  654.  * file system, or NULL if none was found or if an error occured.
  655.  *
  656.  * @param[in] path Path name to match.
  657.  * @param len Number of characters in "path" to match.
  658.  * @return List of matching path names or NULL.
  659.  */
  660. static char **complete_path_simple(const char *path, size_t len)
  661. {
  662.         size_t rlen;
  663.         const char *cpl;
  664.         char *root;
  665.         struct dirent *dent;
  666.         DIR *dir;
  667.         char **ret = NULL;
  668.         size_t ret_size = 256;
  669.         size_t ret_used = 0;
  670.         struct stat st;
  671.  
  672.         if ((rlen = strlen(path)) < len)
  673.                 len = rlen;
  674.         cpl = path;
  675.         while (((root = strpbrk(cpl, DGEN_DIRSEP)) != NULL) &&
  676.                (root < (path + len)))
  677.                 cpl = (root + 1);
  678.         rlen = (cpl - path);
  679.         len -= rlen;
  680.         if (rlen == 0) {
  681.                 path = "." DGEN_DIRSEP;
  682.                 rlen = 2;
  683.         }
  684.         if ((root = malloc(rlen + 1)) == NULL)
  685.                 return NULL;
  686.         memcpy(root, path, rlen);
  687.         root[rlen] = '\0';
  688.         if (((dir = opendir(root)) == NULL) ||
  689.             ((ret = malloc(sizeof(*ret) * ret_size)) == NULL))
  690.                 goto error;
  691.         ret[(ret_used++)] = NULL;
  692.         while ((dent = readdir(dir)) != NULL) {
  693.                 size_t i;
  694.                 char *t;
  695.  
  696.                 if ((cpl[0] != '\0') && (strncmp(cpl, dent->d_name, len)))
  697.                         continue;
  698.                 /* Remove "." and ".." entries. */
  699.                 if ((dent->d_name[0] == '.') &&
  700.                     ((dent->d_name[1] == '\0') ||
  701.                      ((dent->d_name[1] == '.') && (dent->d_name[2] == '\0'))))
  702.                         continue;
  703.                 if (ret_used == ret_size) {
  704.                         char **rt;
  705.  
  706.                         ret_size *= 2;
  707.                         if ((rt = realloc(ret,
  708.                                           (sizeof(*rt) * ret_size))) == NULL)
  709.                                 break;
  710.                         ret = rt;
  711.                 }
  712.                 i = strlen(dent->d_name);
  713.                 /* Allocate one extra char in case it's a directory. */
  714.                 if ((t = malloc(rlen + i + 1 + 1)) == NULL)
  715.                         break;
  716.                 memcpy(t, root, rlen);
  717.                 memcpy(&t[rlen], dent->d_name, i);
  718.                 t[(rlen + i)] = '\0';
  719.                 if ((stat(t, &st) != -1) && (S_ISDIR(st.st_mode))) {
  720.                         t[(rlen + (i++))] = DGEN_DIRSEP[0];
  721.                         t[(rlen + i)] = '\0';
  722.                 }
  723.                 for (i = 0; (ret[i] != NULL); ++i)
  724.                         if (strcmp(dent->d_name, &ret[i][rlen]) < 0)
  725.                                 break;
  726.                 memmove(&ret[(i + 1)], &ret[i],
  727.                         (sizeof(*ret) * (ret_used - i)));
  728.                 ret[i] = t;
  729.                 ++ret_used;
  730.         }
  731.         closedir(dir);
  732.         free(root);
  733.         if (ret[0] != NULL)
  734.                 return ret;
  735.         free(ret);
  736.         return NULL;
  737. error:
  738.         if (dir != NULL)
  739.                 closedir(dir);
  740.         free(root);
  741.         if (ret != NULL) {
  742.                 while (*ret != NULL)
  743.                         free(*(ret++));
  744.                 free(ret);
  745.         }
  746.  
  747.         return NULL;
  748. }
  749.  
  750. #if defined(HAVE_GLOB_H) && !defined(__MINGW32__)
  751.  
  752. #define COMPLETE_USERDIR_TILDE 0x01
  753. #define COMPLETE_USERDIR_EXACT 0x02
  754. #define COMPLETE_USERDIR_ALL 0x04
  755.  
  756. /**
  757.  * Return the list of home directories that match "len" characters of a
  758.  * user's name ("prefix").
  759.  * COMPLETE_USERDIR_TILDE - Instead of directories, the returned strings are
  760.  * tilde-prefixed user names.
  761.  * COMPLETE_USERDIR_EXACT - Prefix must exactly match a user name.
  762.  * COMPLETE_USERDIR_ALL - When prefix length is 0, return all user names
  763.  * instead of the current user only.
  764.  *
  765.  * @param[in] prefix Path name to match.
  766.  * @param len Number of characters to match in "path".
  767.  * @return List of home directories that match "len" characters of "prefix".
  768.  */
  769. static char **complete_userdir(const char *prefix, size_t len, int flags)
  770. {
  771.         char **ret = NULL;
  772.         char *s;
  773.         struct passwd *pwd;
  774.         size_t n;
  775.         size_t i;
  776.         int tilde = !!(flags & COMPLETE_USERDIR_TILDE);
  777.         int exact = !!(flags & COMPLETE_USERDIR_EXACT);
  778.         int all = !!(flags & COMPLETE_USERDIR_ALL);
  779.  
  780.         setpwent();
  781.         if ((!all) && (len == 0)) {
  782.                 if (((pwd = getpwuid(geteuid())) == NULL) ||
  783.                     ((ret = calloc(2, sizeof(ret[0]))) == NULL))
  784.                         goto err;
  785.                 if (tilde)
  786.                         s = pwd->pw_name;
  787.                 else
  788.                         s = pwd->pw_dir;
  789.                 i = strlen(s);
  790.                 if ((ret[0] = calloc((tilde + i + 1),
  791.                                      sizeof(*ret[0]))) == NULL)
  792.                         goto err;
  793.                 if (tilde)
  794.                         ret[0][0] = '~';
  795.                 memcpy(&ret[0][tilde], s, i);
  796.                 ret[0][(tilde + i)] = '\0';
  797.                 goto end;
  798.         }
  799.         n = 64;
  800.         if ((ret = calloc(n, sizeof(ret[0]))) == NULL)
  801.                 goto err;
  802.         i = 0;
  803.         while ((pwd = getpwent()) != NULL) {
  804.                 size_t j;
  805.  
  806.                 if (exact) {
  807.                         if (strncmp(pwd->pw_name, prefix,
  808.                                     strlen(pwd->pw_name)))
  809.                                 continue;
  810.                 }
  811.                 else if (strncmp(pwd->pw_name, prefix, len))
  812.                         continue;
  813.                 if (i == (n - 1)) {
  814.                         char **tmp;
  815.  
  816.                         n += 64;
  817.                         if ((tmp = realloc(ret, (sizeof(ret[0]) * n))) == NULL)
  818.                                 goto end;
  819.                         ret = tmp;
  820.                 }
  821.                 if (tilde)
  822.                         s = pwd->pw_name;
  823.                 else
  824.                         s = pwd->pw_dir;
  825.                 j = strlen(s);
  826.                 if ((ret[i] = calloc((tilde + j + 1),
  827.                                      sizeof(*ret[0]))) == NULL)
  828.                         break;
  829.                 if (tilde)
  830.                         ret[i][0] = '~';
  831.                 memcpy(&ret[i][tilde], s, j);
  832.                 ret[i][(tilde + j)] = '\0';
  833.                 ++i;
  834.         }
  835.         if (i == 0) {
  836.                 free(ret);
  837.                 ret = NULL;
  838.         }
  839. end:
  840.         endpwent();
  841.         return ret;
  842. err:
  843.         endpwent();
  844.         free_pppc(&ret, 0);
  845.         return NULL;
  846. }
  847.  
  848. /**
  849.  * Return a list of pathnames that match "len" characters of "prefix" on the
  850.  * file system, or NULL if none was found or if an error occured. This is done
  851.  * using glob() in order to handle wildcard characters in "prefix".
  852.  *
  853.  * When "prefix" isn't explicitly relative nor absolute, if "relative" is
  854.  * non-NULL, then the path will be completed as if "prefix" was a subdirectory
  855.  * of "relative". If "relative" is NULL, DGen's home directory will be used.
  856.  *
  857.  * If "relative" isn't explicitly relative nor absolute, it will be considered
  858.  * a subdirectory of DGen's home directory.
  859.  *
  860.  * @param[in] prefix Path name to match.
  861.  * @param len Number of characters to match in "path".
  862.  * @param[in] relative If non-NULL, consider path relative to this.
  863.  * @return List of path names that match "len" characters of "prefix".
  864.  */
  865. char **complete_path(const char *prefix, size_t len, const char *relative)
  866. {
  867.         char *s;
  868.         char **ret;
  869.         size_t i;
  870.         glob_t g;
  871.         size_t strip;
  872.  
  873.         (void)complete_path_simple; /* unused */
  874.         if ((i = strlen(prefix)) < len)
  875.                 len = i;
  876.         else
  877.                 i = len;
  878.         if (((s = strchr(prefix, '/')) != NULL) && ((i = (s - prefix)) > len))
  879.                 i = len;
  880.         if ((len == 0) ||
  881.             ((prefix[0] != '~') &&
  882.              (strncmp(prefix, ".", i)) &&
  883.              (strncmp(prefix, "..", i)))) {
  884.                 size_t n;
  885.  
  886.                 if ((relative == NULL) ||
  887.                     (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
  888.                         char *x = dgen_dir(NULL, &n, relative);
  889.  
  890.                         if ((x == NULL) ||
  891.                             ((s = realloc(x, (n + 1 + len + 2))) == NULL)) {
  892.                                 free(x);
  893.                                 return NULL;
  894.                         }
  895.                 }
  896.                 else {
  897.                         n = strlen(relative);
  898.                         if ((s = malloc(n + 1 + len + 2)) == NULL)
  899.                                 return NULL;
  900.                         memcpy(s, relative, n);
  901.                 }
  902.                 s[(n++)] = '/';
  903.                 strip = n;
  904.                 memcpy(&s[n], prefix, len);
  905.                 len += n;
  906.                 s[(len++)] = '*';
  907.                 s[len] = '\0';
  908.         }
  909.         else if (prefix[0] == '~') {
  910.                 char **ud;
  911.                 size_t n;
  912.  
  913.                 if (s == NULL)
  914.                         return complete_userdir(&prefix[1], (i - 1),
  915.                                                 (COMPLETE_USERDIR_TILDE |
  916.                                                  COMPLETE_USERDIR_ALL));
  917.                 ud = complete_userdir(&prefix[1], (i - 1),
  918.                                       COMPLETE_USERDIR_EXACT);
  919.                 if (ud == NULL)
  920.                         goto no_userdir;
  921.                 n = strlen(ud[0]);
  922.                 if ((s = realloc(ud[0], (n + (len - i) + 2))) == NULL) {
  923.                         free_pppc(&ud, 0);
  924.                         goto no_userdir;
  925.                 }
  926.                 free_pppc(&ud, 1);
  927.                 len -= i;
  928.                 strip = 0;
  929.                 memcpy(&s[n], &prefix[i], len);
  930.                 len += n;
  931.                 s[(len++)] = '*';
  932.                 s[len] = '\0';
  933.         }
  934.         else {
  935.         no_userdir:
  936.                 if ((s = malloc(len + 2)) == NULL)
  937.                         return NULL;
  938.                 memcpy(s, prefix, len);
  939.                 s[(len++)] = '*';
  940.                 s[len] = '\0';
  941.                 strip = 0;
  942.         }
  943.         switch (glob(s, (GLOB_MARK | GLOB_NOESCAPE), NULL, &g)) {
  944.         case 0:
  945.                 break;
  946.         case GLOB_NOSPACE:
  947.         case GLOB_ABORTED:
  948.         case GLOB_NOMATCH:
  949.         default:
  950.                 free(s);
  951.                 return NULL;
  952.         }
  953.         free(s);
  954.         if ((ret = calloc((g.gl_pathc + 1), sizeof(ret[0]))) == NULL)
  955.                 goto err;
  956.         for (i = 0; (g.gl_pathv[i] != NULL); ++i) {
  957.                 size_t j;
  958.  
  959.                 len = strlen(g.gl_pathv[i]);
  960.                 if (strip > len)
  961.                         break;
  962.                 j = (len - strip);
  963.                 if ((ret[i] = calloc((j + 1), sizeof(ret[i][0]))) == NULL)
  964.                         break;
  965.                 memcpy(ret[i], &(g.gl_pathv[i][strip]), j);
  966.                 ret[i][j] = '\0';
  967.         }
  968.         if (i == 0)
  969.                 goto err;
  970.         globfree(&g);
  971.         return ret;
  972. err:
  973.         globfree(&g);
  974.         free_pppc(&ret, 0);
  975.         return NULL;
  976. }
  977.  
  978. #else /* defined(HAVE_GLOB_H) && !defined(__MINGW32__) */
  979.  
  980. /**
  981.  * Return a list of pathnames that match "len" characters of "prefix" on the
  982.  * file system, or NULL if none was found or if an error occured.
  983.  *
  984.  * When "prefix" isn't explicitly relative nor absolute, if "relative" is
  985.  * non-NULL, then the path will be completed as if "prefix" was a subdirectory
  986.  * of "relative". If "relative" is NULL, DGen's home directory will be used.
  987.  *
  988.  * If "relative" isn't explicitly relative nor absolute, it will be considered
  989.  * a subdirectory of DGen's home directory.
  990.  *
  991.  * @param[in] prefix Path name to match.
  992.  * @param len Number of characters to match in "path".
  993.  * @param[in] relative If non-NULL, consider path relative to this.
  994.  * @return List of path names that match "len" characters of "prefix".
  995.  */
  996. char **complete_path(const char *prefix, size_t len, const char *relative)
  997. {
  998.         char *s;
  999.         char **ret;
  1000.         size_t i;
  1001.         size_t n;
  1002.         size_t strip;
  1003.         enum path_type pt;
  1004.  
  1005.         if ((i = strlen(prefix)) < len)
  1006.                 len = i;
  1007.         if (((pt = path_type(prefix, len)) == PATH_TYPE_ABSOLUTE) ||
  1008.             (pt == PATH_TYPE_RELATIVE))
  1009.                 return complete_path_simple(prefix, len);
  1010.         if ((len != 0) && (prefix[0] == '~') &&
  1011.             ((len == 1) ||
  1012.              (prefix[1] == '\0') ||
  1013.              (strpbrk(prefix, DGEN_DIRSEP) == &prefix[1]))) {
  1014.                 char *x = dgen_userdir(NULL, &n);
  1015.  
  1016.                 if ((x == NULL) ||
  1017.                     ((s = realloc(x, (n + 1 + 2 + len + 1))) == NULL)) {
  1018.                         free(x);
  1019.                         return NULL;
  1020.                 }
  1021.                 ++prefix;
  1022.                 --len;
  1023.                 strip = 0;
  1024.         }
  1025.         else if ((relative == NULL) ||
  1026.                  (path_type(relative, ~0u) == PATH_TYPE_UNSPECIFIED)) {
  1027.                 char *x = dgen_dir(NULL, &n, relative);
  1028.  
  1029.                 if ((x == NULL) ||
  1030.                     ((s = realloc(x, (n + 1 + len + 1))) == NULL)) {
  1031.                         free(x);
  1032.                         return NULL;
  1033.                 }
  1034.                 strip = (n + 1);
  1035.         }
  1036.         else {
  1037.                 n = strlen(relative);
  1038.                 if ((s = malloc(n + 1 + len + 1)) == NULL)
  1039.                         return NULL;
  1040.                 memcpy(s, relative, n);
  1041.                 strip = (n + 1);
  1042.         }
  1043.         s[(n++)] = DGEN_DIRSEP[0];
  1044.         memcpy(&s[n], prefix, len);
  1045.         len += n;
  1046.         s[len] = '\0';
  1047.         ret = complete_path_simple(s, len);
  1048.         free(s);
  1049.         if (ret == NULL)
  1050.                 return NULL;
  1051.         if (strip == 0)
  1052.                 return ret;
  1053.         for (i = 0; (ret[i] != NULL); ++i)
  1054.                 memmove(ret[i], &ret[i][strip],
  1055.                         ((strlen(ret[i]) - strip) + 1));
  1056.         return ret;
  1057. }
  1058.  
  1059. #endif /* defined(HAVE_GLOB_H) && !defined(__MINGW32__) */
  1060.  
  1061. /**
  1062.  * Free return value of complete*() functions.
  1063.  *
  1064.  * @param[in, out] cp Buffer to pass to free_pppc().
  1065.  */
  1066. void complete_path_free(char **cp)
  1067. {
  1068.         free_pppc(&cp, 0);
  1069. }
  1070.  
  1071. /**
  1072.  * Create an escaped version of a string.
  1073.  * When not NULL, "pos" refers to an offset in string "src". It is updated
  1074.  * with its new offset value in the escaped string.
  1075.  *
  1076.  * @param[in] src String to escape.
  1077.  * @param size Number of characters from "src" to process.
  1078.  * @param flags BACKSLASHIFY_* flags.
  1079.  * @param[in, out] pos Offset in string "src" to update.
  1080.  * @return Escaped version of "src", NULL on error.
  1081.  */
  1082. char *backslashify(const uint8_t *src, size_t size, unsigned int flags,
  1083.                    size_t *pos)
  1084. {
  1085.         char *dst = NULL;
  1086.         char *tmp;
  1087.         size_t i;
  1088.         size_t j;
  1089.         char buf[5];
  1090.  
  1091. again:
  1092.         for (i = 0, j = 0; (i < size); ++i) {
  1093.                 switch (src[i]) {
  1094.                 case '\a':
  1095.                         tmp = "\\a";
  1096.                         break;
  1097.                 case '\b':
  1098.                         tmp = "\\b";
  1099.                         break;
  1100.                 case '\f':
  1101.                         tmp = "\\f";
  1102.                         break;
  1103.                 case '\n':
  1104.                         tmp = "\\n";
  1105.                         break;
  1106.                 case '\r':
  1107.                         tmp = "\\r";
  1108.                         break;
  1109.                 case '\t':
  1110.                         tmp = "\\t";
  1111.                         break;
  1112.                 case '\v':
  1113.                         tmp = "\\v";
  1114.                         break;
  1115.                 case '\'':
  1116.                         if (flags & BACKSLASHIFY_NOQUOTES)
  1117.                                 goto noquotes;
  1118.                         tmp = "\\'";
  1119.                         break;
  1120.                 case '"':
  1121.                         if (flags & BACKSLASHIFY_NOQUOTES)
  1122.                                 goto noquotes;
  1123.                         tmp = "\\\"";
  1124.                         break;
  1125.                 case ' ':
  1126.                         if (flags & BACKSLASHIFY_NOQUOTES)
  1127.                                 tmp = " ";
  1128.                         else
  1129.                                 tmp = "\\ ";
  1130.                         break;
  1131.                 case '\0':
  1132.                         tmp = "\\0";
  1133.                         break;
  1134.                 case '\\':
  1135.                         if (flags & BACKSLASHIFY_NOQUOTES)
  1136.                                 goto noquotes;
  1137.                         tmp = "\\\\";
  1138.                         break;
  1139.                 default:
  1140.                 noquotes:
  1141.                         tmp = buf;
  1142.                         if (isgraph(src[i])) {
  1143.                                 tmp[0] = src[i];
  1144.                                 tmp[1] = '\0';
  1145.                                 break;
  1146.                         }
  1147.                         tmp[0] = '\\';
  1148.                         tmp[1] = 'x';
  1149.                         snprintf(&tmp[2], 3, "%02x", src[i]);
  1150.                         break;
  1151.                 }
  1152.                 if (dst != NULL)
  1153.                         strncpy(&dst[j], tmp, strlen(tmp));
  1154.                 if ((pos != NULL) && (i == *pos)) {
  1155.                         *pos = j;
  1156.                         pos = NULL;
  1157.                 }
  1158.                 j += strlen(tmp);
  1159.         }
  1160.         if ((pos != NULL) && (i == *pos)) {
  1161.                 *pos = j;
  1162.                 pos = NULL;
  1163.         }
  1164.         if (dst == NULL) {
  1165.                 dst = malloc(j + 1);
  1166.                 if (dst == NULL)
  1167.                         return NULL;
  1168.                 dst[j] = '\0';
  1169.                 goto again;
  1170.         }
  1171.         return dst;
  1172. }
  1173.  
  1174. /**
  1175.  * Convert a UTF-8 character to its 32 bit representation.
  1176.  * Return the number of valid bytes for this character.
  1177.  * On error, u32 is set to (uint32_t)-1.
  1178.  *
  1179.  * @param[out] u32 Converted character, (uint32_t)-1 on error.
  1180.  * @param[in] u8 Multibyte character to convert.
  1181.  * @return Number of bytes read.
  1182.  */
  1183. size_t utf8u32(uint32_t *u32, const uint8_t *u8)
  1184. {
  1185.         static const uint8_t fb[] = {
  1186.                 /* first byte: mask, expected value, size */
  1187.                 0x80, 0x00, 1,
  1188.                 0xe0, 0xc0, 2,
  1189.                 0xf0, 0xe0, 3,
  1190.                 0xf8, 0xf0, 4,
  1191.                 0xfc, 0xf8, 5,
  1192.                 0xfe, 0xfc, 6,
  1193.                 0xff, 0x00, 0
  1194.         };
  1195.         const uint8_t *s = fb;
  1196.         size_t i = 0;
  1197.         size_t rem;
  1198.         uint32_t ret;
  1199.  
  1200.         while ((*u8 & s[0]) != s[1])
  1201.                 s += 3;
  1202.         rem = s[2];
  1203.         if (!rem)
  1204.                 goto error;
  1205.         ret = (*u8 & ~s[0]);
  1206.         while (++i != rem) {
  1207.                 ++u8;
  1208.                 if ((*u8 & 0xc0) != 0x80)
  1209.                         goto error;
  1210.                 ret <<= 6;
  1211.                 ret |= (*u8 & ~0xc0);
  1212.         }
  1213.         if (((ret & ~0x07ff) == 0xd800) ||
  1214.             ((ret & ~0x0001) == 0xfffe))
  1215.                 goto error;
  1216.         *u32 = ret;
  1217.         return i;
  1218. error:
  1219.         *u32 = (uint32_t)-1;
  1220.         return i;
  1221. }
  1222.  
  1223. /**
  1224.  * The opposite of utf8u32().
  1225.  *
  1226.  * @param[out] u8 Converted character.
  1227.  * @param u32 Character to convert.
  1228.  * @return Number of characters written to "u8", 0 on error.
  1229.  */
  1230. size_t utf32u8(uint8_t *u8, uint32_t u32)
  1231. {
  1232.         size_t l;
  1233.         size_t i;
  1234.         uint8_t fb;
  1235.         uint32_t u;
  1236.  
  1237.         if ((u32 & 0x80000000) ||
  1238.             ((u32 & ~0x07ff) == 0xd800) ||
  1239.             ((u32 & ~0x0001) == 0xfffe))
  1240.                 return 0;
  1241.         if (u32 < 0x80) {
  1242.                 if (u8 != NULL)
  1243.                         *u8 = u32;
  1244.                 return 1;
  1245.         }
  1246.         for (l = 0, u = u32; (u & ~0x3c); ++l)
  1247.                 u >>= 6;
  1248.         if (u8 == NULL)
  1249.                 return l;
  1250.         for (i = l, fb = 0; (--i); u32 >>= 6, fb >>= 1, fb |= 0xc0)
  1251.                 u8[i] = (0x80 | (u32 & 0x3f));
  1252.         u8[0] = (fb | u32);
  1253.         return l;
  1254. }
  1255.  
  1256. /**
  1257.  * Look for the longest common prefix between a string and an array
  1258.  * of strings while ignoring case.
  1259.  *
  1260.  * @param[in] str String to compare argv entries to.
  1261.  * @param[in] argv NULL-terminated array of prefixes to match.
  1262.  * @return Index in argv or -1 if nothing matches.
  1263.  */
  1264. int prefix_casematch(const char *str, const char *argv[])
  1265. {
  1266.         unsigned int i;
  1267.         size_t ret_len = 0;
  1268.         int ret = -1;
  1269.  
  1270.         for (i = 0; (argv[i] != NULL); ++i) {
  1271.                 size_t len = strlen(argv[i]);
  1272.  
  1273.                 if ((len < ret_len) ||
  1274.                     (strncasecmp(str, argv[i], len)))
  1275.                         continue;
  1276.                 ret_len = len;
  1277.                 ret = i;
  1278.         }
  1279.         return ret;
  1280. }
  1281.  
  1282. /**
  1283.  * Read number from initial portion of a string and convert it.
  1284.  *
  1285.  * @param[in] str String to read from.
  1286.  * @param[out] num If not NULL, stores the converted number.
  1287.  * @return Length of the number in str, 0 on error.
  1288.  */
  1289. size_t prefix_getuint(const char *str, unsigned int *num)
  1290. {
  1291.         size_t len = 0;
  1292.         unsigned int ret = 0;
  1293.  
  1294.         while (isdigit(str[len])) {
  1295.                 ret *= 10;
  1296.                 ret += (str[len] - '0');
  1297.                 ++len;
  1298.         }
  1299.         if (len == 0)
  1300.                 return 0;
  1301.         if (num != NULL)
  1302.                 *num = ret;
  1303.         return len;
  1304. }
  1305.