Index: xz/src/xz/suffix.c |
=================================================================== |
--- xz/src/xz/suffix.c (revision 0) |
+++ xz/src/xz/suffix.c (revision 0) |
@@ -0,0 +1,211 @@ |
+/////////////////////////////////////////////////////////////////////////////// |
+// |
+/// \file suffix.c |
+/// \brief Checks filename suffix and creates the destination filename |
+// |
+// Author: Lasse Collin |
+// |
+// This file has been put into the public domain. |
+// You can do whatever you want with this file. |
+// |
+/////////////////////////////////////////////////////////////////////////////// |
+ |
+#include "private.h" |
+ |
+// For case-insensitive filename suffix on case-insensitive systems |
+#if defined(TUKLIB_DOSLIKE) || defined(__VMS) |
+# define strcmp strcasecmp |
+#endif |
+ |
+ |
+static char *custom_suffix = NULL; |
+ |
+ |
+struct suffix_pair { |
+ const char *compressed; |
+ const char *uncompressed; |
+}; |
+ |
+ |
+/// \brief Checks if src_name has given compressed_suffix |
+/// |
+/// \param suffix Filename suffix to look for |
+/// \param src_name Input filename |
+/// \param src_len strlen(src_name) |
+/// |
+/// \return If src_name has the suffix, src_len - strlen(suffix) is |
+/// returned. It's always a positive integer. Otherwise zero |
+/// is returned. |
+static size_t |
+test_suffix(const char *suffix, const char *src_name, size_t src_len) |
+{ |
+ const size_t suffix_len = strlen(suffix); |
+ |
+ // The filename must have at least one character in addition to |
+ // the suffix. src_name may contain path to the filename, so we |
+ // need to check for directory separator too. |
+ if (src_len <= suffix_len || src_name[src_len - suffix_len - 1] == '/') |
+ return 0; |
+ |
+ if (strcmp(suffix, src_name + src_len - suffix_len) == 0) |
+ return src_len - suffix_len; |
+ |
+ return 0; |
+} |
+ |
+ |
+/// \brief Removes the filename suffix of the compressed file |
+/// |
+/// \return Name of the uncompressed file, or NULL if file has unknown |
+/// suffix. |
+static char * |
+uncompressed_name(const char *src_name, const size_t src_len) |
+{ |
+ static const struct suffix_pair suffixes[] = { |
+ { ".xz", "" }, |
+ { ".txz", ".tar" }, // .txz abbreviation for .txt.gz is rare. |
+ { ".lzma", "" }, |
+ { ".tlz", ".tar" }, |
+ // { ".gz", "" }, |
+ // { ".tgz", ".tar" }, |
+ }; |
+ |
+ const char *new_suffix = ""; |
+ size_t new_len = 0; |
+ |
+ if (opt_format == FORMAT_RAW) { |
+ // Don't check for known suffixes when --format=raw was used. |
+ if (custom_suffix == NULL) { |
+ message_error(_("%s: With --format=raw, " |
+ "--suffix=.SUF is required unless " |
+ "writing to stdout"), src_name); |
+ return NULL; |
+ } |
+ } else { |
+ for (size_t i = 0; i < ARRAY_SIZE(suffixes); ++i) { |
+ new_len = test_suffix(suffixes[i].compressed, |
+ src_name, src_len); |
+ if (new_len != 0) { |
+ new_suffix = suffixes[i].uncompressed; |
+ break; |
+ } |
+ } |
+ } |
+ |
+ if (new_len == 0 && custom_suffix != NULL) |
+ new_len = test_suffix(custom_suffix, src_name, src_len); |
+ |
+ if (new_len == 0) { |
+ message_warning(_("%s: Filename has an unknown suffix, " |
+ "skipping"), src_name); |
+ return NULL; |
+ } |
+ |
+ const size_t new_suffix_len = strlen(new_suffix); |
+ char *dest_name = xmalloc(new_len + new_suffix_len + 1); |
+ |
+ memcpy(dest_name, src_name, new_len); |
+ memcpy(dest_name + new_len, new_suffix, new_suffix_len); |
+ dest_name[new_len + new_suffix_len] = '\0'; |
+ |
+ return dest_name; |
+} |
+ |
+ |
+/// \brief Appends suffix to src_name |
+/// |
+/// In contrast to uncompressed_name(), we check only suffixes that are valid |
+/// for the specified file format. |
+static char * |
+compressed_name(const char *src_name, const size_t src_len) |
+{ |
+ // The order of these must match the order in args.h. |
+ static const struct suffix_pair all_suffixes[][3] = { |
+ { |
+ { ".xz", "" }, |
+ { ".txz", ".tar" }, |
+ { NULL, NULL } |
+ }, { |
+ { ".lzma", "" }, |
+ { ".tlz", ".tar" }, |
+ { NULL, NULL } |
+/* |
+ }, { |
+ { ".gz", "" }, |
+ { ".tgz", ".tar" }, |
+ { NULL, NULL } |
+*/ |
+ }, { |
+ // --format=raw requires specifying the suffix |
+ // manually or using stdout. |
+ { NULL, NULL } |
+ } |
+ }; |
+ |
+ // args.c ensures this. |
+ assert(opt_format != FORMAT_AUTO); |
+ |
+ const size_t format = opt_format - 1; |
+ const struct suffix_pair *const suffixes = all_suffixes[format]; |
+ |
+ for (size_t i = 0; suffixes[i].compressed != NULL; ++i) { |
+ if (test_suffix(suffixes[i].compressed, src_name, src_len) |
+ != 0) { |
+ message_warning(_("%s: File already has `%s' " |
+ "suffix, skipping"), src_name, |
+ suffixes[i].compressed); |
+ return NULL; |
+ } |
+ } |
+ |
+ // TODO: Hmm, maybe it would be better to validate this in args.c, |
+ // since the suffix handling when decoding is weird now. |
+ if (opt_format == FORMAT_RAW && custom_suffix == NULL) { |
+ message_error(_("%s: With --format=raw, " |
+ "--suffix=.SUF is required unless " |
+ "writing to stdout"), src_name); |
+ return NULL; |
+ } |
+ |
+ const char *suffix = custom_suffix != NULL |
+ ? custom_suffix : suffixes[0].compressed; |
+ const size_t suffix_len = strlen(suffix); |
+ |
+ char *dest_name = xmalloc(src_len + suffix_len + 1); |
+ |
+ memcpy(dest_name, src_name, src_len); |
+ memcpy(dest_name + src_len, suffix, suffix_len); |
+ dest_name[src_len + suffix_len] = '\0'; |
+ |
+ return dest_name; |
+} |
+ |
+ |
+extern char * |
+suffix_get_dest_name(const char *src_name) |
+{ |
+ assert(src_name != NULL); |
+ |
+ // Length of the name is needed in all cases to locate the end of |
+ // the string to compare the suffix, so calculate the length here. |
+ const size_t src_len = strlen(src_name); |
+ |
+ return opt_mode == MODE_COMPRESS |
+ ? compressed_name(src_name, src_len) |
+ : uncompressed_name(src_name, src_len); |
+} |
+ |
+ |
+extern void |
+suffix_set(const char *suffix) |
+{ |
+ // Empty suffix and suffixes having a slash are rejected. Such |
+ // suffixes would break things later. |
+ if (suffix[0] == '\0' || strchr(suffix, '/') != NULL) |
+ message_fatal(_("%s: Invalid filename suffix"), optarg); |
+ |
+ // Replace the old custom_suffix (if any) with the new suffix. |
+ free(custom_suffix); |
+ custom_suffix = xstrdup(suffix); |
+ return; |
+} |
Property changes on: xz/src/xz/suffix.c |
___________________________________________________________________ |
Added: svn:eol-style |
+ LF |