# ============================================================================== # array_select_entry.nm - Tony Balinski # # Array entry selection - this uses a number of helper functions to format the # array keys and content. # ============================================================================== # ------------------------------------------------------------------------------ # array_select_entry_flatten_str(s [, len [, quot]]): returns s with all # newlines changed to '/' and tabs and space sequences changed to ' '. If # the result is longer than len + 3, remove everything after len and add # "..."). If the quot parameter is passed, its first character will be # added at either end of the string, not included in the length count, # before any added "...". # ------------------------------------------------------------------------------ define array_select_entry_flatten_str { len = 0 quot = "" if ($n_args >= 2) len = $2 if ($n_args >= 3) quot = substring(replace_in_string($3, "\\s*", "", "regex", "copy"), 0, 1) s = replace_in_string($1, "\\s*\n\\s*", "/", "regex", "copy") s = replace_in_string(s, "\\s+", " ", "regex", "copy") slen = length(s) if (len == 0) len = slen if (slen > len + 3) s = quot substring(s, 0, len) quot "..." else if (slen > 0) s = quot s quot return s } # ------------------------------------------------------------------------------ # array_select_entry_longest_key(array, null): returns the longest key that will # be used to format the list_dialog() lines in array_select_entry(). # ------------------------------------------------------------------------------ define array_select_entry_longest_key { array = $1 null = $2 if (null == "") null = "\"\"" maxkey = "" maxlen = 0 for (key in array) { thekey = key if (key == "") thekey = null else if (!valid_number(key)) thekey = array_select_entry_flatten_str(key, 20, "\"") else thekey = key len = length(thekey) if (len >= maxlen) { maxlen = len maxkey = thekey } } return maxkey } # ------------------------------------------------------------------------------ # array_select_entry_neg_keys_to_string(array, startline, maxkeylenstr): makes # lines appropriate for list_dialog() displays in array_select_entry() for # keys in array which are negative numbers, ordered numerically. Each line # has a number, starting at startline, so that a line selected in # list_dialog() can be identified and its key found (see ["i_to_key"] # below). maxkeylenstr is the longest key value as returned by # array_select_entry_longest_key. Returns an array with the following # keys: # ["lines"] the string holding generated lines # ["next_i"] the line number for any following line # ["i_to_key"] an array of line number to key string values # ------------------------------------------------------------------------------ define array_select_entry_neg_keys_to_string { array = $1 startline = $2 maxkeylenstr = $3 ks = $empty_array ksi = $empty_array keyi = $empty_array lines = "" sep = "" nkeys = array[] for (key in array) { if (valid_number(key) && \ search_string(key, "\\s", 0, "regex") < 0 && \ key < 0) { skey = rjust_to_slen(key, maxkeylenstr) ks[skey] = key } } n = ks[] i = 0 for (skey in ks) { ++i ksi[n - i] = skey } for (i = 0; i < n; i++) { skey = ksi[i] key = ks[skey] keyi[i + startline] = key val = array[key] sval = array_select_entry_flatten_str(val, 50, "\"") lines = lines sep "" rjust_to_slen(i + startline, nkeys) \ ": " skey " -> " sval sep = "\n" } return make_array("lines", lines, \ "next_i", i + startline, \ "i_to_key", keyi) } # ------------------------------------------------------------------------------ # array_select_entry_pos_keys_to_string(array, startline, maxkeylenstr): makes # lines appropriate for list_dialog() displays in array_select_entry() for # keys in array which are non-negative numbers, ordered numerically. Each # line has a number, starting at startline, so that a line selected in # list_dialog() can be identified and its key found (see ["i_to_key"] # below). maxkeylenstr is the longest key value as returned by # array_select_entry_longest_key. Returns an array with the following # keys: # ["lines"] the string holding generated lines # ["next_i"] the line number for any following line # ["i_to_key"] an array of line number to key string values # ------------------------------------------------------------------------------ define array_select_entry_pos_keys_to_string { array = $1 startline = $2 maxkeylenstr = $3 ks = $empty_array ksi = $empty_array keyi = $empty_array lines = "" sep = "" nkeys = array[] for (key in array) { if (valid_number(key) && \ search_string(key, "\\s", 0, "regex") < 0 && \ key >= 0) { skey = rjust_to_slen(key, maxkeylenstr) ks[skey] = key } } n = ks[] i = 0 for (skey in ks) { ksi[i] = skey ++i } for (i = 0; i < n; i++) { skey = ksi[i] key = ks[skey] keyi[i + startline] = key val = array[key] sval = array_select_entry_flatten_str(val, 50, "\"") lines = lines sep "" rjust_to_slen(i + startline, nkeys) ": " \ skey " -> " sval sep = "\n" } return make_array("lines", lines, \ "next_i", i + startline, \ "i_to_key", keyi) } # ------------------------------------------------------------------------------ # array_select_entry_nul_key_to_string(array, startline, maxkeylenstr, null): # makes a single line appropriate for list_dialog() displays in # array_select_entry() for the empty string key in array. The line has a # number, startline, so that if selected in list_dialog(), it can be # identified and its key found (see ["i_to_key"] below). maxkeylenstr is # the longest key value as returned by array_select_entry_longest_key. # Returns an array with the following keys: # ["lines"] the string holding the generated line # ["next_i"] the line number for any following line # ["i_to_key"] an array of line number to key string values # ------------------------------------------------------------------------------ define array_select_entry_nul_key_to_string { array = $1 startline = $2 maxkeylenstr = $3 null = $4 keyi = $empty_array lines = "" nkeys = array[] i = 0 if ("" in array) { keyi[i + startline] = "" i = 1 val = array[""] sval = array_select_entry_flatten_str(val, 50, "\"") lines = rjust_to_slen(startline, nkeys) \ ": " ljust_to_slen(null, maxkeylenstr) " -> " sval } return make_array("lines", lines, \ "next_i", i + startline, \ "i_to_key", keyi) } # ------------------------------------------------------------------------------ # array_select_entry_str_keys_to_string(array, startline, maxkeylenstr): makes # lines appropriate for list_dialog() displays in array_select_entry() for # keys in array which are non-nnumeric strings, ordered as in the array. # Each line has a number, starting at startline, so that a line selected # in list_dialog() can be identified and its key found (see ["i_to_key"] # below). maxkeylenstr is the longest key value as returned by # array_select_entry_longest_key. Returns an array with the following # keys: # ["lines"] the string holding generated lines # ["next_i"] the line number for any following line # ["i_to_key"] an array of line number to key string values # ------------------------------------------------------------------------------ define array_select_entry_str_keys_to_string { array = $1 startline = $2 maxkeylenstr = $3 keyi = $empty_array lines = "" sep = "" nkeys = array[] i = 0 for (key in array) { if (valid_number(key) && search_string(key, "\\s", 0, "regex") < 0) continue else if (key == "") continue keyi[i + startline] = key val = array[key] skey = array_select_entry_flatten_str(key, 20, "\"") if (valid_number(val)) sval = val else if (val == "") sval = "" else sval = array_select_entry_flatten_str(val, 50, "\"") lines = lines sep rjust_to_slen(i + startline, nkeys) \ ": " ljust_to_slen(skey, maxkeylenstr) " -> " sval sep = "\n" i++ } return make_array("lines", lines, \ "next_i", i + startline, \ "i_to_key", keyi) } # ============================================================================== # array_select_entry(prompt, array [, button1, ... button7]): uses a # list_dialog() to ask the user to select an array entry (which must # contain only scalar values). Returns an array with the indices # ["key"] the string for a key - may not be present with # string_dlg true and "OK" pressed # ["value"] the key's value or typed in line # ["btnnum"] the button number # ["button"] the button text # The returned array is empty if no button was pressed. ["key"] and # ["value"] may not be present if no entry was selected. If no button was # given, only ["key"] and ["value"] may be returned. # ============================================================================== define array_select_entry { # pick up arguments if ($n_args > 9) { dialog("Too many buttons specified for array_select_entry()") return $empty_array } prompt = $1 array = $2 b = $empty_array nbtns = $n_args - 2 for (i = 1; i <= nbtns; i++) b[i] = $args[i + 2] # set up result array res = $empty_array # build up list_dialog()'s list null_k = "" keyi = $empty_array nline = 0 nkeys = array[] if (nkeys == 0) lines = "" else { null_key = "" long_key = array_select_entry_longest_key(array, null_k) nline = 1 key_title = ljust_to_slen("", long_key) lines = rjust_to_slen("", nkeys) " " key_title " -> " step = array_select_entry_nul_key_to_string(array, nline, long_key, null_k) keyi = keyi + step["i_to_key"] nline = step["next_i"] lines = lines "\n" step["lines"] step = array_select_entry_neg_keys_to_string(array, nline, long_key) keyi = keyi + step["i_to_key"] nline = step["next_i"] lines = lines "\n" step["lines"] step = array_select_entry_pos_keys_to_string(array, nline, long_key) keyi = keyi + step["i_to_key"] nline = step["next_i"] lines = lines "\n" step["lines"] step = array_select_entry_str_keys_to_string(array, nline, long_key) keyi = keyi + step["i_to_key"] nline = step["next_i"] lines = lines "\n" step["lines"] } # now call up the dialog if (nbtns == 0) s = list_dialog(prompt, lines, "OK") else if (nbtns == 1) s = list_dialog(prompt, lines, b[1]) else if (nbtns == 2) s = list_dialog(prompt, lines, b[1], b[2]) else if (nbtns == 3) s = list_dialog(prompt, lines, b[1], b[2], b[3]) else if (nbtns == 4) s = list_dialog(prompt, lines, b[1], b[2], b[3], b[4]) else if (nbtns == 5) s = list_dialog(prompt, lines, b[1], b[2], b[3], b[4], b[5]) else if (nbtns == 6) s = list_dialog(prompt, lines, b[1], b[2], b[3], b[4], b[5], b[6]) else # if (nbtns == 7) # already checked s = list_dialog(prompt, lines, b[1], b[2], b[3], b[4], b[5], b[6], b[7]) btn = $list_dialog_button # get the key number from the returned string s i = 0 if (nline > 0) i = to_number(s) if (i in keyi) { key = keyi[i] res["key"] = key res["value"] = array[key] } if (btn != 0 && btn <= nbtns) { res["btnnum"] = btn res["button"] = b[btn] } return res } # ============================================================================== # to_number(string [, "strict"|defval]): returns the numeric value read from the # front of the string argument. Fails if no leading number was found, with # defval (which defaults to zero), or, if "strict" is present, with an # invalid function call. # ============================================================================== define to_number { s = $1 defval = 0 if ($n_args > 1 && $2 != "strict") defval = to_number($2) s = replace_in_string(s, "(?n^\\s*([-+]?\\d+).*)", "\\1", "regex") if (!valid_number(s)) { if ($n_args > 1 && $2 == "strict") s = number_NoNumericPrefixFound() else s = defval } return s + 0 } # ============================================================================== # ljust_to_slen(str, maxstr): left-justifies str into a string at least as long # as maxstr, padding to the right with spaces. Assumes no newlines or tabs # in the original strings. # ============================================================================== define ljust_to_slen { str = $1 maxstr = $2 sp = replace_in_string(maxstr, ".", " ", "regex") len = max(length(str), length(maxstr)) return substring(str sp, 0, len) } # ============================================================================== # rjust_to_slen(str, maxstr): right-justifies str into a string at least as long # as maxstr, padding to the left with spaces. Assumes no newlines or tabs # in the original strings. # ============================================================================== define rjust_to_slen { str = $1 maxstr = $2 sp = replace_in_string(maxstr, ".", " ", "regex") len = max(length(str), length(maxstr)) total = sp str return substring(total, length(total)-len, length(total)) } # ============================================================================== # make_array_from_list(list_array[, start]): builds an array from the key-value # pairs from contiguous values in list_array, and returns it. The keys to # list_array must be consecutive numbers, starting with start (or zero). # There must be an even number of them. # ============================================================================== define make_array_from_list { list_array = $1 start = 0 if ($n_args > 1) start = $2 array = $empty_array # now add to array until we have no more elements in list_array[] for (i = start; i in list_array; i += 2) { key = list_array[i] val = list_array[i + 1] array[key] = val } return array } # ============================================================================== # make_array(key, value, ...): builds an array from the key-value pairs, and # returns it. If an odd number of arguments is given, does not return # anything, which should cause an error. # ============================================================================== define make_array { return make_array_from_list($args, 1) }