/*
 * File: ocat.r -- caterr, lconcat
 */
"x || y - concatenate strings x and y."

operator{1} || cater(x, y)

   if !cnv:string(x) then
      runerr(103, x)
   if !cnv:string(y) then
      runerr(103, y)

   abstract {
      return string
      }

   body {
      char *s, *s2;
      word len, i;

      /*
       *  Optimization 1:  The strings to be concatenated are already
       *   adjacent in memory; no allocation is required.
       */
      if (StrLoc(x) + StrLen(x) == StrLoc(y)) {
         StrLoc(result) = StrLoc(x);
         StrLen(result) = StrLen(x) + StrLen(y);
         return result;
         }
      else if ((StrLoc(x) + StrLen(x) == strfree)
      && (DiffPtrs(strend,strfree) > StrLen(y))) {
         /*
          * Optimization 2: The end of x is at the end of the string space.
          *  Hence, x was the last string allocated and need not be
          *  re-allocated. y is appended to the string space and the
          *  result is pointed to the start of x.
          */
	 result = x;
	 /*
	  * Append y to the end of the string space.
	  */
	 Protect(alcstr(StrLoc(y),StrLen(y)), runerr(0));
	 /*
	  *  Set the length of the result and return.
	  */
	 StrLen(result) = StrLen(x) + StrLen(y);
	 return result;
         }

      /*
       * Otherwise, allocate space for x and y, and copy them
       *  to the end of the string space.
       */
      Protect(StrLoc(result) = alcstr(NULL, StrLen(x) + StrLen(y)), runerr(0));
      s = StrLoc(result);
      s2 = StrLoc(x);
      len = StrLen(x);
      for(i = 0; i < len; i++)
	 *s++ = *s2++;
      s2 = StrLoc(y);
      len = StrLen(y);
      for(i = 0; i < len; i++)
	 *s++ = *s2++;

      /*
       *  Set the length of the result and return.
       */
      StrLen(result) = StrLen(x) + StrLen(y);
      return result;
      }
end


"x ||| y - concatenate lists x and y."

operator{1} ||| lconcat(x, y)
   /*
    * x and y must be lists.
    */
   if !is:list(x) then
      runerr(108, x)
   if !is:list(y) then
      runerr(108, y)

   abstract {
      return new list(store[(type(x) ++ type(y)).lst_elem])
      }

   body {
      register struct b_list *bp1;
      register struct b_lelem *lp1;
      word size1, size2, size3;

      /*
       * Get the size of both lists.
       */
      size1 = BlkLoc(x)->list.size;
      size2 = BlkLoc(y)->list.size;
      size3 = size1 + size2;

      Protect(bp1 = (struct b_list *)alclist(size3), runerr(0));
      Protect(lp1 = (struct b_lelem *)alclstb(size3,(word)0,size3), runerr(0));
      bp1->listhead = bp1->listtail = (union block *)lp1;

      /*
       * Make a copy of both lists in adjacent slots.
       */
      cpslots(&x, lp1->lslots, (word)1, size1 + 1);
      cpslots(&y, lp1->lslots + size1, (word)1, size2 + 1);

      BlkLoc(x) = (union block *)bp1;
      return x;
      }
end
