Merge branch 'cp/textconv-cat-file'
authorJunio C Hamano <gitster@pobox.com>
Sun, 27 Jun 2010 19:07:55 +0000 (12:07 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 27 Jun 2010 19:07:55 +0000 (12:07 -0700)
* cp/textconv-cat-file:
git-cat-file.txt: Document --textconv
t/t8007: test textconv support for cat-file
textconv: support for cat_file
sha1_name: add get_sha1_with_context()

1  2 
builtin.h
builtin/blame.c
builtin/cat-file.c
cache.h
sha1_name.c
diff --combined builtin.h
index 1054c6e2950c3bc433841683ca4fcf7ce6501df3,5a1dba00693faf430bf319470d484065e530f27d..ed6ee26933430e1db4e29e62badfaf0b217935ad
+++ b/builtin.h
@@@ -16,20 -16,19 +16,20 @@@ extern const char *help_unknown_cmd(con
  extern void prune_packed_objects(int);
  extern int fmt_merge_msg(int merge_summary, struct strbuf *in,
        struct strbuf *out);
 +extern int fmt_merge_msg_shortlog(struct strbuf *in, struct strbuf *out);
  extern int commit_notes(struct notes_tree *t, const char *msg);
  
  struct notes_rewrite_cfg {
        struct notes_tree **trees;
        const char *cmd;
        int enabled;
 -      combine_notes_fn *combine;
 +      combine_notes_fn combine;
        struct string_list *refs;
        int refs_from_env;
        int mode_from_env;
  };
  
 -combine_notes_fn *parse_combine_notes_fn(const char *v);
 +combine_notes_fn parse_combine_notes_fn(const char *v);
  struct notes_rewrite_cfg *init_copy_notes_for_rewrite(const char *cmd);
  int copy_note_for_rewrite(struct notes_rewrite_cfg *c,
                          const unsigned char *from_obj, const unsigned char *to_obj);
@@@ -37,6 -36,8 +37,8 @@@ void finish_copy_notes_for_rewrite(stru
  
  extern int check_pager_config(const char *cmd);
  
+ extern int textconv_object(const char *path, const unsigned char *sha1, char **buf, unsigned long *buf_size);
  extern int cmd_add(int argc, const char **argv, const char *prefix);
  extern int cmd_annotate(int argc, const char **argv, const char *prefix);
  extern int cmd_apply(int argc, const char **argv, const char *prefix);
diff --combined builtin/blame.c
index 9b88ce9256279728028c2648703ee150ee8a9e0e,2e63648ea04961d5efd6f750ffab5ca636a1a898..01e62fdeb00b2d085efe96a07f2ee77776081a69
@@@ -40,7 -40,7 +40,7 @@@ static int show_root
  static int reverse;
  static int blank_boundary;
  static int incremental;
 -static int xdl_opts = XDF_NEED_MINIMAL;
 +static int xdl_opts;
  
  static enum date_mode blame_date_mode = DATE_ISO8601;
  static size_t blame_date_width;
@@@ -91,10 -91,10 +91,10 @@@ struct origin 
   * if the textconv driver exists.
   * Return 1 if the conversion succeeds, 0 otherwise.
   */
static int textconv_object(const char *path,
-                          const unsigned char *sha1,
-                          char **buf,
-                          unsigned long *buf_size)
+ int textconv_object(const char *path,
+                   const unsigned char *sha1,
+                   char **buf,
+                   unsigned long *buf_size)
  {
        struct diff_filespec *df;
        struct userdiff_driver *textconv;
@@@ -767,11 -767,10 +767,11 @@@ static int pass_blame_to_parent(struct 
  {
        int last_in_target;
        mmfile_t file_p, file_o;
 -      struct blame_chunk_cb_data d = { sb, target, parent, 0, 0 };
 +      struct blame_chunk_cb_data d;
        xpparam_t xpp;
        xdemitconf_t xecfg;
 -
 +      memset(&d, 0, sizeof(d));
 +      d.sb = sb; d.target = target; d.parent = parent;
        last_in_target = find_last_in_target(sb, target);
        if (last_in_target < 0)
                return 1; /* nothing remains for this target */
@@@ -910,11 -909,10 +910,11 @@@ static void find_copy_in_blob(struct sc
        const char *cp;
        int cnt;
        mmfile_t file_o;
 -      struct handle_split_cb_data d = { sb, ent, parent, split, 0, 0 };
 +      struct handle_split_cb_data d;
        xpparam_t xpp;
        xdemitconf_t xecfg;
 -
 +      memset(&d, 0, sizeof(d));
 +      d.sb = sb; d.ent = ent; d.parent = parent; d.split = split;
        /*
         * Prepare mmfile that contains only the lines in ent.
         */
diff --combined builtin/cat-file.c
index e5118c57da2b69963894ff2994ac361ab7f6b837,cada5d22573a59baeee3db3f740932c9419ed9e1..76ec3fec9279f38520fa4b5b525ce2c03cc9cbb0
@@@ -9,6 -9,8 +9,8 @@@
  #include "tree.h"
  #include "builtin.h"
  #include "parse-options.h"
+ #include "diff.h"
+ #include "userdiff.h"
  
  #define BATCH 1
  #define BATCH_CHECK 2
@@@ -84,10 -86,11 +86,11 @@@ static int cat_one_file(int opt, const 
  {
        unsigned char sha1[20];
        enum object_type type;
-       void *buf;
+       char *buf;
        unsigned long size;
+       struct object_context obj_context;
  
-       if (get_sha1(obj_name, sha1))
+       if (get_sha1_with_context(obj_name, sha1, &obj_context))
                die("Not a valid object name %s", obj_name);
  
        buf = NULL;
  
                /* custom pretty-print here */
                if (type == OBJ_TREE) {
 -                      const char *ls_args[3] = {"ls-tree", obj_name, NULL};
 +                      const char *ls_args[3] = { NULL };
 +                      ls_args[0] =  "ls-tree";
 +                      ls_args[1] =  obj_name;
                        return cmd_ls_tree(2, ls_args, NULL);
                }
  
  
                /* otherwise just spit out the data */
                break;
+       case 'c':
+               if (!obj_context.path[0])
+                       die("git cat-file --textconv %s: <object> must be <sha1:path>",
+                           obj_name);
+               if (!textconv_object(obj_context.path, sha1, &buf, &size))
+                       die("git cat-file --textconv: unable to run textconv on %s",
+                           obj_name);
+               break;
        case 0:
                buf = read_object_with_reference(sha1, exp_type, &size, NULL);
                break;
@@@ -203,11 -215,25 +217,25 @@@ static int batch_objects(int print_cont
  }
  
  static const char * const cat_file_usage[] = {
-       "git cat-file (-t|-s|-e|-p|<type>) <object>",
+       "git cat-file (-t|-s|-e|-p|<type>|--textconv) <object>",
        "git cat-file (--batch|--batch-check) < <list_of_objects>",
        NULL
  };
  
+ static int git_cat_file_config(const char *var, const char *value, void *cb)
+ {
+       switch (userdiff_config(var, value)) {
+       case 0:
+               break;
+       case -1:
+               return -1;
+       default:
+               return 0;
+       }
+       return git_default_config(var, value, cb);
+ }
  int cmd_cat_file(int argc, const char **argv, const char *prefix)
  {
        int opt = 0, batch = 0;
                OPT_SET_INT('e', NULL, &opt,
                            "exit with zero when there's no error", 'e'),
                OPT_SET_INT('p', NULL, &opt, "pretty-print object's content", 'p'),
+               OPT_SET_INT(0, "textconv", &opt,
+                           "for blob objects, run textconv on object's content", 'c'),
                OPT_SET_INT(0, "batch", &batch,
                            "show info and content of objects fed from the standard input",
                            BATCH),
                OPT_END()
        };
  
-       git_config(git_default_config, NULL);
+       git_config(git_cat_file_config, NULL);
  
        if (argc != 3 && argc != 2)
                usage_with_options(cat_file_usage, options);
diff --combined cache.h
index ff4a7c26d3b4dc6c9b28d8a28919b11fd71443bb,67030dbfcad242d9310685009b8cf68e5c919947..c9fa3df7f5b343ecea980ceb423e7c23d2eb22b2
+++ b/cache.h
@@@ -361,7 -361,7 +361,7 @@@ enum object_type 
        OBJ_OFS_DELTA = 6,
        OBJ_REF_DELTA = 7,
        OBJ_ANY,
 -      OBJ_MAX,
 +      OBJ_MAX
  };
  
  static inline enum object_type object_type(unsigned int mode)
@@@ -547,6 -547,7 +547,6 @@@ extern int core_compression_seen
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
 -extern int auto_crlf;
  extern int read_replace_refs;
  extern int fsync_object_files;
  extern int core_preload_index;
@@@ -555,53 -556,32 +555,53 @@@ extern int core_apply_sparse_checkout
  enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
        SAFE_CRLF_FAIL = 1,
 -      SAFE_CRLF_WARN = 2,
 +      SAFE_CRLF_WARN = 2
  };
  
  extern enum safe_crlf safe_crlf;
  
 +enum auto_crlf {
 +      AUTO_CRLF_FALSE = 0,
 +      AUTO_CRLF_TRUE = 1,
 +      AUTO_CRLF_INPUT = -1,
 +};
 +
 +extern enum auto_crlf auto_crlf;
 +
 +enum eol {
 +      EOL_UNSET,
 +      EOL_CRLF,
 +      EOL_LF,
 +#ifdef NATIVE_CRLF
 +      EOL_NATIVE = EOL_CRLF
 +#else
 +      EOL_NATIVE = EOL_LF
 +#endif
 +};
 +
 +extern enum eol eol;
 +
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
        BRANCH_TRACK_REMOTE,
        BRANCH_TRACK_ALWAYS,
        BRANCH_TRACK_EXPLICIT,
 -      BRANCH_TRACK_OVERRIDE,
 +      BRANCH_TRACK_OVERRIDE
  };
  
  enum rebase_setup_type {
        AUTOREBASE_NEVER = 0,
        AUTOREBASE_LOCAL,
        AUTOREBASE_REMOTE,
 -      AUTOREBASE_ALWAYS,
 +      AUTOREBASE_ALWAYS
  };
  
  enum push_default_type {
        PUSH_DEFAULT_NOTHING = 0,
        PUSH_DEFAULT_MATCHING,
        PUSH_DEFAULT_TRACKING,
 -      PUSH_DEFAULT_CURRENT,
 +      PUSH_DEFAULT_CURRENT
  };
  
  extern enum branch_track git_branch_track;
@@@ -610,7 -590,7 +610,7 @@@ extern enum push_default_type push_defa
  
  enum object_creation_mode {
        OBJECT_CREATION_USES_HARDLINKS = 0,
 -      OBJECT_CREATION_USES_RENAMES = 1,
 +      OBJECT_CREATION_USES_RENAMES = 1
  };
  
  extern enum object_creation_mode object_creation_mode;
@@@ -690,7 -670,7 +690,7 @@@ enum sharedrepo 
        OLD_PERM_GROUP      = 1,
        OLD_PERM_EVERYBODY  = 2,
        PERM_GROUP          = 0660,
 -      PERM_EVERYBODY      = 0664,
 +      PERM_EVERYBODY      = 0664
  };
  int git_config_perm(const char *var, const char *value);
  int set_shared_perm(const char *path, int mode);
@@@ -750,12 -730,23 +750,23 @@@ static inline unsigned int hexval(unsig
  #define MINIMUM_ABBREV 4
  #define DEFAULT_ABBREV 7
  
+ struct object_context {
+       unsigned char tree[20];
+       char path[PATH_MAX];
+       unsigned mode;
+ };
  extern int get_sha1(const char *str, unsigned char *sha1);
  extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int gently, const char *prefix);
  static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)
  {
        return get_sha1_with_mode_1(str, sha1, mode, 1, NULL);
  }
+ extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int gently, const char *prefix);
+ static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)
+ {
+       return get_sha1_with_context_1(str, sha1, orc, 1, NULL);
+ }
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern char *sha1_to_hex(const unsigned char *sha1);  /* static buffer result! */
  extern int read_ref(const char *filename, unsigned char *sha1);
@@@ -902,7 -893,7 +913,7 @@@ struct ref 
                REF_STATUS_REJECT_NODELETE,
                REF_STATUS_UPTODATE,
                REF_STATUS_REMOTE_REJECT,
 -              REF_STATUS_EXPECTING_REPORT,
 +              REF_STATUS_EXPECTING_REPORT
        } status;
        char *remote_status;
        struct ref *peer_ref; /* when renaming */
diff --combined sha1_name.c
index 8cf635af54568ce09685e79560d0038b3262f842,7fdb20277f16c05213479e3a757745f56096f3f1..4f2af8da934b125f2c09ceb4d8185dabc58f7831
@@@ -679,8 -679,8 +679,8 @@@ static int handle_one_ref(const char *p
  
  /*
   * This interprets names like ':/Initial revision of "git"' by searching
 - * through history and returning the first commit whose message starts
 - * with the given string.
 + * through history and returning the first commit whose message matches
 + * the given regular expression.
   *
   * For future extension, ':/!' is reserved. If you want to match a message
   * beginning with a '!', you have to repeat the exclamation mark.
@@@ -692,17 -692,12 +692,17 @@@ static int get_sha1_oneline(const char 
        struct commit_list *list = NULL, *backup = NULL, *l;
        int retval = -1;
        char *temp_commit_buffer = NULL;
 +      regex_t regex;
  
        if (prefix[0] == '!') {
                if (prefix[1] != '!')
                        die ("Invalid search pattern: %s", prefix);
                prefix++;
        }
 +
 +      if (regcomp(&regex, prefix, REG_EXTENDED))
 +              die("Invalid search pattern: %s", prefix);
 +
        for_each_ref(handle_one_ref, &list);
        for (l = list; l; l = l->next)
                commit_list_insert(l->item, &backup);
                }
                if (!(p = strstr(p, "\n\n")))
                        continue;
 -              if (!prefixcmp(p + 2, prefix)) {
 +              if (!regexec(&regex, p + 2, 0, NULL, 0)) {
                        hashcpy(sha1, commit->object.sha1);
                        retval = 0;
                        break;
                }
        }
 +      regfree(&regex);
        free(temp_commit_buffer);
        free_commit_list(list);
        for (l = backup; l; l = l->next)
@@@ -939,8 -933,8 +939,8 @@@ int interpret_branch_name(const char *n
   */
  int get_sha1(const char *name, unsigned char *sha1)
  {
-       unsigned unused;
-       return get_sha1_with_mode(name, sha1, &unused);
+       struct object_context unused;
+       return get_sha1_with_context(name, sha1, &unused);
  }
  
  /* Must be called only when object_name:filename doesn't exist. */
@@@ -1037,12 -1031,24 +1037,24 @@@ static void diagnose_invalid_index_path
  
  
  int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int gently, const char *prefix)
+ {
+       struct object_context oc;
+       int ret;
+       ret = get_sha1_with_context_1(name, sha1, &oc, gently, prefix);
+       *mode = oc.mode;
+       return ret;
+ }
+ int get_sha1_with_context_1(const char *name, unsigned char *sha1,
+                           struct object_context *oc,
+                           int gently, const char *prefix)
  {
        int ret, bracket_depth;
        int namelen = strlen(name);
        const char *cp;
  
-       *mode = S_IFINVALID;
+       memset(oc, 0, sizeof(*oc));
+       oc->mode = S_IFINVALID;
        ret = get_sha1_1(name, namelen, sha1);
        if (!ret)
                return ret;
                        cp = name + 3;
                }
                namelen = namelen - (cp - name);
+               strncpy(oc->path, cp,
+                       sizeof(oc->path));
+               oc->path[sizeof(oc->path)-1] = '\0';
                if (!active_cache)
                        read_cache();
                pos = cache_name_pos(cp, namelen);
                                break;
                        if (ce_stage(ce) == stage) {
                                hashcpy(sha1, ce->sha1);
-                               *mode = ce->ce_mode;
                                return 0;
                        }
                        pos++;
                }
                if (!get_sha1_1(name, cp-name, tree_sha1)) {
                        const char *filename = cp+1;
-                       ret = get_tree_entry(tree_sha1, filename, sha1, mode);
+                       ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
                        if (!gently) {
                                diagnose_invalid_sha1_path(prefix, filename,
                                                           tree_sha1, object_name);
                                free(object_name);
                        }
+                       hashcpy(oc->tree, tree_sha1);
+                       strncpy(oc->path, filename,
+                               sizeof(oc->path));
+                       oc->path[sizeof(oc->path)-1] = '\0';
                        return ret;
                } else {
                        if (!gently)