@@ -123,7 +123,7 @@ static int parse_long_opt(struct optparse_t *p, const char *arg,
123123}
124124
125125int parse_options (int argc , const char * * argv , const struct option * options ,
126- const char * usagestr , int flags )
126+ const char * const usagestr [] , int flags )
127127{
128128 struct optparse_t args = { argv + 1 , argc - 1 , NULL };
129129 int j = 0 ;
@@ -140,9 +140,9 @@ int parse_options(int argc, const char **argv, const struct option *options,
140140 args .opt = arg + 1 ;
141141 do {
142142 if (* args .opt == 'h' )
143- usage (usagestr );
143+ usage_with_options (usagestr , options );
144144 if (parse_short_opt (& args , options ) < 0 )
145- usage (usagestr );
145+ usage_with_options (usagestr , options );
146146 } while (args .opt );
147147 continue ;
148148 }
@@ -156,12 +156,75 @@ int parse_options(int argc, const char **argv, const struct option *options,
156156 }
157157
158158 if (!strcmp (arg + 2 , "help" ))
159- usage (usagestr );
159+ usage_with_options (usagestr , options );
160160 if (parse_long_opt (& args , arg + 2 , options ))
161- usage (usagestr );
161+ usage_with_options (usagestr , options );
162162 }
163163
164164 memmove (argv + j , args .argv , args .argc * sizeof (* argv ));
165165 argv [j + args .argc ] = NULL ;
166166 return j + args .argc ;
167167}
168+
169+ #define USAGE_OPTS_WIDTH 24
170+ #define USAGE_GAP 2
171+
172+ void usage_with_options (const char * const * usagestr ,
173+ const struct option * opts )
174+ {
175+ struct strbuf sb ;
176+
177+ strbuf_init (& sb , 4096 );
178+ strbuf_addstr (& sb , * usagestr );
179+ strbuf_addch (& sb , '\n' );
180+ while (* ++ usagestr )
181+ strbuf_addf (& sb , " %s\n" , * usagestr );
182+
183+ if (opts -> type != OPTION_GROUP )
184+ strbuf_addch (& sb , '\n' );
185+
186+ for (; opts -> type != OPTION_END ; opts ++ ) {
187+ size_t pos ;
188+ int pad ;
189+
190+ if (opts -> type == OPTION_GROUP ) {
191+ strbuf_addch (& sb , '\n' );
192+ if (* opts -> help )
193+ strbuf_addf (& sb , "%s\n" , opts -> help );
194+ continue ;
195+ }
196+
197+ pos = sb .len ;
198+ strbuf_addstr (& sb , " " );
199+ if (opts -> short_name )
200+ strbuf_addf (& sb , "-%c" , opts -> short_name );
201+ if (opts -> long_name && opts -> short_name )
202+ strbuf_addstr (& sb , ", " );
203+ if (opts -> long_name )
204+ strbuf_addf (& sb , "--%s" , opts -> long_name );
205+
206+ switch (opts -> type ) {
207+ case OPTION_INTEGER :
208+ strbuf_addstr (& sb , " <n>" );
209+ break ;
210+ case OPTION_STRING :
211+ if (opts -> argh )
212+ strbuf_addf (& sb , " <%s>" , opts -> argh );
213+ else
214+ strbuf_addstr (& sb , " ..." );
215+ break ;
216+ default :
217+ break ;
218+ }
219+
220+ pad = sb .len - pos ;
221+ if (pad <= USAGE_OPTS_WIDTH )
222+ pad = USAGE_OPTS_WIDTH - pad ;
223+ else {
224+ strbuf_addch (& sb , '\n' );
225+ pad = USAGE_OPTS_WIDTH ;
226+ }
227+ strbuf_addf (& sb , "%*s%s\n" , pad + USAGE_GAP , "" , opts -> help );
228+ }
229+ usage (sb .buf );
230+ }
0 commit comments