Check-in by ben on 2024-09-29 18:39:15 When displaying a user's list of lists, sort by name and id. INSERTED DELETED 33 12 src/lists/index.dcgi.m4 45 0 src/util.awk 78 12 TOTAL over 2 changed files Index: src/lists/index.dcgi.m4 ================================================================== --- src/lists/index.dcgi.m4 +++ src/lists/index.dcgi.m4 @@ -8,37 +8,42 @@ include(src/config.awk) incl(src/api.awk) incl(src/cgi.awk) incl(src/util.awk) -function main( cmd, iaout, id, is_private, item_count, item_id, \ - label, name, url) +function main( cmd, count, fields, iaout, i, id, is_private, item, \ + item_count, item_id, label, name, record, records, url) { - print search "'s Lists" - print "" - iaout = gettemp() url = api_ssl_endpoint "/services/users/" search "/lists" api_request(url, "GET", iaout) # format list as a gopher directory (menu) cmd = sprintf("%s <%s 2>&1", cmd_json2tsv, iaout) FS = "\t" - name = "" + count = 0 + delete fields[0] id = 0 is_private = 0 + item = "" item_count = 0 item_id = "" + name = "" + record = "" + delete records[0] while ((cmd | getline) > 0) { if ($1 == ".value[]" && $2 == "o") { - # print information for previous list + # add information for previous list if (!is_private && length(name) > 0 && item_count > 0) { label = shorten_left(name, 50) - printf "[1|%4d Items: %-50s|%s/list/%%09%s/%d|%s|%s]\n", - item_count, label, cgipath, search, id, server, port + item = sprintf("[1|%4d Items: %-50s|%s/list/%%09%s/%d|%s|%s]", \ + item_count, label, cgipath, search, id, server, port) + record = label "\t" id "\t" item + count++ + records[count] = record } } else if ($1 == ".value[].list_name" && $2 == "s") { name = $3 id = 0 is_private = 0 @@ -53,15 +58,31 @@ item_count++ } } close(cmd) - # print information for previous list + # add information for previous list if (!is_private && length(name) > 0 && item_count > 0) { label = shorten_left(name, 50) - printf "[1|%4d Items: %-50s|%s/list/%%09%s/%d|%s|%s]\n", - item_count, label, cgipath, search, id, server, port + item = sprintf("[1|%4d Items: %-50s|%s/list/%%09%s/%d|%s|%s]", \ + item_count, label, cgipath, search, id, server, port) + record = label "\t" id "\t" item + count++ + records[count] = record + } + + # sort lists by label and id + hsort(records, count) + + print search "'s Lists" + print "" + + for (i = 1; i <= count; i++) { + record = records[i] + split(record, fields, /\t/) + item = fields[3] + print item } print "" printf "[1|PHAROS|%s|%s|%s]\n", cgipath, server, port Index: src/util.awk ================================================================== --- src/util.awk +++ src/util.awk @@ -51,10 +51,55 @@ print "Error: mktemp failed, no tmpfile" exit } return retval } + +# heapsort +# +# Unstable, and unlike merge and quicksort it relies on random-access +# so has poorer cache performance. +# +# Advantage over quicksort is that its worst-case same as avg: O(n log n) +# +# This presentation based on http://dada.perl.it/shootout/heapsort.lua5.html +# +# From: +# +# Requires 1-based numerically indexed arrays. + +function hsort(A, n, c, p, t, i) { + if (!n) { + n = 1 + while (n in A) n++ + n-- + } + i = int(n/2) + 1 + while (1) { + if (i > 1) { + i-- + t = A[i] + } else { + t = A[n] + A[n] = A[1] + n-- + if (n == 1) { + A[1] = t + return + } + } + for (p = i; (c = 2*p) <= n; p = c) { + if ((c < n) && (A[c] < A[c+1])) + c++ + if (t < A[c]) + A[p] = A[c] + else break + } + A[p] = t + } +} function human_size(bytes) { if (bytes > size_gb) { retval = sprintf("%.1fG", bytes / size_gb) } else if (bytes > size_mb) {