Here is an ACL-only, sorts on first column only, table sort package. I think
it is at least based on, if not totally lifted from, the experiment Clay
mentioned.
 package table_sort
function table_sort() {
 if (oid_xpath_boolean(oid_caret(),'ancestor::tbody')) {
  local chgtrk = option("changetracking")
  set changetracking = off;
  while (oid_name(oid_parent(oid_caret())) != 'tbody') {
   goto_oid(oid_parent(oid_caret()));
   }
  goto_oid(oid_parent(oid_caret()));
  if (oid_find_child_attrs(oid_caret(), morerowsarr, 'morerows')) {
    response('Tables with vertical spans can not be sorted.');
    set changetracking = $chgtrk;
    return;
   } # if
  rows = oid_find_children(oid_caret(), rowarr, "row");
  if ($rows > 0) {
   for (i = 1; i <= $rows; i++) {
    if (store_rows_arr[oid_content(oid_child($rowarr[$i],1))] == '') {
     store_rows_arr[oid_content(oid_child($rowarr[$i],1))] =
oid_content($rowarr[$i],0x1);
     sort_rows_arr[$i] = oid_content(oid_child($rowarr[$i],1));
     } # if
    else {
     tempkey = oid_content(oid_child($rowarr[$i],1)) . $i;
     store_rows_arr[$tempkey] = oid_content($rowarr[$i],0x1);
     sort_rows_arr[$i] = $tempkey;
     } # else
    } # for
   qsort(sort_rows_arr);
   for (i = 1; i <= count($sort_rows_arr); i++) {
    insert(store_rows_arr[$sort_rows_arr[$i]]);
    }
   for (i = 1; i <= $rows; i++) {
    oid_delete($rowarr[$i]);
    } # for
   message "$rows rows sorted.";
   beep;
   } # if
  else {
   response('No rows found to sort. Interesting. Let your administrator
know.');
   }
  delete(store_rows_arr);
  delete(sort_rows_arr);
  set changetracking = $chgtrk;
  } # if
 else {
  response('Place your cursor in the body (tbody) of the table or
informaltable to be sorted before attempting to Sort Table.');
  } # else
} # table_sort