Subversion Repositories Kolibri OS

Rev

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