home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / the25.zip / thesrc251.zip / sort.c < prev    next >
C/C++ Source or Header  |  1998-06-08  |  25KB  |  609 lines

  1. /***********************************************************************/
  2. /* SORT.C - Functions related to the SORT command.                     */
  3. /***********************************************************************/
  4. /*
  5.  * THE - The Hessling Editor. A text editor similar to VM/CMS xedit.
  6.  * Copyright (C) 1991-1997 Mark Hessling
  7.  *
  8.  * This program is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU General Public License as
  10.  * published by the Free Software Foundation; either version 2 of
  11.  * the License, or any later version.
  12.  *
  13.  * This program is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  16.  * General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU General Public License
  19.  * along with this program; if not, write to:
  20.  *
  21.  *    The Free Software Foundation, Inc.
  22.  *    675 Mass Ave,
  23.  *    Cambridge, MA 02139 USA.
  24.  *
  25.  *
  26.  * If you make modifications to this software that you feel increases
  27.  * it usefulness for the rest of the community, please email the
  28.  * changes, enhancements, bug fixes as well as any and all ideas to me.
  29.  * This software is going to be maintained and enhanced as deemed
  30.  * necessary by the community.
  31.  *
  32.  * Mark Hessling                 Email:             M.Hessling@qut.edu.au
  33.  * PO Box 203                    Phone:                    +617 3802 0800
  34.  * Bellara                       http://www.gu.edu.au/gext/the/markh.html
  35.  * QLD 4507                      **** Maintainer PDCurses & REXX/SQL ****
  36.  * Australia                     ************* Author of THE ************
  37.  */
  38.  
  39. /*
  40. $Id: sort.c 2.1 1995/06/24 16:31:17 MH Rel MH $
  41. */
  42.  
  43. #include <the.h>
  44. #include <proto.h>
  45.  
  46. #define MAX_SORT_FIELDS 10
  47.  
  48. #define SF_ERROR    0
  49. #define SF_START    1
  50. #define SF_ORDER    2
  51. #define SF_LEFT     3
  52.  
  53. struct sort_field
  54.  {
  55.   CHARTYPE order;                     /* A - ascending, D - descending */
  56.   LENGTHTYPE left_col;                                  /* left column */
  57.   LENGTHTYPE right_col;                                /* right column */
  58.  };
  59. typedef struct sort_field SORT_FIELD;
  60.  
  61. CHARTYPE *sort_field_1;
  62. CHARTYPE *sort_field_2;
  63.  
  64. SORT_FIELD sort_fields[MAX_SORT_FIELDS];
  65.  
  66. short num_fields;
  67.  
  68. #ifdef __STDC__
  69. static int cmp(const void *,const void *);
  70. #else
  71. static int cmp();
  72. #endif
  73.  
  74. /***********************************************************************/
  75. #ifdef __STDC__
  76. static int cmp(const void *first,const void *second)
  77. #else
  78. static int cmp(first,second)
  79. void *first,*second;
  80. #endif
  81. /***********************************************************************/
  82. {
  83. /*-------------------------- external data ----------------------------*/
  84. /*--------------------------- local data ------------------------------*/
  85.  register short i=0,j=0;
  86.  short len=0,rc=RC_OK;
  87.  LENGTHTYPE right_col=0,left_col=0;
  88.  LINE *one = *(LINE **)first;
  89.  LINE *two = *(LINE **)second;
  90. /*--------------------------- processing ------------------------------*/
  91. /*---------------------------------------------------------------------*/
  92. /* For each sort field defined in the array sort_fields, compare the   */
  93. /* value of both lines for the specified column range.                 */
  94. /*---------------------------------------------------------------------*/
  95.  for (i=0;i<num_fields;i++)
  96.     {
  97. /*---------------------------------------------------------------------*/
  98. /* Calculate the length of the sort field.                             */
  99. /*---------------------------------------------------------------------*/
  100.      len = sort_fields[i].right_col - sort_fields[i].left_col + 1;
  101. /*---------------------------------------------------------------------*/
  102. /* Set the two temporary fields to blanks.                             */
  103. /*---------------------------------------------------------------------*/
  104.      memset(sort_field_1,' ',len);
  105.      memset(sort_field_2,' ',len);
  106. /*---------------------------------------------------------------------*/
  107. /* For the first line to be compared, extract the portion of the line  */
  108. /* that corresponds with the current sort column...                    */
  109. /*---------------------------------------------------------------------*/
  110.      right_col = min(sort_fields[i].right_col,one->length);
  111.      left_col = min(sort_fields[i].left_col,one->length);
  112. /*---------------------------------------------------------------------*/
  113. /* If the sort column lies after the end of the line, leave the        */
  114. /* contents of the sort field blank.                                   */
  115. /*---------------------------------------------------------------------*/
  116.      if (sort_fields[i].left_col <= one->length)
  117.         memcpy(sort_field_1,one->line+left_col-1,right_col-left_col+1);
  118. /*---------------------------------------------------------------------*/
  119. /* For the next  line to be compared, extract the portion of the line  */
  120. /* that corresponds with the current sort column...                    */
  121. /*---------------------------------------------------------------------*/
  122.      right_col = min(sort_fields[i].right_col,two->length);
  123.      left_col = min(sort_fields[i].left_col,two->length);
  124. /*---------------------------------------------------------------------*/
  125. /* If the sort column lies after the end of the line, leave the        */
  126. /* contents of the sort field blank.                                   */
  127. /*---------------------------------------------------------------------*/
  128.      if (sort_fields[i].left_col <= two->length)
  129.         memcpy(sort_field_2,two->line+left_col-1,right_col-left_col+1);
  130. /*---------------------------------------------------------------------*/
  131. /* If CASE IGNORE is on for the current view, set both sort fields to  */
  132. /* uppercase for the comparison.                                       */
  133. /*---------------------------------------------------------------------*/
  134.      if (CURRENT_VIEW->case_sort == CASE_IGNORE)
  135.        {
  136.         for (j=0;j<len;j++)
  137.           {
  138.            if (islower(sort_field_1[j]))
  139.               sort_field_1[j] = toupper(sort_field_1[j]);
  140.            if (islower(sort_field_2[j]))
  141.               sort_field_2[j] = toupper(sort_field_2[j]);
  142.           }
  143.        }
  144. /*---------------------------------------------------------------------*/
  145. /* If the two sort fields are equal, continue the sort with the next   */
  146. /* sort field value. If the sort fields are different, return with the */
  147. /* the comparison value (if ASCENDING) or the comparison value negated */
  148. /* (if DESCENDING).                                                    */
  149. /*---------------------------------------------------------------------*/
  150.      if ((rc = strncmp((DEFCHAR *)sort_field_1,(DEFCHAR *)sort_field_2,len)) != 0)
  151.         return((sort_fields[i].order == 'A') ? rc : -rc);
  152.     }
  153. /*---------------------------------------------------------------------*/
  154. /* To get to here, the result of sorting on all fields has resulted in */
  155. /* both lines being equal. Return with 0 to indicate this.             */
  156. /*---------------------------------------------------------------------*/
  157.  return(0);
  158. }
  159.  
  160. /***********************************************************************/
  161. #ifdef HAVE_PROTO
  162. short execute_sort(CHARTYPE *params)
  163. #else
  164. short execute_sort(params)
  165. #endif
  166. /***********************************************************************/
  167. {
  168. /*-------------------------- external data ----------------------------*/
  169.  extern CHARTYPE *temp_cmd;
  170.  extern VIEW_DETAILS *vd_mark;
  171. /*--------------------------- local data ------------------------------*/
  172. #define STATE_REAL   0
  173. #define STATE_SHADOW 1
  174. #define SOR_PARAMS  32
  175.  register int i=0;
  176.  CHARTYPE *word[SOR_PARAMS+1];
  177.  CHARTYPE strip[SOR_PARAMS];
  178.  unsigned short num_params=0;
  179.  LINE **lfirst=NULL,**lp=NULL;
  180.  LINE **origfirst=NULL,**origlp=NULL;
  181.  LINE *curr=NULL,*first=NULL,*last=NULL;
  182.  LINE *curr_prev=NULL,*curr_next=NULL;
  183.  LINETYPE true_line=0L,dest_line=0L;
  184.  LINETYPE abs_num_lines=0L;
  185.  LINETYPE j=0L;
  186.  LINETYPE num_actual_lines=0L;
  187.  LINETYPE num_sorted_lines=0L,save_num_sorted_lines=0L;
  188.  short rc=RC_OK,direction=DIRECTION_FORWARD;
  189.  LENGTHTYPE left_col=0,right_col=0,max_column_width=0;
  190.  CHARTYPE order='A';
  191.  TARGET target;
  192.  short target_type=TARGET_NORMAL|TARGET_BLOCK_CURRENT|TARGET_ALL|TARGET_SPARE;
  193.  bool lines_based_on_scope=FALSE;
  194.  short state=STATE_REAL;
  195. /*--------------------------- processing ------------------------------*/
  196. #ifdef TRACE
  197.  trace_function("sort.c:    execute_sort");
  198. #endif
  199. /*---------------------------------------------------------------------*/
  200. /* Validate first argument as a target...                              */
  201. /*---------------------------------------------------------------------*/
  202.  initialise_target(&target);
  203.  rc = validate_target(params,&target,target_type,get_true_line(TRUE),TRUE,TRUE);
  204.  if (rc != RC_OK)
  205.    {
  206.     free_target(&target);
  207. #ifdef TRACE
  208.     trace_return();
  209. #endif
  210.     return(RC_INVALID_OPERAND);
  211.    }
  212.  true_line = (target.num_lines < 0L)?target.last_line:target.true_line;
  213.  direction = DIRECTION_FORWARD;
  214.  abs_num_lines = ((target.num_lines < 0L) ? -target.num_lines : target.num_lines);
  215.  lines_based_on_scope = (target.rt[0].target_type == TARGET_BLOCK_CURRENT) ? FALSE : TRUE;
  216. /*---------------------------------------------------------------------*/
  217. /* Don't need to do anything if < 2 lines to be sorted.                */
  218. /*---------------------------------------------------------------------*/
  219.  if (abs_num_lines < 2L)
  220.    {
  221.     free_target(&target);
  222.     display_error(55,(CHARTYPE *)"",FALSE);
  223. #ifdef TRACE
  224.     trace_return();
  225. #endif
  226.     return(RC_OK);
  227.    }
  228. /*---------------------------------------------------------------------*/
  229. /* Parse the remainder of the arguments and set up the sort_fields[]   */
  230. /* array with valid values.                                            */
  231. /*---------------------------------------------------------------------*/
  232.  if (target.spare != (-1))
  233.    {
  234.     for(i=0;i<SOR_PARAMS;i++)
  235.        strip[i]=STRIP_BOTH;
  236.     num_params = param_split(strtrunc(target.rt[target.spare].string),word,SOR_PARAMS,WORD_DELIMS,TEMP_PARAM,strip,FALSE);
  237.    }
  238. /*---------------------------------------------------------------------*/
  239. /* Process parameters differently, depending on the number...          */
  240. /* 0 parameter (target only) - if BOX BLOCK, then the sort field will  */
  241. /*                             be the block columns, otherwise ZONE    */
  242. /*                             settings will be used.                  */
  243. /* 1 parameters (target & order) - same as above but also validate the */
  244. /*                                 ordering value.                     */
  245. /* > 1 parameters (target & sort fields) - validate each parameter.    */
  246. /*---------------------------------------------------------------------*/
  247.  switch(num_params)
  248.    {
  249.     case 0:
  250.     case 1:
  251.            sort_fields[0].left_col = CURRENT_VIEW->zone_start;
  252.            sort_fields[0].right_col = CURRENT_VIEW->zone_end;
  253.            sort_fields[0].order = order;
  254.            num_fields = 1;
  255.            if (target.rt[0].target_type == TARGET_BLOCK_CURRENT
  256.            && MARK_VIEW->mark_type == M_BOX)
  257.              {
  258.               sort_fields[0].left_col = MARK_VIEW->mark_start_col;
  259.               sort_fields[0].right_col = MARK_VIEW->mark_end_col;
  260.              }
  261. /*---------------------------------------------------------------------*/
  262. /* No more processing if only 1 parameter.                             */
  263. /*---------------------------------------------------------------------*/
  264.            if (num_params == 0)
  265.               break;
  266. /*---------------------------------------------------------------------*/
  267. /* Processing for 2 parameters; validate ordering value.               */
  268. /*---------------------------------------------------------------------*/
  269.            if (equal((CHARTYPE *)"ascending",word[0],1)
  270.            ||  equal((CHARTYPE *)"descending",word[0],1))
  271.              {
  272.               order = word[0][0];
  273.               if (islower(order))
  274.                  order = toupper(order);
  275.               sort_fields[0].order = order;
  276.               break;
  277.              }
  278. /*---------------------------------------------------------------------*/
  279. /* If the parameter is not Ascending or Descending, display error.     */
  280. /*---------------------------------------------------------------------*/
  281.            display_error(1,(CHARTYPE *)word[0],FALSE);
  282.            free_target(&target);
  283. #ifdef TRACE
  284.            trace_return();
  285. #endif
  286.            return(RC_INVALID_OPERAND);
  287.            break;
  288. /*---------------------------------------------------------------------*/
  289. /* More than 1 parameters; sort field(s) are being specified.          */
  290. /*---------------------------------------------------------------------*/
  291.     default:
  292.            i = 0;
  293.            num_fields = 0;
  294.            state = SF_START;
  295.            while(1)
  296.              {
  297.               switch(state)
  298.                 {
  299.                  case SF_START:
  300.                       if (equal((CHARTYPE *)"ascending",word[i],1)
  301.                       ||  equal((CHARTYPE *)"descending",word[i],1))
  302.                         {
  303.                          order = word[i][0];
  304.                          if (islower(order))
  305.                             order = toupper(order);
  306.                          sort_fields[num_fields].order = order;
  307.                          state = SF_ORDER;
  308.                          i++;
  309.                          break;
  310.                         }
  311.                       left_col = atoi((DEFCHAR *)word[i]);
  312.                       if (left_col == 0)
  313.                         {
  314.                          state = SF_ERROR;
  315.                          break;
  316.                         }
  317.                       sort_fields[num_fields].order = order;
  318.                       sort_fields[num_fields].left_col = left_col;
  319.                       state = SF_LEFT;
  320.                       i++;
  321.                       break;
  322.                  case SF_ORDER:
  323.                       left_col = atoi((DEFCHAR *)word[i]);
  324.                       if (left_col < 1)
  325.                         {
  326.                          state = SF_ERROR;
  327.                          break;
  328.                         }
  329.                       sort_fields[num_fields].left_col = left_col;
  330.                       state = SF_LEFT;
  331.                       i++;
  332.                       break;
  333.                  case SF_LEFT:
  334.                       right_col = atoi((DEFCHAR *)word[i]);
  335.                       if (right_col < 1)
  336.                         {
  337.                          state = SF_ERROR;
  338.                          break;
  339.                         }
  340.                       sort_fields[num_fields].right_col = right_col;
  341.                       if (right_col < left_col)
  342.                         {
  343.                          state = SF_ERROR;
  344.                          break;
  345.                         }
  346.                       state = SF_START;
  347.                       i++;
  348.                       num_fields++;
  349.                       break;
  350.                  default:
  351.                       state = SF_ERROR;
  352.                       break;
  353.                 }
  354. /*---------------------------------------------------------------------*/
  355. /* If we have an error, display a message...                           */
  356. /*---------------------------------------------------------------------*/
  357.               if (state == SF_ERROR)
  358.                 {
  359.                  free_target(&target);
  360.                  display_error(1,(CHARTYPE *)word[i],FALSE);
  361. #ifdef TRACE
  362.                  trace_return();
  363. #endif
  364.                  return(RC_INVALID_OPERAND);
  365.                 }
  366. /*---------------------------------------------------------------------*/
  367. /* If we have run out of parameters...                                 */
  368. /*---------------------------------------------------------------------*/
  369.               if (i == num_params)
  370.                 {
  371. /*---------------------------------------------------------------------*/
  372. /* ...then if we have the correct number of parameters, OK.            */
  373. /*---------------------------------------------------------------------*/
  374.                  if (state == SF_START)
  375.                     break;
  376.                  else
  377. /*---------------------------------------------------------------------*/
  378. /* ...otherwise display an error.                                      */
  379. /*---------------------------------------------------------------------*/
  380.                    {
  381.                     free_target(&target);
  382.                     display_error(1,strtrunc(target.rt[target.spare].string),FALSE);
  383. #ifdef TRACE
  384.                     trace_return();
  385. #endif
  386.                     return(RC_INVALID_OPERAND);
  387.                    }
  388.                 }
  389.              }
  390.            break;
  391.    }
  392. /*---------------------------------------------------------------------*/
  393. /* Determine the maximum length of a sort field.                       */
  394. /*---------------------------------------------------------------------*/
  395.  for (i=0;i<num_fields;i++)
  396.     max_column_width = max(max_column_width,
  397.                 sort_fields[i].right_col - sort_fields[i].left_col + 1);
  398. /*---------------------------------------------------------------------*/
  399. /* Allocate memory for each of the temporary sort fields to the length */
  400. /* of the maximum field width.                                         */
  401. /*---------------------------------------------------------------------*/
  402.  if ((sort_field_1 = (CHARTYPE *)(*the_malloc)(max_column_width)) == NULL)
  403.    {
  404.     free_target(&target);
  405.     display_error(30,(CHARTYPE *)"",FALSE);
  406. #ifdef TRACE
  407.     trace_return();
  408. #endif
  409.     return(RC_OUT_OF_MEMORY);
  410.    }
  411.  if ((sort_field_2 = (CHARTYPE *)(*the_malloc)(max_column_width)) == NULL)
  412.    {
  413.     free_target(&target);
  414.     display_error(30,(CHARTYPE *)"",FALSE);
  415. #ifdef TRACE
  416.     trace_return();
  417. #endif
  418.     return(RC_OUT_OF_MEMORY);
  419.    }
  420. /*---------------------------------------------------------------------*/
  421. /* Assign the values of the newly allocated array to the LINE pointers */
  422. /* for the target lines.                                               */
  423. /*---------------------------------------------------------------------*/
  424.  first = curr = lll_find(CURRENT_FILE->first_line,CURRENT_FILE->last_line,true_line,CURRENT_FILE->number_lines);
  425. /*---------------------------------------------------------------------*/
  426. /* Allocate memory for num_lines of LINE pointers and for a copy of    */
  427. /* original lines.                                                     */
  428. /*---------------------------------------------------------------------*/
  429.  if ((lfirst = (LINE **)(*the_malloc)(abs_num_lines*sizeof(LINE *))) == NULL)
  430.    {
  431.     free_target(&target);
  432.     display_error(30,(CHARTYPE *)"",FALSE);
  433. #ifdef TRACE
  434.     trace_return();
  435. #endif
  436.     return(RC_OUT_OF_MEMORY);
  437.    }
  438.  if ((origfirst = (LINE **)(*the_malloc)(3*abs_num_lines*sizeof(LINE *))) == NULL)
  439.    {
  440.     free_target(&target);
  441.     display_error(30,(CHARTYPE *)"",FALSE);
  442. #ifdef TRACE
  443.     trace_return();
  444. #endif
  445.     return(RC_OUT_OF_MEMORY);
  446.    }
  447.  lp = lfirst;
  448.  origlp = origfirst;
  449.  for (j=0L,num_actual_lines=0L;;j++)
  450.    {
  451.     if (lines_based_on_scope)
  452.       {
  453.        if (num_actual_lines == abs_num_lines)
  454.           break;
  455.       }
  456.     else
  457.       {
  458.        if (abs_num_lines == j)
  459.           break;
  460.       }
  461.     rc = processable_line(CURRENT_VIEW,true_line+(LINETYPE)(j*direction),curr);
  462.     switch(rc)
  463.       {
  464.        case LINE_SHADOW:
  465.             break;
  466.        case LINE_TOF:
  467.        case LINE_EOF:
  468.             num_actual_lines++;
  469.             break;
  470.        default:
  471.             lp[num_sorted_lines] = curr;
  472.             memcpy(origlp++,&curr,sizeof(LINE*));
  473.             memcpy(origlp++,&curr->next,sizeof(LINE*));
  474.             memcpy(origlp++,&curr->prev,sizeof(LINE*));
  475.             num_actual_lines++;
  476.             num_sorted_lines++;
  477.             break;
  478.       }
  479. /*---------------------------------------------------------------------*/
  480. /* Proceed to the next record, even if the current record not in scope.*/
  481. /*---------------------------------------------------------------------*/
  482.     if (direction == DIRECTION_BACKWARD)
  483.        curr = curr->prev;
  484.     else
  485.        curr = curr->next;
  486.      if (curr == NULL)
  487.         break;
  488.    }
  489.  last = curr;
  490.  origlp = origfirst;
  491.  save_num_sorted_lines = num_sorted_lines;
  492.  origlp = origfirst;
  493. /*---------------------------------------------------------------------*/
  494. /* Sort the target array...                                            */
  495. /*---------------------------------------------------------------------*/
  496.  qsort(lfirst,num_sorted_lines,sizeof(LINE *),cmp);
  497. /*---------------------------------------------------------------------*/
  498. /* Merge  the sorted array pointers into the linked list...            */
  499. /*---------------------------------------------------------------------*/
  500.  lp = lfirst;
  501.  origlp = origfirst;
  502.  curr = first;
  503.  for (j=0L,num_actual_lines=0L,num_sorted_lines=0L;;j++)
  504.    {
  505.     if (lines_based_on_scope)
  506.       {
  507.        if (num_actual_lines == abs_num_lines)
  508.           break;
  509.       }
  510.     else
  511.       {
  512.        if (abs_num_lines == j)
  513.           break;
  514.       }
  515.     rc = processable_line(CURRENT_VIEW,true_line+(LINETYPE)(j*direction),curr);
  516.     switch(rc)
  517.       {
  518.        case LINE_SHADOW:
  519.             curr_prev = curr->prev;
  520.             curr_next = curr->next;
  521.             if (state == STATE_REAL
  522.             &&  num_sorted_lines !=0)
  523.               {
  524.                lp[num_sorted_lines-1L]->next = origlp[((num_sorted_lines-1L)*3L)+1];
  525.                curr->prev = lp[num_sorted_lines-1L];
  526.               }
  527.             state = STATE_SHADOW;
  528.             if (direction == DIRECTION_BACKWARD)
  529.                curr = curr_prev;
  530.             else
  531.                curr = curr_next;
  532.             break;
  533.        case LINE_TOF:
  534.        case LINE_EOF:
  535.             num_actual_lines++;
  536.             if (direction == DIRECTION_BACKWARD)
  537.                curr = curr->prev;
  538.             else
  539.                curr = curr->next;
  540.             break;
  541.        default:
  542.             if (num_sorted_lines == 0L)
  543.               {
  544.                lp[num_sorted_lines]->next = lp[num_sorted_lines+1L];
  545.                lp[num_sorted_lines]->prev = origlp[(num_sorted_lines*3L)+2L];
  546.                lp[num_sorted_lines]->prev->next = lp[num_sorted_lines];
  547.               }
  548.             else
  549.               {
  550.                if (num_sorted_lines == save_num_sorted_lines - 1L)
  551.                  {
  552.                   lp[num_sorted_lines]->next = origlp[(num_sorted_lines*3L)+1L];
  553.                   lp[num_sorted_lines]->prev = lp[num_sorted_lines-1L];
  554.                   lp[num_sorted_lines]->next->prev = lp[num_sorted_lines];
  555.                  }
  556.                else
  557.                  {
  558.                   lp[num_sorted_lines]->next = lp[num_sorted_lines+1L];
  559.                   lp[num_sorted_lines]->prev = lp[num_sorted_lines-1L];
  560.                  }
  561.               }
  562.             if (state == STATE_SHADOW)
  563.               {
  564.                lp[num_sorted_lines]->prev = origlp[(num_sorted_lines*3L)+2L];
  565.                lp[num_sorted_lines]->prev->next = lp[num_sorted_lines];
  566.               }
  567.             state = STATE_REAL;
  568.             if (direction == DIRECTION_BACKWARD)
  569.                curr = origlp[(num_sorted_lines*3L)+2L];
  570.             else
  571.                curr = origlp[(num_sorted_lines*3L)+1L];
  572.             num_actual_lines++;
  573.             num_sorted_lines++;
  574.             break;
  575.       }
  576. /*---------------------------------------------------------------------*/
  577. /* Proceed to the next record, even if the current record not in scope.*/
  578. /*---------------------------------------------------------------------*/
  579.      if (curr == NULL)
  580.         break;
  581.    }
  582. /*---------------------------------------------------------------------*/
  583. /* If STAY is OFF, change the current and focus lines by the number    */
  584. /* of lines calculated from the target.                                */
  585. /*---------------------------------------------------------------------*/
  586.  if (!CURRENT_VIEW->stay                                 /* stay is off */
  587.  &&  abs_num_lines != 0L)
  588.     CURRENT_VIEW->focus_line = CURRENT_VIEW->current_line = find_next_in_scope(CURRENT_VIEW,NULL,dest_line,direction);
  589. /*---------------------------------------------------------------------*/
  590. /* Free up the memory used for the sort fields and the target array.   */
  591. /*---------------------------------------------------------------------*/
  592.  (*the_free)(sort_field_1);
  593.  (*the_free)(sort_field_2);
  594.  (*the_free)(lfirst);
  595.  (*the_free)(origfirst);
  596.  free_target(&target);
  597. /*---------------------------------------------------------------------*/
  598. /* Increment alteration count...                                       */
  599. /*---------------------------------------------------------------------*/
  600.  increment_alt(CURRENT_FILE);
  601.  
  602.  sprintf((DEFCHAR *)temp_cmd,"%ld line(s) sorted",abs_num_lines);
  603.  display_error(0,temp_cmd,TRUE);
  604. #ifdef TRACE
  605.  trace_return();
  606. #endif
  607.  return(RC_OK);
  608. }
  609.