/* * Compare two sort list items, according to the sort specs. */ int list_coll_offset(struct sort_list_item **ss1, struct sort_list_item **ss2, size_t offset) { int ret; ret = key_coll(&((*ss1)->ka), &((*ss2)->ka), offset); if (debug_sort) { if (offset) printf("; offset=%d", (int) offset); bwsprintf(stdout, ((*ss1)->str), "; s1=<", ">"); bwsprintf(stdout, ((*ss2)->str), ", s2=<", ">"); printf("; cmp1=%d\n", ret); } if (ret) return (ret); if (!(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) { ret = top_level_str_coll(((*ss1)->str), ((*ss2)->str)); if (debug_sort) printf("; cmp2=%d\n", ret); } return (ret); }
/* * Implements random sort (-R). */ static int randomcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) { struct bwstring *s1, *s2; MD5_CTX ctx1, ctx2; char *b1, *b2; UNUSED_ARG(offset); s1 = kv1->k; s2 = kv2->k; if (debug_sort) { bwsprintf(stdout, s1, "; k1=<", ">"); bwsprintf(stdout, s2, ", k2=<", ">"); } if (s1 == s2) return (0); memcpy(&ctx1,&md5_ctx,sizeof(MD5_CTX)); memcpy(&ctx2,&md5_ctx,sizeof(MD5_CTX)); MD5Update(&ctx1, bwsrawdata(s1), bwsrawlen(s1)); MD5Update(&ctx2, bwsrawdata(s2), bwsrawlen(s2)); b1 = MD5End(&ctx1, NULL); b2 = MD5End(&ctx2, NULL); if (b1 == NULL) { if (b2 == NULL) return (0); else { sort_free(b2); return (-1); } } else if (b2 == NULL) { sort_free(b1); return (+1); } else { int cmp_res; cmp_res = strcmp(b1,b2); sort_free(b1); sort_free(b2); if (!cmp_res) cmp_res = bwscoll(s1, s2, 0); return (cmp_res); } }
/* * Implements month sort (-M). */ static int monthcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) { int val1, val2; bool key1_read, key2_read; val1 = val2 = 0; key1_read = key2_read = false; UNUSED_ARG(offset); if (debug_sort) { bwsprintf(stdout, kv1->k, "; k1=<", ">"); bwsprintf(stdout, kv2->k, "; k2=<", ">"); } if (kv1->hint->status == HS_UNINITIALIZED) { kv1->hint->v.Mh.m = bws_month_score(kv1->k); key1_read = true; kv1->hint->status = HS_INITIALIZED; } if (kv2->hint->status == HS_UNINITIALIZED) { kv2->hint->v.Mh.m = bws_month_score(kv2->k); key2_read = true; kv2->hint->status = HS_INITIALIZED; } if (kv1->hint->status == HS_INITIALIZED) { val1 = kv1->hint->v.Mh.m; key1_read = true; } if (kv2->hint->status == HS_INITIALIZED) { val2 = kv2->hint->v.Mh.m; key2_read = true; } if (!key1_read) val1 = bws_month_score(kv1->k); if (!key2_read) val2 = bws_month_score(kv2->k); if (val1 == val2) { return (0); } if (val1 < val2) return (-1); return (+1); }
/* * Implements string sort. */ static int wstrcoll(struct key_value *kv1, struct key_value *kv2, size_t offset) { if (debug_sort) { if (offset) printf("; offset=%d\n", (int) offset); bwsprintf(stdout, kv1->k, "; k1=<", ">"); printf("(%zu)", BWSLEN(kv1->k)); bwsprintf(stdout, kv2->k, ", k2=<", ">"); printf("(%zu)", BWSLEN(kv2->k)); } return (bwscoll(kv1->k, kv2->k, offset)); }
/* * Implements random sort (-R). */ static int randomcoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused) { struct bwstring *s1, *s2; MD5_CTX ctx1, ctx2; unsigned char hash1[MD5_DIGEST_LENGTH], hash2[MD5_DIGEST_LENGTH]; int cmp; s1 = kv1->k; s2 = kv2->k; if (debug_sort) { bwsprintf(stdout, s1, "; k1=<", ">"); bwsprintf(stdout, s2, ", k2=<", ">"); } if (s1 == s2) return (0); if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status == HS_INITIALIZED) { cmp = memcmp(kv1->hint->v.Rh.cached, kv2->hint->v.Rh.cached, sizeof(kv1->hint->v.Rh.cached)); if (cmp != 0) return (cmp); } memcpy(&ctx1, &md5_ctx, sizeof(MD5_CTX)); memcpy(&ctx2, &md5_ctx, sizeof(MD5_CTX)); MD5Update(&ctx1, bwsrawdata(s1), bwsrawlen(s1)); MD5Update(&ctx2, bwsrawdata(s2), bwsrawlen(s2)); MD5Final(hash1, &ctx1); MD5Final(hash2, &ctx2); if (kv1->hint->status == HS_UNINITIALIZED) randomcoll_init_hint(kv1, hash1); if (kv2->hint->status == HS_UNINITIALIZED) randomcoll_init_hint(kv2, hash2); return (memcmp(hash1, hash2, sizeof(hash1))); }
/* * Implements version sort (-V). */ static int versioncoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused) { struct bwstring *s1, *s2; s1 = kv1->k; s2 = kv2->k; if (debug_sort) { bwsprintf(stdout, s1, "; k1=<", ">"); bwsprintf(stdout, s2, ", k2=<", ">"); } if (s1 == s2) return (0); return (vcmp(s1, s2)); }
/* * Compare a string and a sort list item, according to the sort specs. */ int str_list_coll(struct bwstring *str1, struct sort_list_item **ss2) { struct keys_array *ka1; int ret = 0; ka1 = keys_array_alloc(); preproc(str1, ka1); sort_list_item_make_key(*ss2); if (debug_sort) { bwsprintf(stdout, str1, "; s1=<", ">"); bwsprintf(stdout, (*ss2)->str, ", s2=<", ">"); } ret = key_coll(ka1, &((*ss2)->ka), 0); if (debug_sort) printf("; cmp1=%d", ret); clean_keys_array(str1, ka1); sort_free(ka1); if ((ret == 0) && !(sort_opts_vals.sflag) && sort_opts_vals.complex_sort) { ret = top_level_str_coll(str1, ((*ss2)->str)); if (debug_sort) printf("; cmp2=%d", ret); } if (debug_sort) printf("\n"); return (ret); }
/* * Implements numeric sort for -n and -h. */ static int numcoll_impl(struct key_value *kv1, struct key_value *kv2, size_t offset __unused, bool use_suffix) { struct bwstring *s1, *s2; wchar_t sfrac1[MAX_NUM_SIZE + 1], sfrac2[MAX_NUM_SIZE + 1]; wchar_t smain1[MAX_NUM_SIZE + 1], smain2[MAX_NUM_SIZE + 1]; int cmp_res, sign1, sign2; size_t frac1, frac2, main1, main2; unsigned char SI1, SI2; bool e1, e2, key1_read, key2_read; s1 = kv1->k; s2 = kv2->k; sign1 = sign2 = 0; main1 = main2 = 0; frac1 = frac2 = 0; key1_read = key2_read = false; if (debug_sort) { bwsprintf(stdout, s1, "; k1=<", ">"); bwsprintf(stdout, s2, ", k2=<", ">"); } if (s1 == s2) return (0); if (kv1->hint->status == HS_UNINITIALIZED) { /* read the number from the string */ read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1); key1_read = true; kv1->hint->v.nh.n1 = wcstoull(smain1, NULL, 10); if(main1 < 1 && frac1 < 1) kv1->hint->v.nh.empty=true; kv1->hint->v.nh.si = SI1; kv1->hint->status = (kv1->hint->v.nh.n1 != ULLONG_MAX) ? HS_INITIALIZED : HS_ERROR; kv1->hint->v.nh.neg = (sign1 < 0) ? true : false; } if (kv2->hint->status == HS_UNINITIALIZED) { /* read the number from the string */ read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2,&SI2); key2_read = true; kv2->hint->v.nh.n1 = wcstoull(smain2, NULL, 10); if(main2 < 1 && frac2 < 1) kv2->hint->v.nh.empty=true; kv2->hint->v.nh.si = SI2; kv2->hint->status = (kv2->hint->v.nh.n1 != ULLONG_MAX) ? HS_INITIALIZED : HS_ERROR; kv2->hint->v.nh.neg = (sign2 < 0) ? true : false; } if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status == HS_INITIALIZED) { unsigned long long n1, n2; bool neg1, neg2; e1 = kv1->hint->v.nh.empty; e2 = kv2->hint->v.nh.empty; if (e1 && e2) return (0); neg1 = kv1->hint->v.nh.neg; neg2 = kv2->hint->v.nh.neg; if (neg1 && !neg2) return (-1); if (neg2 && !neg1) return (+1); if (e1) return (neg2 ? +1 : -1); else if (e2) return (neg1 ? -1 : +1); if (use_suffix) { cmp_res = cmpsuffix(kv1->hint->v.nh.si, kv2->hint->v.nh.si); if (cmp_res) return (neg1 ? -cmp_res : cmp_res); } n1 = kv1->hint->v.nh.n1; n2 = kv2->hint->v.nh.n1; if (n1 < n2) return (neg1 ? +1 : -1); else if (n1 > n2) return (neg1 ? -1 : +1); } /* read the numbers from the strings */ if (!key1_read) read_number(s1, &sign1, smain1, &main1, sfrac1, &frac1, &SI1); if (!key2_read) read_number(s2, &sign2, smain2, &main2, sfrac2, &frac2, &SI2); e1 = ((main1 + frac1) == 0); e2 = ((main2 + frac2) == 0); if (e1 && e2) return (0); /* we know the result if the signs are different */ if (sign1 < 0 && sign2 >= 0) return (-1); if (sign1 >= 0 && sign2 < 0) return (+1); if (e1) return ((sign2 < 0) ? +1 : -1); else if (e2) return ((sign1 < 0) ? -1 : +1); if (use_suffix) { cmp_res = cmpsuffix(SI1, SI2); if (cmp_res) return ((sign1 < 0) ? -cmp_res : cmp_res); } /* if both numbers are empty assume that the strings are equal */ if (main1 < 1 && main2 < 1 && frac1 < 1 && frac2 < 1) return (0); /* * if the main part is of different size, we know the result * (because the leading zeros are removed) */ if (main1 < main2) cmp_res = -1; else if (main1 > main2) cmp_res = +1; /* if the sizes are equal then simple non-collate string compare gives the correct result */ else cmp_res = wcscmp(smain1, smain2); /* check fraction */ if (!cmp_res) cmp_res = wcscmp(sfrac1, sfrac2); if (!cmp_res) return (0); /* reverse result if the signs are negative */ if (sign1 < 0 && sign2 < 0) cmp_res = -cmp_res; return (cmp_res); }
/* * Implements general numeric sort (-g). */ static int gnumcoll(struct key_value *kv1, struct key_value *kv2, size_t offset __unused) { double d1, d2; int err1, err2; bool empty1, empty2, key1_read, key2_read; d1 = d2 = 0; err1 = err2 = 0; key1_read = key2_read = false; if (debug_sort) { bwsprintf(stdout, kv1->k, "; k1=<", ">"); bwsprintf(stdout, kv2->k, "; k2=<", ">"); } if (kv1->hint->status == HS_UNINITIALIZED) { errno = 0; d1 = bwstod(kv1->k, &empty1); err1 = errno; if (empty1) kv1->hint->v.gh.notnum = true; else if (err1 == 0) { kv1->hint->v.gh.d = d1; kv1->hint->v.gh.nan = is_nan(d1); kv1->hint->status = HS_INITIALIZED; } else kv1->hint->status = HS_ERROR; key1_read = true; } if (kv2->hint->status == HS_UNINITIALIZED) { errno = 0; d2 = bwstod(kv2->k, &empty2); err2 = errno; if (empty2) kv2->hint->v.gh.notnum = true; else if (err2 == 0) { kv2->hint->v.gh.d = d2; kv2->hint->v.gh.nan = is_nan(d2); kv2->hint->status = HS_INITIALIZED; } else kv2->hint->status = HS_ERROR; key2_read = true; } if (kv1->hint->status == HS_INITIALIZED && kv2->hint->status == HS_INITIALIZED) { if (kv1->hint->v.gh.notnum) return ((kv2->hint->v.gh.notnum) ? 0 : -1); else if (kv2->hint->v.gh.notnum) return (+1); if (kv1->hint->v.gh.nan) return ((kv2->hint->v.gh.nan) ? cmp_nans(kv1->hint->v.gh.d, kv2->hint->v.gh.d) : -1); else if (kv2->hint->v.gh.nan) return (+1); d1 = kv1->hint->v.gh.d; d2 = kv2->hint->v.gh.d; if (d1 < d2) return (-1); else if (d1 > d2) return (+1); else return (0); } if (!key1_read) { errno = 0; d1 = bwstod(kv1->k, &empty1); err1 = errno; } if (!key2_read) { errno = 0; d2 = bwstod(kv2->k, &empty2); err2 = errno; } /* Non-value case: */ if (empty1) return (empty2 ? 0 : -1); else if (empty2) return (+1); /* NAN case */ if (is_nan(d1)) return (is_nan(d2) ? cmp_nans(d1, d2) : -1); else if (is_nan(d2)) return (+1); /* Infinities */ if (err1 == ERANGE || err2 == ERANGE) { /* Minus infinity case */ if (huge_minus(d1, err1)) { if (huge_minus(d2, err2)) { if (d1 < d2) return (-1); if (d1 > d2) return (+1); return (0); } else return (-1); } else if (huge_minus(d2, err2)) { if (huge_minus(d1, err1)) { if (d1 < d2) return (-1); if (d1 > d2) return (+1); return (0); } else return (+1); } /* Plus infinity case */ if (huge_plus(d1, err1)) { if (huge_plus(d2, err2)) { if (d1 < d2) return (-1); if (d1 > d2) return (+1); return (0); } else return (+1); } else if (huge_plus(d2, err2)) { if (huge_plus(d1, err1)) { if (d1 < d2) return (-1); if (d1 > d2) return (+1); return (0); } else return (-1); } } if (d1 < d2) return (-1); if (d1 > d2) return (+1); return (0); }