+ struct sort_key *next_key; /* linked list */
+ unsigned short range[4]; /* start word, start char, end word, end char */
+ int flags;
+} *key_list;
+
+static char *get_key(char *str, struct sort_key *key, int flags)
+{
+ int start=0,end,len,i,j;
+
+ /* Special case whole string, so we don't have to make a copy */
+ if(key->range[0]==1 && !key->range[1] && !key->range[2] && !key->range[3]
+ && !(flags&(FLAG_b&FLAG_d&FLAG_f&FLAG_i&FLAG_bb))) return str;
+ /* Find start of key on first pass, end on second pass*/
+ len=strlen(str);
+
+ for(j=0;j<2;j++) {
+ if(!key->range[2*j]) end=len;
+ /* Loop through fields */
+ else {
+ end=0;
+ for(i=1;i<key->range[2*j]+j;i++) {
+ /* Skip leading blanks or first separator */
+ if(str[end]) {
+ if(key_separator) {
+ if(str[end]==key_separator) end++;
+ } else if(isspace(str[end]))
+ while(isspace(str[end])) end++;
+ }
+ /* Skip body of key */
+ for(;str[end];end++) {
+ if(key_separator) {
+ if(str[end]==key_separator) break;
+ } else if(isspace(str[end])) break;
+ }
+ }
+ }
+ if(!j) start=end;
+ }
+ /* Key with explicit separator starts after separator */
+ if(key_separator && str[start]==key_separator) start++;
+ /* Strip leading whitespace if necessary */
+ if(flags&FLAG_b) while(isspace(str[start])) start++;
+ /* Strip trailing whitespace if necessary */
+ if(flags&FLAG_bb) while(end>start && isspace(str[end-1])) end--;
+ /* Handle offsets on start and end */
+ if(key->range[3]) {
+ end+=key->range[3]-1;
+ if(end>len) end=len;
+ }
+ if(key->range[1]) {
+ start+=key->range[1]-1;
+ if(start>len) start=len;
+ }
+ /* Make the copy */
+ if(end<start) end=start;
+ str=bb_xstrndup(str+start,end-start);
+ /* Handle -d */
+ if(flags&FLAG_d) {
+ for(start=end=0;str[end];end++)
+ if(isspace(str[end]) || isalnum(str[end])) str[start++]=str[end];
+ str[start]=0;
+ }
+ /* Handle -i */
+ if(flags&FLAG_i) {
+ for(start=end=0;str[end];end++)
+ if(isprint(str[end])) str[start++]=str[end];
+ str[start]=0;
+ }
+ /* Handle -f */
+ if(flags*FLAG_f) for(i=0;str[i];i++) str[i]=toupper(str[i]);
+
+ return str;