parse-options.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. #include "util.h"
  2. #include "parse-options.h"
  3. #include "cache.h"
  4. #include "header.h"
  5. #define OPT_SHORT 1
  6. #define OPT_UNSET 2
  7. static int opterror(const struct option *opt, const char *reason, int flags)
  8. {
  9. if (flags & OPT_SHORT)
  10. return error("switch `%c' %s", opt->short_name, reason);
  11. if (flags & OPT_UNSET)
  12. return error("option `no-%s' %s", opt->long_name, reason);
  13. return error("option `%s' %s", opt->long_name, reason);
  14. }
  15. static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
  16. int flags, const char **arg)
  17. {
  18. if (p->opt) {
  19. *arg = p->opt;
  20. p->opt = NULL;
  21. } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
  22. **(p->argv + 1) == '-')) {
  23. *arg = (const char *)opt->defval;
  24. } else if (p->argc > 1) {
  25. p->argc--;
  26. *arg = *++p->argv;
  27. } else
  28. return opterror(opt, "requires a value", flags);
  29. return 0;
  30. }
  31. static int get_value(struct parse_opt_ctx_t *p,
  32. const struct option *opt, int flags)
  33. {
  34. const char *s, *arg = NULL;
  35. const int unset = flags & OPT_UNSET;
  36. if (unset && p->opt)
  37. return opterror(opt, "takes no value", flags);
  38. if (unset && (opt->flags & PARSE_OPT_NONEG))
  39. return opterror(opt, "isn't available", flags);
  40. if (!(flags & OPT_SHORT) && p->opt) {
  41. switch (opt->type) {
  42. case OPTION_CALLBACK:
  43. if (!(opt->flags & PARSE_OPT_NOARG))
  44. break;
  45. /* FALLTHROUGH */
  46. case OPTION_BOOLEAN:
  47. case OPTION_INCR:
  48. case OPTION_BIT:
  49. case OPTION_SET_UINT:
  50. case OPTION_SET_PTR:
  51. return opterror(opt, "takes no value", flags);
  52. case OPTION_END:
  53. case OPTION_ARGUMENT:
  54. case OPTION_GROUP:
  55. case OPTION_STRING:
  56. case OPTION_INTEGER:
  57. case OPTION_UINTEGER:
  58. case OPTION_LONG:
  59. case OPTION_U64:
  60. default:
  61. break;
  62. }
  63. }
  64. switch (opt->type) {
  65. case OPTION_BIT:
  66. if (unset)
  67. *(int *)opt->value &= ~opt->defval;
  68. else
  69. *(int *)opt->value |= opt->defval;
  70. return 0;
  71. case OPTION_BOOLEAN:
  72. *(bool *)opt->value = unset ? false : true;
  73. if (opt->set)
  74. *(bool *)opt->set = true;
  75. return 0;
  76. case OPTION_INCR:
  77. *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
  78. return 0;
  79. case OPTION_SET_UINT:
  80. *(unsigned int *)opt->value = unset ? 0 : opt->defval;
  81. return 0;
  82. case OPTION_SET_PTR:
  83. *(void **)opt->value = unset ? NULL : (void *)opt->defval;
  84. return 0;
  85. case OPTION_STRING:
  86. if (unset)
  87. *(const char **)opt->value = NULL;
  88. else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
  89. *(const char **)opt->value = (const char *)opt->defval;
  90. else
  91. return get_arg(p, opt, flags, (const char **)opt->value);
  92. return 0;
  93. case OPTION_CALLBACK:
  94. if (unset)
  95. return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
  96. if (opt->flags & PARSE_OPT_NOARG)
  97. return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
  98. if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
  99. return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
  100. if (get_arg(p, opt, flags, &arg))
  101. return -1;
  102. return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
  103. case OPTION_INTEGER:
  104. if (unset) {
  105. *(int *)opt->value = 0;
  106. return 0;
  107. }
  108. if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
  109. *(int *)opt->value = opt->defval;
  110. return 0;
  111. }
  112. if (get_arg(p, opt, flags, &arg))
  113. return -1;
  114. *(int *)opt->value = strtol(arg, (char **)&s, 10);
  115. if (*s)
  116. return opterror(opt, "expects a numerical value", flags);
  117. return 0;
  118. case OPTION_UINTEGER:
  119. if (unset) {
  120. *(unsigned int *)opt->value = 0;
  121. return 0;
  122. }
  123. if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
  124. *(unsigned int *)opt->value = opt->defval;
  125. return 0;
  126. }
  127. if (get_arg(p, opt, flags, &arg))
  128. return -1;
  129. *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
  130. if (*s)
  131. return opterror(opt, "expects a numerical value", flags);
  132. return 0;
  133. case OPTION_LONG:
  134. if (unset) {
  135. *(long *)opt->value = 0;
  136. return 0;
  137. }
  138. if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
  139. *(long *)opt->value = opt->defval;
  140. return 0;
  141. }
  142. if (get_arg(p, opt, flags, &arg))
  143. return -1;
  144. *(long *)opt->value = strtol(arg, (char **)&s, 10);
  145. if (*s)
  146. return opterror(opt, "expects a numerical value", flags);
  147. return 0;
  148. case OPTION_U64:
  149. if (unset) {
  150. *(u64 *)opt->value = 0;
  151. return 0;
  152. }
  153. if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
  154. *(u64 *)opt->value = opt->defval;
  155. return 0;
  156. }
  157. if (get_arg(p, opt, flags, &arg))
  158. return -1;
  159. *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
  160. if (*s)
  161. return opterror(opt, "expects a numerical value", flags);
  162. return 0;
  163. case OPTION_END:
  164. case OPTION_ARGUMENT:
  165. case OPTION_GROUP:
  166. default:
  167. die("should not happen, someone must be hit on the forehead");
  168. }
  169. }
  170. static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
  171. {
  172. for (; options->type != OPTION_END; options++) {
  173. if (options->short_name == *p->opt) {
  174. p->opt = p->opt[1] ? p->opt + 1 : NULL;
  175. return get_value(p, options, OPT_SHORT);
  176. }
  177. }
  178. return -2;
  179. }
  180. static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
  181. const struct option *options)
  182. {
  183. const char *arg_end = strchr(arg, '=');
  184. const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
  185. int abbrev_flags = 0, ambiguous_flags = 0;
  186. if (!arg_end)
  187. arg_end = arg + strlen(arg);
  188. for (; options->type != OPTION_END; options++) {
  189. const char *rest;
  190. int flags = 0;
  191. if (!options->long_name)
  192. continue;
  193. rest = skip_prefix(arg, options->long_name);
  194. if (options->type == OPTION_ARGUMENT) {
  195. if (!rest)
  196. continue;
  197. if (*rest == '=')
  198. return opterror(options, "takes no value", flags);
  199. if (*rest)
  200. continue;
  201. p->out[p->cpidx++] = arg - 2;
  202. return 0;
  203. }
  204. if (!rest) {
  205. if (!prefixcmp(options->long_name, "no-")) {
  206. /*
  207. * The long name itself starts with "no-", so
  208. * accept the option without "no-" so that users
  209. * do not have to enter "no-no-" to get the
  210. * negation.
  211. */
  212. rest = skip_prefix(arg, options->long_name + 3);
  213. if (rest) {
  214. flags |= OPT_UNSET;
  215. goto match;
  216. }
  217. /* Abbreviated case */
  218. if (!prefixcmp(options->long_name + 3, arg)) {
  219. flags |= OPT_UNSET;
  220. goto is_abbreviated;
  221. }
  222. }
  223. /* abbreviated? */
  224. if (!strncmp(options->long_name, arg, arg_end - arg)) {
  225. is_abbreviated:
  226. if (abbrev_option) {
  227. /*
  228. * If this is abbreviated, it is
  229. * ambiguous. So when there is no
  230. * exact match later, we need to
  231. * error out.
  232. */
  233. ambiguous_option = abbrev_option;
  234. ambiguous_flags = abbrev_flags;
  235. }
  236. if (!(flags & OPT_UNSET) && *arg_end)
  237. p->opt = arg_end + 1;
  238. abbrev_option = options;
  239. abbrev_flags = flags;
  240. continue;
  241. }
  242. /* negated and abbreviated very much? */
  243. if (!prefixcmp("no-", arg)) {
  244. flags |= OPT_UNSET;
  245. goto is_abbreviated;
  246. }
  247. /* negated? */
  248. if (strncmp(arg, "no-", 3))
  249. continue;
  250. flags |= OPT_UNSET;
  251. rest = skip_prefix(arg + 3, options->long_name);
  252. /* abbreviated and negated? */
  253. if (!rest && !prefixcmp(options->long_name, arg + 3))
  254. goto is_abbreviated;
  255. if (!rest)
  256. continue;
  257. }
  258. match:
  259. if (*rest) {
  260. if (*rest != '=')
  261. continue;
  262. p->opt = rest + 1;
  263. }
  264. return get_value(p, options, flags);
  265. }
  266. if (ambiguous_option)
  267. return error("Ambiguous option: %s "
  268. "(could be --%s%s or --%s%s)",
  269. arg,
  270. (ambiguous_flags & OPT_UNSET) ? "no-" : "",
  271. ambiguous_option->long_name,
  272. (abbrev_flags & OPT_UNSET) ? "no-" : "",
  273. abbrev_option->long_name);
  274. if (abbrev_option)
  275. return get_value(p, abbrev_option, abbrev_flags);
  276. return -2;
  277. }
  278. static void check_typos(const char *arg, const struct option *options)
  279. {
  280. if (strlen(arg) < 3)
  281. return;
  282. if (!prefixcmp(arg, "no-")) {
  283. error ("did you mean `--%s` (with two dashes ?)", arg);
  284. exit(129);
  285. }
  286. for (; options->type != OPTION_END; options++) {
  287. if (!options->long_name)
  288. continue;
  289. if (!prefixcmp(options->long_name, arg)) {
  290. error ("did you mean `--%s` (with two dashes ?)", arg);
  291. exit(129);
  292. }
  293. }
  294. }
  295. void parse_options_start(struct parse_opt_ctx_t *ctx,
  296. int argc, const char **argv, int flags)
  297. {
  298. memset(ctx, 0, sizeof(*ctx));
  299. ctx->argc = argc - 1;
  300. ctx->argv = argv + 1;
  301. ctx->out = argv;
  302. ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
  303. ctx->flags = flags;
  304. if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
  305. (flags & PARSE_OPT_STOP_AT_NON_OPTION))
  306. die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
  307. }
  308. static int usage_with_options_internal(const char * const *,
  309. const struct option *, int);
  310. int parse_options_step(struct parse_opt_ctx_t *ctx,
  311. const struct option *options,
  312. const char * const usagestr[])
  313. {
  314. int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
  315. /* we must reset ->opt, unknown short option leave it dangling */
  316. ctx->opt = NULL;
  317. for (; ctx->argc; ctx->argc--, ctx->argv++) {
  318. const char *arg = ctx->argv[0];
  319. if (*arg != '-' || !arg[1]) {
  320. if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
  321. break;
  322. ctx->out[ctx->cpidx++] = ctx->argv[0];
  323. continue;
  324. }
  325. if (arg[1] != '-') {
  326. ctx->opt = arg + 1;
  327. if (internal_help && *ctx->opt == 'h')
  328. return usage_with_options_internal(usagestr, options, 0);
  329. switch (parse_short_opt(ctx, options)) {
  330. case -1:
  331. return parse_options_usage(usagestr, options, arg + 1, 1);
  332. case -2:
  333. goto unknown;
  334. default:
  335. break;
  336. }
  337. if (ctx->opt)
  338. check_typos(arg + 1, options);
  339. while (ctx->opt) {
  340. if (internal_help && *ctx->opt == 'h')
  341. return usage_with_options_internal(usagestr, options, 0);
  342. arg = ctx->opt;
  343. switch (parse_short_opt(ctx, options)) {
  344. case -1:
  345. return parse_options_usage(usagestr, options, arg, 1);
  346. case -2:
  347. /* fake a short option thing to hide the fact that we may have
  348. * started to parse aggregated stuff
  349. *
  350. * This is leaky, too bad.
  351. */
  352. ctx->argv[0] = strdup(ctx->opt - 1);
  353. *(char *)ctx->argv[0] = '-';
  354. goto unknown;
  355. default:
  356. break;
  357. }
  358. }
  359. continue;
  360. }
  361. if (!arg[2]) { /* "--" */
  362. if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
  363. ctx->argc--;
  364. ctx->argv++;
  365. }
  366. break;
  367. }
  368. if (internal_help && !strcmp(arg + 2, "help-all"))
  369. return usage_with_options_internal(usagestr, options, 1);
  370. if (internal_help && !strcmp(arg + 2, "help"))
  371. return usage_with_options_internal(usagestr, options, 0);
  372. if (!strcmp(arg + 2, "list-opts"))
  373. return PARSE_OPT_LIST_OPTS;
  374. if (!strcmp(arg + 2, "list-cmds"))
  375. return PARSE_OPT_LIST_SUBCMDS;
  376. switch (parse_long_opt(ctx, arg + 2, options)) {
  377. case -1:
  378. return parse_options_usage(usagestr, options, arg + 2, 0);
  379. case -2:
  380. goto unknown;
  381. default:
  382. break;
  383. }
  384. continue;
  385. unknown:
  386. if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
  387. return PARSE_OPT_UNKNOWN;
  388. ctx->out[ctx->cpidx++] = ctx->argv[0];
  389. ctx->opt = NULL;
  390. }
  391. return PARSE_OPT_DONE;
  392. }
  393. int parse_options_end(struct parse_opt_ctx_t *ctx)
  394. {
  395. memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
  396. ctx->out[ctx->cpidx + ctx->argc] = NULL;
  397. return ctx->cpidx + ctx->argc;
  398. }
  399. int parse_options_subcommand(int argc, const char **argv, const struct option *options,
  400. const char *const subcommands[], const char *usagestr[], int flags)
  401. {
  402. struct parse_opt_ctx_t ctx;
  403. perf_header__set_cmdline(argc, argv);
  404. /* build usage string if it's not provided */
  405. if (subcommands && !usagestr[0]) {
  406. struct strbuf buf = STRBUF_INIT;
  407. strbuf_addf(&buf, "perf %s [<options>] {", argv[0]);
  408. for (int i = 0; subcommands[i]; i++) {
  409. if (i)
  410. strbuf_addstr(&buf, "|");
  411. strbuf_addstr(&buf, subcommands[i]);
  412. }
  413. strbuf_addstr(&buf, "}");
  414. usagestr[0] = strdup(buf.buf);
  415. strbuf_release(&buf);
  416. }
  417. parse_options_start(&ctx, argc, argv, flags);
  418. switch (parse_options_step(&ctx, options, usagestr)) {
  419. case PARSE_OPT_HELP:
  420. exit(129);
  421. case PARSE_OPT_DONE:
  422. break;
  423. case PARSE_OPT_LIST_OPTS:
  424. while (options->type != OPTION_END) {
  425. printf("--%s ", options->long_name);
  426. options++;
  427. }
  428. exit(130);
  429. case PARSE_OPT_LIST_SUBCMDS:
  430. for (int i = 0; subcommands[i]; i++)
  431. printf("%s ", subcommands[i]);
  432. exit(130);
  433. default: /* PARSE_OPT_UNKNOWN */
  434. if (ctx.argv[0][1] == '-') {
  435. error("unknown option `%s'", ctx.argv[0] + 2);
  436. } else {
  437. error("unknown switch `%c'", *ctx.opt);
  438. }
  439. usage_with_options(usagestr, options);
  440. }
  441. return parse_options_end(&ctx);
  442. }
  443. int parse_options(int argc, const char **argv, const struct option *options,
  444. const char * const usagestr[], int flags)
  445. {
  446. return parse_options_subcommand(argc, argv, options, NULL,
  447. (const char **) usagestr, flags);
  448. }
  449. #define USAGE_OPTS_WIDTH 24
  450. #define USAGE_GAP 2
  451. static void print_option_help(const struct option *opts, int full)
  452. {
  453. size_t pos;
  454. int pad;
  455. if (opts->type == OPTION_GROUP) {
  456. fputc('\n', stderr);
  457. if (*opts->help)
  458. fprintf(stderr, "%s\n", opts->help);
  459. return;
  460. }
  461. if (!full && (opts->flags & PARSE_OPT_HIDDEN))
  462. return;
  463. pos = fprintf(stderr, " ");
  464. if (opts->short_name)
  465. pos += fprintf(stderr, "-%c", opts->short_name);
  466. else
  467. pos += fprintf(stderr, " ");
  468. if (opts->long_name && opts->short_name)
  469. pos += fprintf(stderr, ", ");
  470. if (opts->long_name)
  471. pos += fprintf(stderr, "--%s", opts->long_name);
  472. switch (opts->type) {
  473. case OPTION_ARGUMENT:
  474. break;
  475. case OPTION_LONG:
  476. case OPTION_U64:
  477. case OPTION_INTEGER:
  478. case OPTION_UINTEGER:
  479. if (opts->flags & PARSE_OPT_OPTARG)
  480. if (opts->long_name)
  481. pos += fprintf(stderr, "[=<n>]");
  482. else
  483. pos += fprintf(stderr, "[<n>]");
  484. else
  485. pos += fprintf(stderr, " <n>");
  486. break;
  487. case OPTION_CALLBACK:
  488. if (opts->flags & PARSE_OPT_NOARG)
  489. break;
  490. /* FALLTHROUGH */
  491. case OPTION_STRING:
  492. if (opts->argh) {
  493. if (opts->flags & PARSE_OPT_OPTARG)
  494. if (opts->long_name)
  495. pos += fprintf(stderr, "[=<%s>]", opts->argh);
  496. else
  497. pos += fprintf(stderr, "[<%s>]", opts->argh);
  498. else
  499. pos += fprintf(stderr, " <%s>", opts->argh);
  500. } else {
  501. if (opts->flags & PARSE_OPT_OPTARG)
  502. if (opts->long_name)
  503. pos += fprintf(stderr, "[=...]");
  504. else
  505. pos += fprintf(stderr, "[...]");
  506. else
  507. pos += fprintf(stderr, " ...");
  508. }
  509. break;
  510. default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
  511. case OPTION_END:
  512. case OPTION_GROUP:
  513. case OPTION_BIT:
  514. case OPTION_BOOLEAN:
  515. case OPTION_INCR:
  516. case OPTION_SET_UINT:
  517. case OPTION_SET_PTR:
  518. break;
  519. }
  520. if (pos <= USAGE_OPTS_WIDTH)
  521. pad = USAGE_OPTS_WIDTH - pos;
  522. else {
  523. fputc('\n', stderr);
  524. pad = USAGE_OPTS_WIDTH;
  525. }
  526. fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
  527. }
  528. int usage_with_options_internal(const char * const *usagestr,
  529. const struct option *opts, int full)
  530. {
  531. if (!usagestr)
  532. return PARSE_OPT_HELP;
  533. fprintf(stderr, "\n usage: %s\n", *usagestr++);
  534. while (*usagestr && **usagestr)
  535. fprintf(stderr, " or: %s\n", *usagestr++);
  536. while (*usagestr) {
  537. fprintf(stderr, "%s%s\n",
  538. **usagestr ? " " : "",
  539. *usagestr);
  540. usagestr++;
  541. }
  542. if (opts->type != OPTION_GROUP)
  543. fputc('\n', stderr);
  544. for ( ; opts->type != OPTION_END; opts++)
  545. print_option_help(opts, full);
  546. fputc('\n', stderr);
  547. return PARSE_OPT_HELP;
  548. }
  549. void usage_with_options(const char * const *usagestr,
  550. const struct option *opts)
  551. {
  552. exit_browser(false);
  553. usage_with_options_internal(usagestr, opts, 0);
  554. exit(129);
  555. }
  556. int parse_options_usage(const char * const *usagestr,
  557. const struct option *opts,
  558. const char *optstr, bool short_opt)
  559. {
  560. if (!usagestr)
  561. goto opt;
  562. fprintf(stderr, "\n usage: %s\n", *usagestr++);
  563. while (*usagestr && **usagestr)
  564. fprintf(stderr, " or: %s\n", *usagestr++);
  565. while (*usagestr) {
  566. fprintf(stderr, "%s%s\n",
  567. **usagestr ? " " : "",
  568. *usagestr);
  569. usagestr++;
  570. }
  571. fputc('\n', stderr);
  572. opt:
  573. for ( ; opts->type != OPTION_END; opts++) {
  574. if (short_opt) {
  575. if (opts->short_name == *optstr)
  576. break;
  577. continue;
  578. }
  579. if (opts->long_name == NULL)
  580. continue;
  581. if (!prefixcmp(optstr, opts->long_name))
  582. break;
  583. if (!prefixcmp(optstr, "no-") &&
  584. !prefixcmp(optstr + 3, opts->long_name))
  585. break;
  586. }
  587. if (opts->type != OPTION_END)
  588. print_option_help(opts, 0);
  589. return PARSE_OPT_HELP;
  590. }
  591. int parse_opt_verbosity_cb(const struct option *opt,
  592. const char *arg __maybe_unused,
  593. int unset)
  594. {
  595. int *target = opt->value;
  596. if (unset)
  597. /* --no-quiet, --no-verbose */
  598. *target = 0;
  599. else if (opt->short_name == 'v') {
  600. if (*target >= 0)
  601. (*target)++;
  602. else
  603. *target = 1;
  604. } else {
  605. if (*target <= 0)
  606. (*target)--;
  607. else
  608. *target = -1;
  609. }
  610. return 0;
  611. }