git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v4 05/18] Parse the -L options

From
Junio C Hamano <gitster@pobox.com>
Date
Aug 6, 2010, 19:42 UTC
Message-ID
<7v39ur8r56.fsf@alter.siamese.dyndns.org>
In-Reply-To
<1281024717-7855-6-git-send-email-struggleyb.nku@gmail.com>
Bo Yang <struggleyb.nku@gmail.com> writes:
Show 10 quoted lines
>  static void cmd_log_init(int argc, const char **argv, const char *prefix,
>  			 struct rev_info *rev, struct setup_revision_opt *opt)
>  {
>  	int i;
>  	int decoration_given = 0;
>  	struct userformat_want w;
> +	const char *path = NULL, *pathspec = NULL;
> +	static struct diff_line_range *range = NULL, *r = NULL;
> +	static struct parse_opt_ctx_t ctx;
> +	static struct line_opt_callback_data line_cb = {&range, &ctx, NULL};

Do these have to be static? cmd_log_init() may be near the top of the call chain and has less reason to be reentrant, but it feels somewhat wrong if we are placing something that should live on stack in BSS.

Show 16 quoted lines
> +	static const struct option options[] = {
> +		OPT_CALLBACK('L', NULL, &line_cb, "n,m", "Process only line range n,m, counting from 1", log_line_range_callback),
> +		OPT_END()
> +	};
> + ...
> +	parse_options_start(&ctx, argc, argv, prefix, PARSE_OPT_KEEP_DASHDASH |
> +			PARSE_OPT_KEEP_ARGV0 | PARSE_OPT_STOP_AT_NON_OPTION);
> +	for (;;) {
> +		switch (parse_options_step(&ctx, options, log_opt_usage)) {
> +		case PARSE_OPT_HELP:
> +			exit(129);
> +		case PARSE_OPT_DONE:
> +			goto parse_done;
> +		case PARSE_OPT_NON_OPTION:
> + ... do the extra path thing ...
> +			pathspec = prefix_path(prefix, prefix ? strlen(prefix) : 0, path);

Please do not call it "pathspec", as this is a specific path in a commit. "pathspec" is a pattern to be matched to zero or more paths.

Show 9 quoted lines
> ...
> +			parse_options_next(&ctx, 1);
> +			continue;
> +		case PARSE_OPT_UNKNOWN:
> +			parse_options_next(&ctx, 1);
> +			continue;
> +		}
> +		parse_revision_opt(rev, &ctx, options, log_opt_usage);
> +	}

Hmm, so the strategy is that you first run the command line through a pass of parse-options that is aware only of "-L" syntax, eat whatever it recognizes, and give remainder to the setup_revisions().

While I agree with that strategy in general, I think this implementation is ugly. It may be even wrong. For example, can a user specify a path that begins with a dash with this parser?

My gut feeling is that the capturing of the (optional) second argument given to -L is better done inside your callback.

Now, the current callback interface does not give you access to ctx so you may need to invent a new type of "more powerful callback API" that gives you access to the ctx as well, but if you did so, you should be able to do something like:

    static int log_line_range_callback(...)
    {
	arg = parse_options_current(ctx);
        ... make sure it is a line range, e.g. "10,20"
        parse_options_next(ctx); /* consume it */
        path = parse_options_current(ctx); /* peek the second position */
        if (does it look like a path?) {
		... associate path with the range in arg
		parse_options_next(ctx); /* consume it */
	} else if (have we already got another range earlier?) {
        	... use the previous path with the range in arg
        } else {
        	die("-L range not followed by path");
	}
    }

no? In the above illustration, I am assuming that the "more powerful" one allows the callback to control even parsing of the first argument, i.e. parse-options does not call get_arg() before calling you back.

And "does it look like a path?" logic could say something like "If it is in the index, it is a path, even if it begins with a dash", or "If it is prefixed with ./, then it is always a path but we strip that dot-slash out", and somesuch, to make the heuristic of "do we have the optional second parameter?" better than "we do not allow a path that begins with a dash". After all, the callback for -L knows better than the generic "parse-options" infrastructure what to expect for the optional argument at the second position.

And if you do that, I suspect that you also can lose the "clear up the last range" hack after the loop is done, no?

Previous: Bo YangNext: Bo Yang
Message 10 of 28 in “Reroll the line log series”
  1. 00/18 Reroll the line log seriesBo Yang, Aug 5, 2010
  2. 01/18 parse-options: enhance STOP_AT_NON_OPTIONBo Yang, Aug 5, 2010
  3. 02/18 parse-options: add two helper functionsBo Yang, Aug 5, 2010
  4. Thomas RastAug 5, 2010
  5. 03/18 Add the basic data structure for line level historyBo Yang, Aug 5, 2010
  6. Thomas RastAug 5, 2010
  7. Junio C HamanoAug 6, 2010
  8. 04/18 Refactor parse_locBo Yang, Aug 5, 2010
  9. 05/18 Parse the -L optionsBo Yang, Aug 5, 2010
  10. Junio C HamanoAug 6, 2010
  11. Bo YangAug 10, 2010
  12. 06/18 Export three functions from diff.cBo Yang, Aug 5, 2010
  13. 07/18 Add range clone functionsBo Yang, Aug 5, 2010
  14. 08/18 map/take range to the parent of commitsBo Yang, Aug 5, 2010
  15. Thomas RastAug 5, 2010
  16. 09/18 Print the line logBo Yang, Aug 5, 2010
  17. 10/18 Hook line history into cmd_log, ensuring a topo-ordered walkBo Yang, Aug 5, 2010
  18. 11/18 Add tests for line history browserBo Yang, Aug 5, 2010
  19. Thomas RastAug 5, 2010
  20. Bo YangAug 6, 2010
  21. Thomas RastAug 6, 2010
  22. 12/18 Make rewrite_parents public to other part of gitBo Yang, Aug 5, 2010
  23. 13/18 Make graph_next_line external to other part of gitBo Yang, Aug 5, 2010
  24. 14/18 Add parent rewriting to line history browserBo Yang, Aug 5, 2010
  25. 15/18 Add --graph prefix before line history outputBo Yang, Aug 5, 2010
  26. 16/18 Add --full-line-diff optionBo Yang, Aug 5, 2010
  27. 17/18 Add test cases for '--graph' of line level logBo Yang, Aug 5, 2010
  28. 18/18 Document line history browserBo Yang, Aug 5, 2010

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.