/* * Parse a sequence into an array of sorted & merged ranges. */ EXPORTED struct seqset *seqset_parse(const char *sequence, struct seqset *set, unsigned maxval) { unsigned start = 0, end = 0; /* short circuit no sequence */ if (!sequence) return NULL; if (!set) set = seqset_init(maxval, SEQ_SPARSE); while (*sequence) { if (read_num(&sequence, maxval, &start)) fatal("invalid sequence", EC_SOFTWARE); if (*sequence == ':') { sequence++; if (read_num(&sequence, maxval, &end)) fatal("invalid sequence", EC_SOFTWARE); } else end = start; if (start > end) { unsigned i = end; end = start; start = i; } if (set->len == set->alloc) { set->alloc += SETGROWSIZE; set->set = xrealloc(set->set, set->alloc * sizeof(struct seq_range)); } set->set[set->len].low = start; set->set[set->len].high = end; set->len++; if (*sequence == ',') sequence++; /* could test for invalid chars here, but the number parser next * time through will grab them, so no need */ } seqset_simplify(set); return set; }
int main(int argc, char *argv[]) { const char *alt_config = NULL; unsigned maxval = 0; int flags = SEQ_MERGE; struct seqset *seq = NULL; int opt; unsigned num; char *res; const char *origlist = NULL; while ((opt = getopt(argc, argv, "C:m:o:s")) != EOF) { switch (opt) { case 'C': /* alt config file */ alt_config = optarg; break; case 'm': /* maxval */ parseuint32(optarg, NULL, &maxval); break; case 'o': origlist = optarg; break; case 's': flags = SEQ_SPARSE; } } if ((argc - optind) < 1) usage(argv[0]); cyrus_init(alt_config, "cyr_sequence", 0); /* special case */ if (!strcmp(argv[optind], "create")) { int i; seq = seqset_init(maxval, flags); for (i = optind + 1; i < argc; i++) { char *ptr = argv[i]; int isadd = 1; if (*ptr == '~') { isadd = 0; ptr++; } if (parseuint32(ptr, NULL, &num)) printf("%s NAN\n", argv[i]); else seqset_add(seq, num, isadd); } if (origlist) { unsigned oldmax = seq_lastnum(origlist, NULL); if (oldmax > maxval) { struct seqset *origseq = seqset_parse(origlist, NULL, oldmax); unsigned val; for (val = maxval + 1; val <= oldmax; val++) seqset_add(seq, val, seqset_ismember(origseq, val)); seqset_free(origseq); } } res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "parsed")) { unsigned i; seq = seqset_parse(argv[optind+1], NULL, maxval); printf("Sections: " SIZE_T_FMT "\n", seq->len); for (i = 0; i < seq->len; i++) { if (seq->set[i].high == UINT_MAX) printf(" [%u, *]\n", seq->set[i].low); else printf(" [%u, %u]\n", seq->set[i].low, seq->set[i].high); } } else if (!strcmp(argv[optind], "compress")) { seq = seqset_parse(argv[optind+1], NULL, maxval); res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "members")) { seq = seqset_parse(argv[optind+1], NULL, maxval); while ((num = seqset_getnext(seq))) { printf("%u\n", num); } } else if (!strcmp(argv[optind], "join")) { struct seqset *seq2; seq = seqset_parse(argv[optind+1], NULL, maxval); seq2 = seqset_parse(argv[optind+2], NULL, maxval); seqset_join(seq, seq2); res = seqset_cstring(seq); printf("%s\n", res); free(res); } else if (!strcmp(argv[optind], "ismember")) { int i; seq = seqset_parse(argv[optind+1], NULL, maxval); for (i = optind + 2; i < argc; i++) { if (parseuint32(argv[i], NULL, &num)) printf("%s NAN\n", argv[i]); else printf("%d %s\n", num, seqset_ismember(seq, num) ? "Yes" : "No"); } } else { printf("Unknown command %s", argv[optind]); } seqset_free(seq); cyrus_done(); return 0; }