{"thread":{"id":"1608","subject":"Make \"git-ls-files\" work in subdirectories","startedAt":"2005-08-21T19:55:33Z","lastAt":"2005-08-21T23:50:19Z","messageCount":5,"participants":["Linus Torvalds","Chris Wedgwood","YOSHIFUJI Hideaki / 吉藤英明"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"7608","messageId":"Pine.LNX.4.58.0508211210500.3317@g5.osdl.org","threadId":"1608","inReplyTo":null,"subject":"Make \"git-ls-files\" work in subdirectories","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-21T19:55:33Z","receivedAt":"2005-08-21T19:55:33Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis makes git-ls-files work inside a relative directory, and also adds\nsome rudimentary filename globbing support. For example, in the kernel you\ncan now do\n\n\tcd arch/i386\n\tgit-ls-files\n\nand it will show all files under that subdirectory (and it will have\nremoved the \"arch/i386/\" prefix unless you give it the \"--full-name\"  \noption, so that you can feed the result to \"xargs grep\" or similar).\n\nThe filename globbing is kind of strange: it does _not_ follow normal \nglobbing rules, although it does look \"almost\" like a normal file glob \n(and it uses the POSIX.2 \"fnmatch()\" function).\n\nThe glob pattern (there can be only one) is always split into a \"directory \npart\" and a \"glob part\", where the directory part is defined as any full \ndirectory path without any '*' or '?' characters. The \"glob\" part is \nwhatever is left over.\n\nFor example, when doing\n\n\tgit-ls-files 'arch/i386/p*/*.c'\n\nthe \"directory part\" is is \"arch/i386/\", and the \"glob part\" is \"p*/*.c\". \nThe directory part will be added to the prefix, and handled efficiently \n(ie we will not be searching outside of that subdirectory), while the glob \npart (if anything is left over) will be used to trigger \"fnmatch()\" \nmatches.\n\nThis is efficient and very useful, but can result in somewhat\nnon-intuitive behaviour.\n\nFor example:\n\n\tgit-ls-files 'arch/i386/*.[ch]'\n\nwill find all .c and .h files under arch/i386/, _including_ things in\nlower subdirectories (ie it will match \"arch/i386/kernel/process.c\",\nbecause \"kernel/process.c\" will match the \"*.c\" specifier).\n\nAlso, while\n\n\tgit-ls-files arch/i386/\n\nwill show all files under that subdirectory, doing the same without the\nfinal slash would try to show the file \"i386\" under the \"arch/\"  \nsubdirectory, and since there is no such file (even if there is such a\n_directory_) it will not match anything at all.\n\nThese semantics may not seem intuitive, but they are actually very\npractical. In particular, it makes it very simple to do\n\n\tgit-ls-files fs/*.c | xargs grep some_pattern\n\nand it does what you want.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n[ Implementation note: the difference between \"prefix_len\" and \n  \"prefix_offset\" is that \"prefix_len\" is used for all the compare logic, \n  while \"prefix_offset\" is used to determine how much of the prefix not to\n  print out. So \"--full-name\" just clears prefix_offset, which keeps all\n  the comparisons the same, but prints out the full absolute git path,\n  rather than the relative one.\n\n  Also: unlike things like \"git-diff-files\" etc, we do _not_ handle \n  prefixes containint \"..\" and \"./\" etc gracefully. That's partly exactly \n  because the result of git-ls-files is normally a relative pathname, and\n  it just makes it almost impossible to do what the git-diff-* functions \n  do efficiently and with sane semantics ]\n\n---\ndiff --git a/ls-files.c b/ls-files.c\n--- a/ls-files.c\n+++ b/ls-files.c\n@@ -19,6 +19,10 @@ static int show_unmerged = 0;\n static int show_killed = 0;\n static int line_terminator = '\\n';\n \n+static int prefix_len = 0, prefix_offset = 0;\n+static const char *prefix = NULL;\n+static const char *glob = NULL;\n+\n static const char *tag_cached = \"\";\n static const char *tag_unmerged = \"\";\n static const char *tag_removed = \"\";\n@@ -222,6 +226,7 @@ static void add_name(const char *pathnam\n \tent = xmalloc(sizeof(*ent) + len + 1);\n \tent->len = len;\n \tmemcpy(ent->name, pathname, len);\n+\tent->name[len] = 0;\n \tdir[nr_dir++] = ent;\n }\n \n@@ -297,6 +302,20 @@ static int cmp_name(const void *p1, cons\n \t\t\t\t  e2->name, e2->len);\n }\n \n+static void show_dir_entry(const char *tag, struct nond_on_fs *ent)\n+{\n+\tint len = prefix_len;\n+\tint offset = prefix_offset;\n+\n+\tif (len >= ent->len)\n+\t\tdie(\"git-ls-files: internal error - directory entry not superset of prefix\");\n+\n+\tif (glob && fnmatch(glob, ent->name + len, 0))\n+\t\treturn;\n+\n+\tprintf(\"%s%s%c\", tag, ent->name + offset, line_terminator);\n+}\n+\n static void show_killed_files(void)\n {\n \tint i;\n@@ -342,25 +361,48 @@ static void show_killed_files(void)\n \t\t\t}\n \t\t}\n \t\tif (killed)\n-\t\t\tprintf(\"%s%.*s%c\", tag_killed,\n-\t\t\t       dir[i]->len, dir[i]->name,\n-\t\t\t       line_terminator);\n+\t\t\tshow_dir_entry(tag_killed, dir[i]);\n \t}\n }\n \n+static void show_ce_entry(const char *tag, struct cache_entry *ce)\n+{\n+\tint len = prefix_len;\n+\tint offset = prefix_offset;\n+\n+\tif (len >= ce_namelen(ce))\n+\t\tdie(\"git-ls-files: internal error - cache entry not superset of prefix\");\n+\n+\tif (glob && fnmatch(glob, ce->name + len, 0))\n+\t\treturn;\n+\n+\tif (!show_stage)\n+\t\tprintf(\"%s%s%c\", tag, ce->name + offset, line_terminator);\n+\telse\n+\t\tprintf(\"%s%06o %s %d\\t%s%c\",\n+\t\t       tag,\n+\t\t       ntohl(ce->ce_mode),\n+\t\t       sha1_to_hex(ce->sha1),\n+\t\t       ce_stage(ce),\n+\t\t       ce->name + offset, line_terminator); \n+}\n+\n static void show_files(void)\n {\n \tint i;\n \n \t/* For cached/deleted files we don't need to even do the readdir */\n \tif (show_others || show_killed) {\n-\t\tread_directory(\".\", \"\", 0);\n+\t\tconst char *path = \".\", *base = \"\";\n+\t\tint baselen = prefix_len;\n+\n+\t\tif (baselen)\n+\t\t\tpath = base = prefix;\n+\t\tread_directory(path, base, baselen);\n \t\tqsort(dir, nr_dir, sizeof(struct nond_on_fs *), cmp_name);\n \t\tif (show_others)\n \t\t\tfor (i = 0; i < nr_dir; i++)\n-\t\t\t\tprintf(\"%s%.*s%c\", tag_other,\n-\t\t\t\t       dir[i]->len, dir[i]->name,\n-\t\t\t\t       line_terminator);\n+\t\t\t\tshow_dir_entry(tag_other, dir[i]);\n \t\tif (show_killed)\n \t\t\tshow_killed_files();\n \t}\n@@ -371,19 +413,7 @@ static void show_files(void)\n \t\t\t\tcontinue;\n \t\t\tif (show_unmerged && !ce_stage(ce))\n \t\t\t\tcontinue;\n-\t\t\tif (!show_stage)\n-\t\t\t\tprintf(\"%s%s%c\",\n-\t\t\t\t       ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t       tag_cached,\n-\t\t\t\t       ce->name, line_terminator);\n-\t\t\telse\n-\t\t\t\tprintf(\"%s%06o %s %d\\t%s%c\",\n-\t\t\t\t       ce_stage(ce) ? tag_unmerged :\n-\t\t\t\t       tag_cached,\n-\t\t\t\t       ntohl(ce->ce_mode),\n-\t\t\t\t       sha1_to_hex(ce->sha1),\n-\t\t\t\t       ce_stage(ce),\n-\t\t\t\t       ce->name, line_terminator); \n+\t\t\tshow_ce_entry(ce_stage(ce) ? tag_unmerged : tag_cached, ce);\n \t\t}\n \t}\n \tif (show_deleted) {\n@@ -394,9 +424,66 @@ static void show_files(void)\n \t\t\t\tcontinue;\n \t\t\tif (!lstat(ce->name, &st))\n \t\t\t\tcontinue;\n-\t\t\tprintf(\"%s%s%c\", tag_removed, ce->name,\n-\t\t\t       line_terminator);\n+\t\t\tshow_ce_entry(tag_removed, ce);\n+\t\t}\n+\t}\n+}\n+\n+/*\n+ * Prune the index to only contain stuff starting with \"prefix\"\n+ */\n+static void prune_cache(void)\n+{\n+\tint pos = cache_name_pos(prefix, prefix_len);\n+\tunsigned int first, last;\n+\n+\tif (pos < 0)\n+\t\tpos = -pos-1;\n+\tactive_cache += pos;\n+\tactive_nr -= pos;\n+\tfirst = 0;\n+\tlast = active_nr;\n+\twhile (last > first) {\n+\t\tint next = (last + first) >> 1;\n+\t\tstruct cache_entry *ce = active_cache[next];\n+\t\tif (!strncmp(ce->name, prefix, prefix_len)) {\n+\t\t\tfirst = next+1;\n+\t\t\tcontinue;\n \t\t}\n+\t\tlast = next;\n+\t}\n+\tactive_nr = last;\n+}\n+\n+/*\n+ * If the glob starts with a subdirectory, append it to\n+ * the prefix instead, for more efficient operation.\n+ *\n+ * But we do not update the \"prefix_offset\", which tells\n+ * how much of the name to ignore at printout.\n+ */\n+static void extend_prefix(void)\n+{\n+\tconst char *p, *slash;\n+\tchar c;\n+\n+\tp = glob;\n+\tslash = NULL;\n+\twhile ((c = *p++) != '\\0') {\n+\t\tif (c == '*')\n+\t\t\tbreak;\n+\t\tif (c == '/')\n+\t\t\tslash = p;\n+\t}\n+\tif (slash) {\n+\t\tint len = slash - glob;\n+\t\tchar *newprefix = xmalloc(len + prefix_len + 1);\n+\t\tmemcpy(newprefix, prefix, prefix_len);\n+\t\tmemcpy(newprefix + prefix_len, glob, len);\n+\t\tprefix_len += len;\n+\t\tnewprefix[prefix_len] = 0;\n+\t\tprefix = newprefix;\n+\t\tglob = *slash ? slash : NULL;\n \t}\n }\n \n@@ -410,54 +497,94 @@ int main(int argc, char **argv)\n \tint i;\n \tint exc_given = 0;\n \n+\tprefix = setup_git_directory();\n+\tif (prefix)\n+\t\tprefix_offset = prefix_len = strlen(prefix);\n+\n \tfor (i = 1; i < argc; i++) {\n \t\tchar *arg = argv[i];\n \n \t\tif (!strcmp(arg, \"-z\")) {\n \t\t\tline_terminator = 0;\n-\t\t} else if (!strcmp(arg, \"-t\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-t\")) {\n \t\t\ttag_cached = \"H \";\n \t\t\ttag_unmerged = \"M \";\n \t\t\ttag_removed = \"R \";\n \t\t\ttag_other = \"? \";\n \t\t\ttag_killed = \"K \";\n-\t\t} else if (!strcmp(arg, \"-c\") || !strcmp(arg, \"--cached\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-c\") || !strcmp(arg, \"--cached\")) {\n \t\t\tshow_cached = 1;\n-\t\t} else if (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n \t\t\tshow_deleted = 1;\n-\t\t} else if (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n \t\t\tshow_others = 1;\n-\t\t} else if (!strcmp(arg, \"-i\") || !strcmp(arg, \"--ignored\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-i\") || !strcmp(arg, \"--ignored\")) {\n \t\t\tshow_ignored = 1;\n-\t\t} else if (!strcmp(arg, \"-s\") || !strcmp(arg, \"--stage\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-s\") || !strcmp(arg, \"--stage\")) {\n \t\t\tshow_stage = 1;\n-\t\t} else if (!strcmp(arg, \"-k\") || !strcmp(arg, \"--killed\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-k\") || !strcmp(arg, \"--killed\")) {\n \t\t\tshow_killed = 1;\n-\t\t} else if (!strcmp(arg, \"-u\") || !strcmp(arg, \"--unmerged\")) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-u\") || !strcmp(arg, \"--unmerged\")) {\n \t\t\t/* There's no point in showing unmerged unless\n \t\t\t * you also show the stage information.\n \t\t\t */\n \t\t\tshow_stage = 1;\n \t\t\tshow_unmerged = 1;\n-\t\t} else if (!strcmp(arg, \"-x\") && i+1 < argc) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-x\") && i+1 < argc) {\n \t\t\texc_given = 1;\n \t\t\tadd_exclude(argv[++i], \"\", 0, &exclude_list[EXC_CMDL]);\n-\t\t} else if (!strncmp(arg, \"--exclude=\", 10)) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--exclude=\", 10)) {\n \t\t\texc_given = 1;\n \t\t\tadd_exclude(arg+10, \"\", 0, &exclude_list[EXC_CMDL]);\n-\t\t} else if (!strcmp(arg, \"-X\") && i+1 < argc) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"-X\") && i+1 < argc) {\n \t\t\texc_given = 1;\n \t\t\tadd_excludes_from_file(argv[++i]);\n-\t\t} else if (!strncmp(arg, \"--exclude-from=\", 15)) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--exclude-from=\", 15)) {\n \t\t\texc_given = 1;\n \t\t\tadd_excludes_from_file(arg+15);\n-\t\t} else if (!strncmp(arg, \"--exclude-per-directory=\", 24)) {\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strncmp(arg, \"--exclude-per-directory=\", 24)) {\n \t\t\texc_given = 1;\n \t\t\texclude_per_dir = arg + 24;\n-\t\t} else\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (!strcmp(arg, \"--full-name\")) {\n+\t\t\tprefix_offset = 0;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (glob || *arg == '-')\n \t\t\tusage(ls_files_usage);\n+\t\tglob = arg;\n \t}\n \n+\tif (glob)\n+\t\textend_prefix();\n+\n \tif (show_ignored && !exc_given) {\n \t\tfprintf(stderr, \"%s: --ignored needs some exclude pattern\\n\",\n \t\t\targv[0]);\n@@ -469,6 +596,8 @@ int main(int argc, char **argv)\n \t\tshow_cached = 1;\n \n \tread_cache();\n+\tif (prefix)\n+\t\tprune_cache();\n \tshow_files();\n \treturn 0;\n }\n"},{"id":"7615","messageId":"20050821224622.GB26241@taniwha.stupidest.org","threadId":"1608","inReplyTo":"Pine.LNX.4.58.0508211210500.3317@g5.osdl.org","subject":"Re: Make \"git-ls-files\" work in subdirectories","fromName":"Chris Wedgwood","fromEmail":"cw@f00f.org","sentAt":"2005-08-21T22:46:22Z","receivedAt":"2005-08-21T22:46:22Z","isPatch":false,"sender":{"key":"cw@f00f.org","avatar":null},"body":"On Sun, Aug 21, 2005 at 12:55:33PM -0700, Linus Torvalds wrote:\n\n> -\t\t} else if (!strcmp(arg, \"-t\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-t\")) {\n>  \t\t\ttag_cached = \"H \";\n>  \t\t\ttag_unmerged = \"M \";\n>  \t\t\ttag_removed = \"R \";\n>  \t\t\ttag_other = \"? \";\n>  \t\t\ttag_killed = \"K \";\n> -\t\t} else if (!strcmp(arg, \"-c\") || !strcmp(arg, \"--cached\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-c\") || !strcmp(arg, \"--cached\")) {\n>  \t\t\tshow_cached = 1;\n> -\t\t} else if (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-d\") || !strcmp(arg, \"--deleted\")) {\n>  \t\t\tshow_deleted = 1;\n> -\t\t} else if (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-o\") || !strcmp(arg, \"--others\")) {\n>  \t\t\tshow_others = 1;\n> -\t\t} else if (!strcmp(arg, \"-i\") || !strcmp(arg, \"--ignored\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-i\") || !strcmp(arg, \"--ignored\")) {\n>  \t\t\tshow_ignored = 1;\n> -\t\t} else if (!strcmp(arg, \"-s\") || !strcmp(arg, \"--stage\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-s\") || !strcmp(arg, \"--stage\")) {\n>  \t\t\tshow_stage = 1;\n> -\t\t} else if (!strcmp(arg, \"-k\") || !strcmp(arg, \"--killed\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-k\") || !strcmp(arg, \"--killed\")) {\n>  \t\t\tshow_killed = 1;\n> -\t\t} else if (!strcmp(arg, \"-u\") || !strcmp(arg, \"--unmerged\")) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-u\") || !strcmp(arg, \"--unmerged\")) {\n>  \t\t\t/* There's no point in showing unmerged unless\n>  \t\t\t * you also show the stage information.\n>  \t\t\t */\n>  \t\t\tshow_stage = 1;\n>  \t\t\tshow_unmerged = 1;\n> -\t\t} else if (!strcmp(arg, \"-x\") && i+1 < argc) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-x\") && i+1 < argc) {\n>  \t\t\texc_given = 1;\n>  \t\t\tadd_exclude(argv[++i], \"\", 0, &exclude_list[EXC_CMDL]);\n> -\t\t} else if (!strncmp(arg, \"--exclude=\", 10)) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strncmp(arg, \"--exclude=\", 10)) {\n>  \t\t\texc_given = 1;\n>  \t\t\tadd_exclude(arg+10, \"\", 0, &exclude_list[EXC_CMDL]);\n> -\t\t} else if (!strcmp(arg, \"-X\") && i+1 < argc) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"-X\") && i+1 < argc) {\n>  \t\t\texc_given = 1;\n>  \t\t\tadd_excludes_from_file(argv[++i]);\n> -\t\t} else if (!strncmp(arg, \"--exclude-from=\", 15)) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strncmp(arg, \"--exclude-from=\", 15)) {\n>  \t\t\texc_given = 1;\n>  \t\t\tadd_excludes_from_file(arg+15);\n> -\t\t} else if (!strncmp(arg, \"--exclude-per-directory=\", 24)) {\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strncmp(arg, \"--exclude-per-directory=\", 24)) {\n>  \t\t\texc_given = 1;\n>  \t\t\texclude_per_dir = arg + 24;\n> -\t\t} else\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (!strcmp(arg, \"--full-name\")) {\n> +\t\t\tprefix_offset = 0;\n> +\t\t\tcontinue;\n> +\t\t}\n> +\t\tif (glob || *arg == '-')\n>  \t\t\tusage(ls_files_usage);\n> +\t\tglob = arg;\n\nis there some aversion to getopt or similar get?\n"},{"id":"7616","messageId":"Pine.LNX.4.58.0508211613340.3317@g5.osdl.org","threadId":"1608","inReplyTo":"20050821224622.GB26241@taniwha.stupidest.org","subject":"Re: Make \"git-ls-files\" work in subdirectories","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-08-21T23:17:52Z","receivedAt":"2005-08-21T23:17:52Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 21 Aug 2005, Chris Wedgwood wrote:\n> \n> is there some aversion to getopt or similar get?\n\ngetopt() is too limited, and getopt_long() is very glibc-specific and thus\ninherently evil. And the complexity of doing autoconf or similar is worse\nthan just doing it by hand.\n\nI've considered doing a small library that could just be contained withing \nthe git sources to avoid duplication, but it just hasn't been worth it.\n\nIf somebody wants to do it, go wild. The rules are\n - anything that is not expected of \"modern unix\" is too unportable (glibc \n   is not a realistic expectation, but a lot of GNU tools _are_ realistic)\n - autoconf and its ilk are worse than the disease they are trying to fix\n\n\t\tLinus\n"},{"id":"7617","messageId":"20050821234544.GA19869@taniwha.stupidest.org","threadId":"1608","inReplyTo":"Pine.LNX.4.58.0508211613340.3317@g5.osdl.org","subject":"Re: Make \"git-ls-files\" work in subdirectories","fromName":"Chris Wedgwood","fromEmail":"cw@f00f.org","sentAt":"2005-08-21T23:45:44Z","receivedAt":"2005-08-21T23:45:44Z","isPatch":false,"sender":{"key":"cw@f00f.org","avatar":null},"body":"On Sun, Aug 21, 2005 at 04:17:52PM -0700, Linus Torvalds wrote:\n\n> getopt() is too limited, and getopt_long() is very glibc-specific\n> and thus inherently evil. And the complexity of doing autoconf or\n> similar is worse than just doing it by hand.\n\nwhat about libpopt?\n"},{"id":"7619","messageId":"20050822.085019.32290547.yoshfuji@linux-ipv6.org","threadId":"1608","inReplyTo":"Pine.LNX.4.58.0508211613340.3317@g5.osdl.org","subject":"Re: Make \"git-ls-files\" work in subdirectories","fromName":"YOSHIFUJI Hideaki / 吉藤英明","fromEmail":"yoshfuji@linux-ipv6.org","sentAt":"2005-08-21T23:50:19Z","receivedAt":"2005-08-21T23:50:19Z","isPatch":false,"sender":{"key":"yoshfuji@linux-ipv6.org","avatar":"https://gravatar.com/avatar/92c288bb8d3e34afd7bb1574cc1079a3d0aa6d36d80955d1ec6a1cea2868d392?d=mp&s=160"},"body":"In article <Pine.LNX.4.58.0508211613340.3317@g5.osdl.org> (at Sun, 21 Aug 2005 16:17:52 -0700 (PDT)), Linus Torvalds <torvalds@osdl.org> says:\n\n> getopt() is too limited, and getopt_long() is very glibc-specific and thus\n> inherently evil. And the complexity of doing autoconf or similar is worse\n> than just doing it by hand.\n\n(I'm not against having our own getopt_long()\nor alike, but anyway...)\n\nWell, not really \"glibc-specific\" now.\n\nNetBSD (>=1.5) has thir own implementation of getopt_long()\n(w/ 4-clause BSD licence, which is not compatible w/ GPL2).\nOpenBSD (>=3.3), FreeBSD (>=5.0), too.\nSolaris (>=9?) seems to have one, too.\n\nNetBSD: http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/getopt_long.c\nOpenBSD: http://www.openbsd.org/cgi-bin/cvsweb.cgi/src/lib/libc/stdlib/getopt_long.c\nFreeBSD: http://www.freebsd.org/cgi/cvsweb.cgi/src/lib/libc/stdlib/getopt_long.c\nSolaris: http://iforce.sun.com/protected/solaris10/adoptionkit/general/getopt_long.txt\n\n--yoshfuji\n"}]}