77#include "utf8.h"
88#include "mailmap.h"
99#include "shortlog.h"
10+ #include "parse-options.h"
1011
11- static const char shortlog_usage [] =
12- "git-shortlog [-n] [-s] [-e] [-w] [<commit-id>... ]" ;
12+ static char const * const shortlog_usage [] = {
13+ "git-shortlog [-n] [-s] [-e] [-w] [rev-opts] [--] [<commit-id>... ]" ,
14+ "" ,
15+ "[rev-opts] are documented in git-rev-list(1)" ,
16+ NULL
17+ };
1318
1419static int compare_by_number (const void * a1 , const void * a2 )
1520{
@@ -164,21 +169,19 @@ static void get_from_rev(struct rev_info *rev, struct shortlog *log)
164169 shortlog_add_commit (log , commit );
165170}
166171
167- static int parse_uint (char const * * arg , int comma )
172+ static int parse_uint (char const * * arg , int comma , int defval )
168173{
169174 unsigned long ul ;
170175 int ret ;
171176 char * endp ;
172177
173178 ul = strtoul (* arg , & endp , 10 );
174- if (endp != * arg && * endp && * endp != comma )
179+ if (* endp && * endp != comma )
175180 return -1 ;
176- ret = (int ) ul ;
177- if (ret != ul )
181+ if (ul > INT_MAX )
178182 return -1 ;
179- * arg = endp ;
180- if (* * arg )
181- (* arg )++ ;
183+ ret = * arg == endp ? defval : (int )ul ;
184+ * arg = * endp ? endp + 1 : endp ;
182185 return ret ;
183186}
184187
@@ -187,30 +190,30 @@ static const char wrap_arg_usage[] = "-w[<width>[,<indent1>[,<indent2>]]]";
187190#define DEFAULT_INDENT1 6
188191#define DEFAULT_INDENT2 9
189192
190- static void parse_wrap_args (const char * arg , int * in1 , int * in2 , int * wrap )
193+ static int parse_wrap_args (const struct option * opt , const char * arg , int unset )
191194{
192- arg += 2 ; /* skip -w */
193-
194- * wrap = parse_uint ( & arg , ',' ) ;
195- if (* wrap < 0 )
196- die ( wrap_arg_usage ) ;
197- * in1 = parse_uint ( & arg , ',' );
198- if ( * in1 < 0 )
199- die ( wrap_arg_usage ) ;
200- * in2 = parse_uint ( & arg , '\0' ) ;
201- if ( * in2 < 0 )
202- die ( wrap_arg_usage );
203-
204- if (! * wrap )
205- * wrap = DEFAULT_WRAPLEN ;
206- if (! * in1 )
207- * in1 = DEFAULT_INDENT1 ;
208- if (! * in2 )
209- * in2 = DEFAULT_INDENT2 ;
210- if ( * wrap &&
211- (( * in1 && * wrap <= * in1 ) ||
212- ( * in2 && * wrap <= * in2 )))
213- die ( wrap_arg_usage ) ;
195+ struct shortlog * log = opt -> value ;
196+
197+ log -> wrap_lines = ! unset ;
198+ if (unset )
199+ return 0 ;
200+ if (! arg ) {
201+ log -> wrap = DEFAULT_WRAPLEN ;
202+ log -> in1 = DEFAULT_INDENT1 ;
203+ log -> in2 = DEFAULT_INDENT2 ;
204+ return 0 ;
205+ }
206+
207+ log -> wrap = parse_uint ( & arg , ',' , DEFAULT_WRAPLEN );
208+ log -> in1 = parse_uint ( & arg , ',' , DEFAULT_INDENT1 ) ;
209+ log -> in2 = parse_uint ( & arg , '\0' , DEFAULT_INDENT2 );
210+ if ( log -> wrap < 0 || log -> in1 < 0 || log -> in2 < 0 )
211+ return error ( wrap_arg_usage );
212+ if ( log -> wrap &&
213+ (( log -> in1 && log -> wrap <= log -> in1 ) ||
214+ ( log -> in2 && log -> wrap <= log -> in2 )))
215+ return error ( wrap_arg_usage );
216+ return 0 ;
214217}
215218
216219void shortlog_init (struct shortlog * log )
@@ -227,38 +230,54 @@ void shortlog_init(struct shortlog *log)
227230
228231int cmd_shortlog (int argc , const char * * argv , const char * prefix )
229232{
230- struct shortlog log ;
231- struct rev_info rev ;
233+ static struct shortlog log ;
234+ static struct rev_info rev ;
232235 int nongit ;
233236
237+ static const struct option options [] = {
238+ OPT_BOOLEAN ('n' , "numbered" , & log .sort_by_number ,
239+ "sort output according to the number of commits per author" ),
240+ OPT_BOOLEAN ('s' , "summary" , & log .summary ,
241+ "Suppress commit descriptions, only provides commit count" ),
242+ OPT_BOOLEAN ('e' , "email" , & log .email ,
243+ "Show the email address of each author" ),
244+ { OPTION_CALLBACK , 'w' , NULL , & log , "w[,i1[,i2]]" ,
245+ "Linewrap output" , PARSE_OPT_OPTARG , & parse_wrap_args },
246+ OPT_END (),
247+ };
248+
249+ struct parse_opt_ctx_t ctx ;
250+
234251 prefix = setup_git_directory_gently (& nongit );
235252 shortlog_init (& log );
236-
237- /* since -n is a shadowed rev argument, parse our args first */
238- while (argc > 1 ) {
239- if (!strcmp (argv [1 ], "-n" ) || !strcmp (argv [1 ], "--numbered" ))
240- log .sort_by_number = 1 ;
241- else if (!strcmp (argv [1 ], "-s" ) ||
242- !strcmp (argv [1 ], "--summary" ))
243- log .summary = 1 ;
244- else if (!strcmp (argv [1 ], "-e" ) ||
245- !strcmp (argv [1 ], "--email" ))
246- log .email = 1 ;
247- else if (!prefixcmp (argv [1 ], "-w" )) {
248- log .wrap_lines = 1 ;
249- parse_wrap_args (argv [1 ], & log .in1 , & log .in2 , & log .wrap );
253+ init_revisions (& rev , prefix );
254+ parse_options_start (& ctx , argc , argv , PARSE_OPT_KEEP_DASHDASH |
255+ PARSE_OPT_KEEP_ARGV0 );
256+
257+ for (;;) {
258+ int n ;
259+ switch (parse_options_step (& ctx , options , shortlog_usage )) {
260+ case PARSE_OPT_HELP :
261+ exit (129 );
262+ case PARSE_OPT_DONE :
263+ goto parse_done ;
250264 }
251- else if (!strcmp (argv [1 ], "-h" ) || !strcmp (argv [1 ], "--help" ))
252- usage (shortlog_usage );
253- else
254- break ;
255- argv ++ ;
256- argc -- ;
265+ n = handle_revision_opt (& rev , ctx .argc , ctx .argv ,
266+ & ctx .cpidx , ctx .out );
267+ if (n <= 0 ) {
268+ error ("unknown option `%s'" , ctx .argv [0 ]);
269+ usage_with_options (shortlog_usage , options );
270+ }
271+ ctx .argv += n ;
272+ ctx .argc -= n ;
273+ }
274+ parse_done :
275+ argc = parse_options_end (& ctx );
276+
277+ if (setup_revisions (argc , argv , & rev , NULL ) != 1 ) {
278+ error ("unrecognized argument: %s" , argv [1 ]);
279+ usage_with_options (shortlog_usage , options );
257280 }
258- init_revisions (& rev , prefix );
259- argc = setup_revisions (argc , argv , & rev , NULL );
260- if (argc > 1 )
261- die ("unrecognized argument: %s" , argv [1 ]);
262281
263282 /* assume HEAD if from a tty */
264283 if (!nongit && !rev .pending .nr && isatty (0 ))
0 commit comments