{"thread":{"id":"7030","subject":"[PATCH 2/2] git-show: use pathattr to run \"display\"","startedAt":"2007-03-01T07:18:05Z","lastAt":"2007-03-01T09:37:28Z","messageCount":6,"participants":["Junio C Hamano","Andy Parkins"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"35920","messageId":"7vodndxwia.fsf@assigned-by-dhcp.cox.net","threadId":"7030","inReplyTo":null,"subject":"[PATCH 2/2] git-show: use pathattr to run \"display\"","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-01T07:18:05Z","receivedAt":"2007-03-01T07:18:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is a bit of detour, to demonstrate a possible use of\npathattr infrastructure.  With this,\n\n\t$ git show v1.4.4:t/test4012.png\n\nwould hopefully do what you would expect.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n * I was planning to write the config reader as a follow-up, but\n   got sidetracked.  After all, doing something whose effect is\n   visible is more fun.\n\n builtin-log.c |   31 ++++++++++++++++++++++++-------\n pathattr.c    |    8 ++++++++\n pathattr.h    |    3 +++\n 3 files changed, 35 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 1c9f7d0..519fab2 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -12,6 +12,7 @@\n #include \"builtin.h\"\n #include \"tag.h\"\n #include \"reflog-walk.h\"\n+#include \"pathattr.h\"\n \n static int default_show_root = 1;\n \n@@ -86,26 +87,42 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \treturn cmd_log_walk(&rev);\n }\n \n-static int show_object(const unsigned char *sha1, int suppress_header)\n+static void to_stdout(const unsigned char *blobdata, unsigned long size)\n+{\n+\tfwrite(blobdata, size, 1, stdout);\n+}\n+\n+static int show_object(const unsigned char *sha1, const char *path, int nohead)\n {\n \tunsigned long size;\n \tenum object_type type;\n-\tchar *buf = read_sha1_file(sha1, &type, &size);\n+\tunsigned char *buf = read_sha1_file(sha1, &type, &size);\n \tint offset = 0;\n+\tpretty_fn pretty = to_stdout;\n \n \tif (!buf)\n \t\treturn error(\"Could not read object %s\", sha1_to_hex(sha1));\n \n-\tif (suppress_header)\n+\tif (nohead) {\n \t\twhile (offset < size && buf[offset++] != '\\n') {\n \t\t\tint new_offset = offset;\n \t\t\twhile (new_offset < size && buf[new_offset++] != '\\n')\n \t\t\t\t; /* do nothing */\n \t\t\toffset = new_offset;\n \t\t}\n+\t}\n+\n+\tif (size <= offset)\n+\t\tgoto finish;\n+\n+\tif (path) {\n+\t\tconst struct pathattr *a = pathattr_lookup(path);\n+\t\tif (a && a->pretty)\n+\t\t\tpretty = a->pretty;\n+\t}\n \n-\tif (offset < size)\n-\t\tfwrite(buf + offset, size - offset, 1, stdout);\n+\tpretty(buf + offset, size - offset);\n+ finish:\n \tfree(buf);\n \treturn 0;\n }\n@@ -142,7 +159,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\tconst char *name = objects[i].name;\n \t\tswitch (o->type) {\n \t\tcase OBJ_BLOB:\n-\t\t\tret = show_object(o->sha1, 0);\n+\t\t\tret = show_object(o->sha1, name, 0);\n \t\t\tbreak;\n \t\tcase OBJ_TAG: {\n \t\t\tstruct tag *t = (struct tag *)o;\n@@ -153,7 +170,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\t\t\t\tt->tag,\n \t\t\t\t\tdiff_get_color(rev.diffopt.color_diff,\n \t\t\t\t\t\tDIFF_RESET));\n-\t\t\tret = show_object(o->sha1, 1);\n+\t\t\tret = show_object(o->sha1, name, 1);\n \t\t\tobjects[i].item = (struct object *)t->tagged;\n \t\t\ti--;\n \t\t\tbreak;\ndiff --git a/pathattr.c b/pathattr.c\nindex 06bbb4e..c84be39 100644\n--- a/pathattr.c\n+++ b/pathattr.c\n@@ -1,6 +1,13 @@\n #include \"cache.h\"\n #include \"pathattr.h\"\n \n+static void show_display(const unsigned char *blobdata, unsigned long size)\n+{\n+\tFILE *display = popen(\"display -\", \"w\");\n+\tfwrite(blobdata, size, 1, display);\n+\tfclose(display);\n+}\n+\n /*\n  * Path match specification\n  */\n@@ -93,6 +100,7 @@ static void init_stack(void)\n \ta = locate(stk, \"image/*\");\n \ta->conv_i = NULL;\n \ta->conv_o = NULL;\n+\ta->pretty = show_display;\n \tadd_match(stk, a, \"*.png\");\n \tadd_match(stk, a, \"*.jpg\");\n \tadd_match(stk, a, \"*.gif\");\ndiff --git a/pathattr.h b/pathattr.h\nindex 4ca4e60..bfd9ff1 100644\n--- a/pathattr.h\n+++ b/pathattr.h\n@@ -3,6 +3,8 @@\n \n #include \"convert.h\"\n \n+typedef void (*pretty_fn)(const unsigned char *blobdata, unsigned long size);\n+\n /*\n  * Data in one section of [pathattr \"name\"], except\n  * the path match specification.\n@@ -11,6 +13,7 @@ struct pathattr {\n \tchar *name;\n \tconvi_fn conv_i;\n \tconvo_fn conv_o;\n+\tpretty_fn pretty;\n };\n \n const struct pathattr *pathattr_lookup(const char *);\n-- \n1.5.0.2.809.g0f936\n"},{"id":"35936","messageId":"200703010904.48146.andyparkins@gmail.com","threadId":"7030","inReplyTo":"7vodndxwia.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 2/2] git-show: use pathattr to run \"display\"","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-01T09:04:44Z","receivedAt":"2007-03-01T09:04:44Z","isPatch":true,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Thursday 2007 March 01 07:18, Junio C Hamano wrote:\n> This is a bit of detour, to demonstrate a possible use of\n> pathattr infrastructure.  With this,\n>\n> \t$ git show v1.4.4:t/test4012.png\n>\n> would hopefully do what you would expect.\n\nIs this serious?  This doesn't belong inside git does it?\n\nWhat if I don't want to run \"display\"?  What if I don't want to run anything, \nand just want png files dumped raw to the terminal?\n\n\n\nAndy\n\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"35940","messageId":"200703010917.54026.andyparkins@gmail.com","threadId":"7030","inReplyTo":"200703010904.48146.andyparkins@gmail.com","subject":"Re: [PATCH 2/2] git-show: use pathattr to run \"display\"","fromName":"Andy Parkins","fromEmail":"andyparkins@gmail.com","sentAt":"2007-03-01T09:17:53Z","receivedAt":"2007-03-01T09:17:53Z","isPatch":true,"sender":{"key":"andyparkins@gmail.com","avatar":null},"body":"On Thursday 2007 March 01 09:04, Andy Parkins wrote:\n> Is this serious?  This doesn't belong inside git does it?\n\nI see from the source that it's not.  It's just a demo.  Sorry Junio.\n\n\nAndy\n-- \nDr Andy Parkins, M Eng (hons), MIET\nandyparkins@gmail.com\n"},{"id":"35943","messageId":"7vbqjdwbzr.fsf@assigned-by-dhcp.cox.net","threadId":"7030","inReplyTo":"7vodndxwia.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 3/2] pathattr: read from git_config().","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-01T09:26:32Z","receivedAt":"2007-03-01T09:26:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Now we read the path traits from the usual configuration\nmechanism.  No per-directory .gitattributes yet, though.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n * [3/2] (this one) and [4/2] are the follow-up to the pathattr\n   series.\n\n pathattr.c |   63 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 62 insertions(+), 1 deletions(-)\n\ndiff --git a/pathattr.c b/pathattr.c\nindex c84be39..2532c9a 100644\n--- a/pathattr.c\n+++ b/pathattr.c\n@@ -85,6 +85,67 @@ static void add_match(struct pathattr_stack *s, struct pathattr *a, const char *\n \tm->attr = a;\n }\n \n+static convi_fn conv_i_trait(const char *value)\n+{\n+\tif (!strcmp(value, \"crlf\"))\n+\t\treturn convi_crlf;\n+\treturn NULL;\n+}\n+\n+static convo_fn conv_o_trait(const char *value)\n+{\n+\tif (!strcmp(value, \"crlf\"))\n+\t\treturn convo_crlf;\n+\treturn NULL;\n+}\n+\n+static pretty_fn pretty_trait(const char *value)\n+{\n+\tif (!strcmp(value, \"display\"))\n+\t\treturn show_display;\n+\treturn NULL;\n+}\n+\n+static int attr_config(const char *var, const char *value)\n+{\n+\tstruct pathattr *a;\n+\tstatic const char pa[] = \"pathattr.\";\n+\tconst char *trait;\n+\tchar group[256];\n+\tint group_len;\n+\n+\tif (prefixcmp(var, pa))\n+\t\treturn 0; /* we are not interested in other configs */\n+\ttrait = strrchr(var, '.');\n+\tif (!trait)\n+\t\treturn 0; /* huh? */\n+\tgroup_len = trait - var - (sizeof(pa) - 1);\n+\tif (group_len <= 0)\n+\t\treturn 0; /* huh? */\n+\ttrait++;\n+\tif (sizeof(group) < group_len)\n+\t\tdie(\"'%.*s' is too long as a group name\", group_len,\n+\t\t    var + sizeof(pa) - 1);\n+\tmemcpy(group, var + sizeof(pa) - 1, group_len);\n+\tgroup[group_len] = 0;\n+\ta = locate(stk, group);\n+\n+\tif (!strcmp(trait, \"path\"))\n+\t\tadd_match(stk, a, value);\n+\telse if (!strcmp(trait, \"conv_i\"))\n+\t\ta->conv_i = conv_i_trait(value);\n+\telse if (!strcmp(trait, \"conv_o\"))\n+\t\ta->conv_i = conv_o_trait(value);\n+\telse if (!strcmp(trait, \"pretty\"))\n+\t\ta->pretty = pretty_trait(value);\n+\t/*\n+\t * Do not barf if the configuration has unknown trait.\n+\t * the user might be bisecting git and trying an older\n+\t * version on the latest repository.\n+\t */\n+\treturn 0;\n+}\n+\n static void init_stack(void)\n {\n \tstruct pathattr *a;\n@@ -105,7 +166,7 @@ static void init_stack(void)\n \tadd_match(stk, a, \"*.jpg\");\n \tadd_match(stk, a, \"*.gif\");\n \n-\t/* NEEDSWORK: read from config */\n+\tgit_config(attr_config);\n }\n \n static void pop_stack(void)\n-- \n1.5.0.2.809.g0f936\n"},{"id":"35944","messageId":"7vzm6xux9o.fsf@assigned-by-dhcp.cox.net","threadId":"7030","inReplyTo":"7vodndxwia.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH 4/2] pathattr: allow piping to external program.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-01T09:29:55Z","receivedAt":"2007-03-01T09:29:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This sets up capability for various traits to be an external\nprocess, accessed via pipe.  conv-i and conv-o need to spawn\nbidirectional pipe, but I have not coded that part yet.\n\nYou can try running:\n\n    $ git show HEAD:Documentation/*.txt\n\nwith:\n\n    [pathattr \"kludge\"]\n        path = Documentation/*.txt\n        pretty = \"pipe sed -e 's/^/>> /'\"\n\nto see what it does.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n---\n\n * I somehow suspect two Johannes'es would hate me for doing\n   this.  I should instead resume coding the part to read\n   .gitattributes from each directory, but spawning external\n   stuff to borrow what other people already have done is much\n   more fun than doing gruntwork in C.\n\n builtin-log.c |   18 ++++++++++---\n convert.c     |   16 ++++++------\n convert.h     |    3 --\n pathattr.c    |   77 ++++++++++++++++++++++++++++++++++++++++++++++----------\n pathattr.h    |    8 +++++-\n 5 files changed, 92 insertions(+), 30 deletions(-)\n\ndiff --git a/builtin-log.c b/builtin-log.c\nindex 519fab2..86062d3 100644\n--- a/builtin-log.c\n+++ b/builtin-log.c\n@@ -87,7 +87,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \treturn cmd_log_walk(&rev);\n }\n \n-static void to_stdout(const unsigned char *blobdata, unsigned long size)\n+static void to_stdout(const unsigned char *blobdata, unsigned long size, const char *unused)\n {\n \tfwrite(blobdata, size, 1, stdout);\n }\n@@ -99,6 +99,7 @@ static int show_object(const unsigned char *sha1, const char *path, int nohead)\n \tunsigned char *buf = read_sha1_file(sha1, &type, &size);\n \tint offset = 0;\n \tpretty_fn pretty = to_stdout;\n+\tchar *pretty_args = NULL;\n \n \tif (!buf)\n \t\treturn error(\"Could not read object %s\", sha1_to_hex(sha1));\n@@ -117,11 +118,13 @@ static int show_object(const unsigned char *sha1, const char *path, int nohead)\n \n \tif (path) {\n \t\tconst struct pathattr *a = pathattr_lookup(path);\n-\t\tif (a && a->pretty)\n+\t\tif (a && a->pretty) {\n \t\t\tpretty = a->pretty;\n+\t\t\tpretty_args = a->pretty_args;\n+\t\t}\n \t}\n \n-\tpretty(buf + offset, size - offset);\n+\tpretty(buf + offset, size - offset, pretty_args);\n  finish:\n \tfree(buf);\n \treturn 0;\n@@ -159,6 +162,13 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\tconst char *name = objects[i].name;\n \t\tswitch (o->type) {\n \t\tcase OBJ_BLOB:\n+\t\t\t/*\n+\t\t\t * This is a hack to make v2.6.0:README\n+\t\t\t * and friends to work.  Anybody have\n+\t\t\t * better ideas?\n+\t\t\t */\n+\t\t\tif (strchr(name, ':'))\n+\t\t\t\tname = strchr(name, ':') + 1;\n \t\t\tret = show_object(o->sha1, name, 0);\n \t\t\tbreak;\n \t\tcase OBJ_TAG: {\n@@ -170,7 +180,7 @@ int cmd_show(int argc, const char **argv, const char *prefix)\n \t\t\t\t\tt->tag,\n \t\t\t\t\tdiff_get_color(rev.diffopt.color_diff,\n \t\t\t\t\t\tDIFF_RESET));\n-\t\t\tret = show_object(o->sha1, name, 1);\n+\t\t\tret = show_object(o->sha1, NULL, 1);\n \t\t\tobjects[i].item = (struct object *)t->tagged;\n \t\t\ti--;\n \t\t\tbreak;\ndiff --git a/convert.c b/convert.c\nindex c39946d..504036e 100644\n--- a/convert.c\n+++ b/convert.c\n@@ -253,11 +253,11 @@ static int convo_autocrlf(const char *path, char **bufp, unsigned long *sizep)\n int convert_to_git(const char *path, char **bufp, unsigned long *sizep)\n {\n \tif (path) {\n-\t\tconst struct pathattr *attr = pathattr_lookup(path);\n-\t\tif (attr) {\n-\t\t\tif (!attr->conv_i)\n+\t\tconst struct pathattr *a = pathattr_lookup(path);\n+\t\tif (a) {\n+\t\t\tif (!a->conv_i)\n \t\t\t\treturn 0;\n-\t\t\treturn attr->conv_i(path, bufp, sizep);\n+\t\t\treturn a->conv_i(path, bufp, sizep, a->conv_i_args);\n \t\t}\n \t}\n \t/* Fallback */\n@@ -268,11 +268,11 @@ int convert_to_working_tree(const char *path, char **bufp,\n \t\t\t    unsigned long *sizep)\n {\n \tif (path) {\n-\t\tconst struct pathattr *attr = pathattr_lookup(path);\n-\t\tif (attr) {\n-\t\t\tif (!attr->conv_o)\n+\t\tconst struct pathattr *a = pathattr_lookup(path);\n+\t\tif (a) {\n+\t\t\tif (!a->conv_o)\n \t\t\t\treturn 0;\n-\t\t\treturn attr->conv_o(path, bufp, sizep);\n+\t\t\treturn a->conv_o(path, bufp, sizep, a->conv_o_args);\n \t\t}\n \t}\n \t/* Fallback */\ndiff --git a/convert.h b/convert.h\nindex e54b3ef..ff6fb85 100644\n--- a/convert.h\n+++ b/convert.h\n@@ -1,9 +1,6 @@\n #ifndef CONVERT_H\n #define CONVERT_H\n \n-typedef int (*convi_fn)(const char *, char **, unsigned long *);\n-typedef int (*convo_fn)(const char *, char **, unsigned long *);\n-\n int convi_crlf(const char *path, char **bufp, unsigned long *sizep);\n int convo_crlf(const char *path, char **bufp, unsigned long *sizep);\n \ndiff --git a/pathattr.c b/pathattr.c\nindex 2532c9a..9362234 100644\n--- a/pathattr.c\n+++ b/pathattr.c\n@@ -1,9 +1,30 @@\n #include \"cache.h\"\n #include \"pathattr.h\"\n \n-static void show_display(const unsigned char *blobdata, unsigned long size)\n+static int convi_pipe(const char *path, char **bufp, unsigned long *sizep,\n+\t\t      const char *args)\n {\n-\tFILE *display = popen(\"display -\", \"w\");\n+\t/* NEEDSWORK: set up two-way pipe, spawn command specified\n+\t * with args, and have it convert bufp & sizep\n+\t */\n+\treturn 0;\n+}\n+\n+static int convo_pipe(const char *path, char **bufp, unsigned long *sizep,\n+\t\t      const char *args)\n+{\n+\t/* NEEDSWORK: set up two-way pipe, spawn command specified\n+\t * with args, and have it convert bufp & sizep\n+\t */\n+\treturn 0;\n+}\n+\n+static void pretty_pipe(const unsigned char *blobdata, unsigned long size,\n+\t\t\tconst char *args)\n+{\n+\tFILE *display;\n+\n+\tdisplay = popen(args, \"w\");\n \tfwrite(blobdata, size, 1, display);\n \tfclose(display);\n }\n@@ -67,6 +88,7 @@ static struct pathattr *locate(struct pathattr_stack *s, const char *name)\n \t\ts->attr = xrealloc(s->attr, sizeof(*a) * s->attr_alloc);\n \t}\n \ta = &(s->attr[s->attr_nr++]);\n+\tmemset(a, 0, sizeof(*a));\n \ta->name = xstrdup(name);\n \treturn a;\n }\n@@ -80,29 +102,57 @@ static void add_match(struct pathattr_stack *s, struct pathattr *a, const char *\n \t\ts->match = xrealloc(s->match, sizeof(*m) * s->match_alloc);\n \t}\n \tm = &(s->match[s->match_nr++]);\n+\tmemset(m, 0, sizeof(*m));\n \tm->pattern = xstrdup(pattern);\n \tm->type = strchr(pattern, '/') ? FNM_PATHNAME : 0;\n \tm->attr = a;\n }\n \n-static convi_fn conv_i_trait(const char *value)\n+static int call_convi_crlf(const char *path, char **bufp, unsigned long *sizep,\n+\t\t\t   const char *args)\n+{\n+\treturn convi_crlf(path, bufp, sizep);\n+}\n+\n+static int call_convo_crlf(const char *path, char **bufp, unsigned long *sizep,\n+\t\t\t   const char *args)\n+{\n+\treturn convo_crlf(path, bufp, sizep);\n+}\n+\n+static int parse_pipe_trait(const char *value, char **args)\n+{\n+\tif (strncmp(value, \"pipe \", 5))\n+\t\treturn 0;\n+\tfree(*args);\n+\t*args = xstrdup(value + 5);\n+\treturn 1;\n+}\n+\n+static convi_fn conv_i_trait(const char *value, struct pathattr *a)\n {\n \tif (!strcmp(value, \"crlf\"))\n-\t\treturn convi_crlf;\n+\t\treturn call_convi_crlf;\n+\tif (parse_pipe_trait(value, &a->conv_i_args))\n+\t\treturn convi_pipe;\n \treturn NULL;\n }\n \n-static convo_fn conv_o_trait(const char *value)\n+static convo_fn conv_o_trait(const char *value, struct pathattr *a)\n {\n \tif (!strcmp(value, \"crlf\"))\n-\t\treturn convo_crlf;\n+\t\treturn call_convo_crlf;\n+\tif (parse_pipe_trait(value, &a->conv_o_args))\n+\t\treturn convo_pipe;\n \treturn NULL;\n }\n \n-static pretty_fn pretty_trait(const char *value)\n+static pretty_fn pretty_trait(const char *value, struct pathattr *a)\n {\n \tif (!strcmp(value, \"display\"))\n-\t\treturn show_display;\n+\t\tvalue = \"pipe display -\";\n+\tif (parse_pipe_trait(value, &a->pretty_args))\n+\t\treturn pretty_pipe;\n \treturn NULL;\n }\n \n@@ -133,11 +183,11 @@ static int attr_config(const char *var, const char *value)\n \tif (!strcmp(trait, \"path\"))\n \t\tadd_match(stk, a, value);\n \telse if (!strcmp(trait, \"conv_i\"))\n-\t\ta->conv_i = conv_i_trait(value);\n+\t\ta->conv_i = conv_i_trait(value, a);\n \telse if (!strcmp(trait, \"conv_o\"))\n-\t\ta->conv_i = conv_o_trait(value);\n+\t\ta->conv_i = conv_o_trait(value, a);\n \telse if (!strcmp(trait, \"pretty\"))\n-\t\ta->pretty = pretty_trait(value);\n+\t\ta->pretty = pretty_trait(value, a);\n \t/*\n \t * Do not barf if the configuration has unknown trait.\n \t * the user might be bisecting git and trying an older\n@@ -154,14 +204,13 @@ static void init_stack(void)\n \n \t/* A couple of silly example as an illustration */\n \ta = locate(stk, \"silly\");\n-\ta->conv_i = convi_crlf;\n-\ta->conv_o = convo_crlf;\n+\ta->conv_i = call_convi_crlf;\n+\ta->conv_o = call_convo_crlf;\n \tadd_match(stk, a, \"*.dos-txt\");\n \n \ta = locate(stk, \"image/*\");\n \ta->conv_i = NULL;\n \ta->conv_o = NULL;\n-\ta->pretty = show_display;\n \tadd_match(stk, a, \"*.png\");\n \tadd_match(stk, a, \"*.jpg\");\n \tadd_match(stk, a, \"*.gif\");\ndiff --git a/pathattr.h b/pathattr.h\nindex bfd9ff1..34e8ce4 100644\n--- a/pathattr.h\n+++ b/pathattr.h\n@@ -3,7 +3,9 @@\n \n #include \"convert.h\"\n \n-typedef void (*pretty_fn)(const unsigned char *blobdata, unsigned long size);\n+typedef int (*convi_fn)(const char *, char **, unsigned long *, const char *);\n+typedef int (*convo_fn)(const char *, char **, unsigned long *, const char *);\n+typedef void (*pretty_fn)(const unsigned char *, unsigned long, const char *);\n \n /*\n  * Data in one section of [pathattr \"name\"], except\n@@ -14,6 +16,10 @@ struct pathattr {\n \tconvi_fn conv_i;\n \tconvo_fn conv_o;\n \tpretty_fn pretty;\n+\n+\tchar *conv_i_args;\n+\tchar *conv_o_args;\n+\tchar *pretty_args;\n };\n \n const struct pathattr *pathattr_lookup(const char *);\n-- \n1.5.0.2.809.g0f936\n"},{"id":"35946","messageId":"7vodnduwx3.fsf@assigned-by-dhcp.cox.net","threadId":"7030","inReplyTo":"7vzm6xux9o.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 4/2] pathattr: allow piping to external program.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2007-03-01T09:37:28Z","receivedAt":"2007-03-01T09:37:28Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> This sets up capability for various traits to be an external\n> process, accessed via pipe.  conv-i and conv-o need to spawn\n> bidirectional pipe, but I have not coded that part yet.\n>\n> You can try running:\n>\n>     $ git show HEAD:Documentation/*.txt\n\n... obviously I meant\n\n\t$ git show HEAD:Documentation/git.txt\n\nor something a bit more concrete than '*' here.\n\n>\n> with:\n>\n>     [pathattr \"kludge\"]\n>         path = Documentation/*.txt\n>         pretty = \"pipe sed -e 's/^/>> /'\"\n>\n> to see what it does.\n>\n> Signed-off-by: Junio C Hamano <junkio@cox.net>\n"}]}