Mercurial > hg > dmlib
comparison src/dmargs.c @ 2400:01c6a5261962
Sync commandline argument help printing/handling changes from th-libs.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 12 Jan 2020 19:25:52 +0200 |
parents | c801995cbb13 |
children | 263093248f26 |
comparison
equal
deleted
inserted
replaced
2399:5d391c31ebc9 | 2400:01c6a5261962 |
---|---|
173 | 173 |
174 return optionsOK; | 174 return optionsOK; |
175 } | 175 } |
176 | 176 |
177 | 177 |
178 static void dmPad(FILE *outFile, int count) | 178 void dmPrintPad(FILE *fh, int count, const char och) |
179 { | 179 { |
180 while (count--) | 180 while (count--) |
181 fputc(' ', outFile); | 181 fputc(och, fh); |
182 } | 182 } |
183 | 183 |
184 | 184 |
185 static void dmPrintWrap(FILE *fh, const char *str, int spad, int rpad, int width) | 185 /** |
186 * Print given string indented in such a way that it is automatically | |
187 * line-wrapped as necessary, taking hard linefeeds into account as well. | |
188 * @param fh stdio file handle to output to | |
189 * @param str string to output | |
190 * @param spad starting pad/indent of the first line | |
191 * @param rpad how much to pad the other lines | |
192 * @param width total line width to wrap at | |
193 */ | |
194 void dmPrintWrap(FILE *fh, const char *str, | |
195 const int spad, int const rpad, const int width) | |
186 { | 196 { |
187 size_t pos = 0; | 197 size_t pos = 0; |
188 BOOL first = TRUE; | 198 BOOL first = TRUE; |
189 | 199 |
190 while (str[pos]) | 200 while (str[pos]) |
191 { | 201 { |
192 // Pre-pad line | 202 // Pre-pad line |
193 int linelen = first ? spad : rpad; | 203 int linelen = first ? spad : rpad; |
194 dmPad(fh, first ? 0 : rpad); | 204 dmPrintPad(fh, first ? 0 : rpad, ' '); |
195 first = FALSE; | 205 first = FALSE; |
196 | 206 |
197 // Skip whitespace at line start | 207 // Skip whitespace at line start |
198 while (isspace(str[pos]) || str[pos] == '\n') pos++; | 208 while (isspace(str[pos]) || str[pos] == '\n') |
209 pos++; | |
199 | 210 |
200 // Handle each word | 211 // Handle each word |
201 while (str[pos] && str[pos] != '\n') | 212 while (str[pos] && str[pos] != '\n') |
202 { | 213 { |
203 size_t next; | 214 size_t next; |
204 int wlen; | 215 int wlen; |
205 for (wlen = 0, next = pos; str[next] && !isspace(str[next]) && str[next] != '\n'; next++, wlen++); | 216 |
206 // fprintf(stdout, "X '%c', %d .. linelen=%d/%d, wlen=%d\n", str[pos], pos, linelen, width, wlen); | 217 // Find word length and next break |
207 if (linelen + wlen < width) | 218 for (wlen = 0, next = pos; |
208 { | 219 str[next] && !isspace(str[next]) && |
209 for (;pos < next; pos++, linelen++) | 220 str[next] != '\n'; |
210 fputc(str[pos], fh); | 221 next++, wlen++); |
211 | 222 |
212 if (str[next] == '\n' || str[next] == 0) | 223 // Check if we have too much of text? |
213 { | 224 if (linelen + wlen >= width) |
214 fprintf(fh, "\n"); | 225 break; |
215 break; | 226 |
216 } | 227 // Print what we have |
217 else | 228 for (;pos < next; pos++, linelen++) |
218 { | 229 fputc(str[pos], fh); |
219 fputc(str[pos], fh); | 230 |
220 pos++; | 231 // Check if we are at end of input or hard linefeed |
221 linelen++; | 232 if (str[next] == '\n' || str[next] == 0) |
222 } | 233 break; |
223 } | |
224 else | 234 else |
225 { | 235 { |
226 fprintf(fh, "\n"); | 236 fputc(str[pos], fh); |
227 break; | 237 pos++; |
228 } | 238 linelen++; |
229 } | 239 } |
240 } | |
241 fprintf(fh, "\n"); | |
242 } | |
243 } | |
244 | |
245 | |
246 static inline const char *dmArgsGetOptArg(const DMOptArg *opt) | |
247 { | |
248 #ifdef DM_USE_OPT_ARG | |
249 return opt->o_arg != NULL ? opt->o_arg : "ARG"; | |
250 #else | |
251 (void) opt; | |
252 return "ARG"; | |
253 #endif | |
254 } | |
255 | |
256 | |
257 static void dmArgsPrintHelpPrintItem(FILE *fh, const DMOptArg *opt, int *lineWidth, const int maxLineWidth, const BOOL doPrint) | |
258 { | |
259 const char *arg = dmArgsGetOptArg(opt); | |
260 char fmtBuf[32]; | |
261 int padWidth; | |
262 BOOL hasLongOpt = opt->o_long != NULL; | |
263 | |
264 if (opt->o_short != 0) | |
265 { | |
266 if (!hasLongOpt && (opt->flags & OPT_ARGREQ)) | |
267 { | |
268 snprintf(fmtBuf, sizeof(fmtBuf), " -%c <%s>", | |
269 opt->o_short, arg); | |
270 } | |
271 else | |
272 { | |
273 snprintf(fmtBuf, sizeof(fmtBuf), " -%c,", | |
274 opt->o_short); | |
275 } | |
276 | |
277 *lineWidth = strlen(fmtBuf); | |
278 if (doPrint) | |
279 padWidth = hasLongOpt ? 2 : maxLineWidth - *lineWidth; | |
280 else | |
281 padWidth = 2; | |
282 } | |
283 else | |
284 { | |
285 fmtBuf[0] = 0; | |
286 *lineWidth = 0; | |
287 padWidth = 4 + 2; | |
288 } | |
289 | |
290 if (doPrint) | |
291 { | |
292 fputs(fmtBuf, fh); | |
293 dmPrintPad(fh, padWidth, ' '); | |
294 } | |
295 *lineWidth += padWidth; | |
296 | |
297 if (hasLongOpt) | |
298 { | |
299 if (opt->flags & OPT_ARGREQ) | |
300 { | |
301 snprintf(fmtBuf, sizeof(fmtBuf), "--%s=<%s>", | |
302 opt->o_long, arg); | |
303 } | |
304 else | |
305 { | |
306 snprintf(fmtBuf, sizeof(fmtBuf), "--%s", | |
307 opt->o_long); | |
308 } | |
309 | |
310 *lineWidth += strlen(fmtBuf); | |
311 } | |
312 else | |
313 fmtBuf[0] = 0; | |
314 | |
315 if (doPrint) | |
316 { | |
317 padWidth = hasLongOpt ? maxLineWidth - *lineWidth : 0; | |
318 *lineWidth += padWidth; | |
319 | |
320 fputs(fmtBuf, fh); | |
321 dmPrintPad(fh, padWidth, ' '); | |
322 dmPrintWrap(fh, opt->desc, *lineWidth, *lineWidth, 79); | |
230 } | 323 } |
231 } | 324 } |
232 | 325 |
233 | 326 |
234 /** | 327 /** |
236 * @param fh stdio file handle to output to | 329 * @param fh stdio file handle to output to |
237 * @param opts options list array | 330 * @param opts options list array |
238 * @param nopts number of elements in options list array | 331 * @param nopts number of elements in options list array |
239 * @param flags flags (currently unused) | 332 * @param flags flags (currently unused) |
240 */ | 333 */ |
241 void dmArgsPrintHelp(FILE *fh, | 334 void dmArgsPrintHelp(FILE *fh, const DMOptArg *opts, |
242 const DMOptArg *opts, const int nopts, | 335 const int nopts, const int flags) |
243 const int flags) | 336 { |
244 { | 337 int index, maxLineWidth; |
245 int index; | 338 |
246 (void) flags; | 339 (void) flags; |
247 | 340 |
248 // Print out option list | 341 // Determine width of the options and arguments |
342 maxLineWidth = 0; | |
249 for (index = 0; index < nopts; index++) | 343 for (index = 0; index < nopts; index++) |
250 { | 344 { |
251 const DMOptArg *opt = &opts[index]; | 345 int lineWidth = 0; |
252 char tmpStr[128]; | 346 dmArgsPrintHelpPrintItem(NULL, &opts[index], &lineWidth, 0, FALSE); |
253 | 347 if (lineWidth > maxLineWidth) |
254 // Print short option | 348 maxLineWidth = lineWidth; |
255 if (opt->o_short != 0) | 349 } |
256 { | 350 |
257 snprintf(tmpStr, sizeof(tmpStr), | 351 maxLineWidth += 2; |
258 "-%c,", opt->o_short); | 352 |
259 } | 353 // Print out the formatted option list |
260 else | 354 for (index = 0; index < nopts; index++) |
261 tmpStr[0] = 0; | 355 { |
262 | 356 int lineWidth; |
263 fprintf(fh, " %-5s", tmpStr); | 357 dmArgsPrintHelpPrintItem(fh, &opts[index], &lineWidth, maxLineWidth, TRUE); |
264 | 358 } |
265 // Print long option | 359 } |
266 if (opt->o_long != NULL) | |
267 { | |
268 snprintf(tmpStr, sizeof(tmpStr), "--%s%s", | |
269 opt->o_long, | |
270 (opt->flags & OPT_ARGREQ) ? "=ARG" : ""); | |
271 } | |
272 else | |
273 tmpStr[0] = 0; | |
274 | |
275 fprintf(fh, "%-18s", tmpStr); | |
276 | |
277 dmPrintWrap(fh, opt->desc, 24, 24, 79); | |
278 } | |
279 } |