rts-char.c

     
   1  //! @file rts-char.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it 
  12  //! under the terms of the GNU General Public License as published by the 
  13  //! Free Software Foundation; either version 3 of the License, or 
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but 
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 
  19  //! more details. You should have received a copy of the GNU General Public 
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! CHAR, STRING and BYTES routines.
  25  
  26  #include "a68g.h"
  27  #include "a68g-genie.h"
  28  #include "a68g-prelude.h"
  29  #include "a68g-transput.h"
  30  
  31  // OP (CHAR, CHAR) BOOL.
  32  
  33  #define A68G_CMP_CHAR(n, OP)\
  34  void n (NODE_T * p) {\
  35    A68G_CHAR i, j;\
  36    POP_OBJECT (p, &j, A68G_CHAR);\
  37    POP_OBJECT (p, &i, A68G_CHAR);\
  38    PUSH_VALUE (p, (BOOL_T) (TO_UCHAR (VALUE (&i)) OP TO_UCHAR (VALUE (&j))), A68G_BOOL);\
  39    }
  40  
  41  A68G_CMP_CHAR (genie_eq_char, ==);
  42  A68G_CMP_CHAR (genie_ne_char, !=);
  43  A68G_CMP_CHAR (genie_lt_char, <);
  44  A68G_CMP_CHAR (genie_gt_char, >);
  45  A68G_CMP_CHAR (genie_le_char, <=);
  46  A68G_CMP_CHAR (genie_ge_char, >=);
  47  
  48  //! @brief OP ABS = (CHAR) INT
  49  
  50  void genie_abs_char (NODE_T * p)
  51  {
  52    A68G_CHAR i;
  53    POP_OBJECT (p, &i, A68G_CHAR);
  54    PUSH_VALUE (p, TO_UCHAR (VALUE (&i)), A68G_INT);
  55  }
  56  
  57  //! @brief OP REPR = (INT) CHAR
  58  
  59  void genie_repr_char (NODE_T * p)
  60  {
  61    A68G_INT k;
  62    POP_OBJECT (p, &k, A68G_INT);
  63    PRELUDE_ERROR (VALUE (&k) < 0 || VALUE (&k) > (int) UCHAR_MAX, p, ERROR_OUT_OF_BOUNDS, M_CHAR);
  64    PUSH_VALUE (p, (char) (VALUE (&k)), A68G_CHAR);
  65  }
  66  
  67  // OP (CHAR) BOOL.
  68  
  69  #define A68G_CHAR_BOOL(n, OP)\
  70  void n (NODE_T * p) {\
  71    A68G_CHAR ch;\
  72    POP_OBJECT (p, &ch, A68G_CHAR);\
  73    PUSH_VALUE (p, (BOOL_T) (OP (VALUE (&ch)) == 0 ? A68G_FALSE : A68G_TRUE), A68G_BOOL);\
  74    }
  75  
  76  A68G_CHAR_BOOL (genie_is_alnum, IS_ALNUM);
  77  A68G_CHAR_BOOL (genie_is_alpha, IS_ALPHA);
  78  A68G_CHAR_BOOL (genie_is_cntrl, IS_CNTRL);
  79  A68G_CHAR_BOOL (genie_is_digit, IS_DIGIT);
  80  A68G_CHAR_BOOL (genie_is_graph, IS_GRAPH);
  81  A68G_CHAR_BOOL (genie_is_lower, IS_LOWER);
  82  A68G_CHAR_BOOL (genie_is_print, IS_PRINT);
  83  A68G_CHAR_BOOL (genie_is_punct, IS_PUNCT);
  84  A68G_CHAR_BOOL (genie_is_space, IS_SPACE);
  85  A68G_CHAR_BOOL (genie_is_upper, IS_UPPER);
  86  A68G_CHAR_BOOL (genie_is_xdigit, IS_XDIGIT);
  87  
  88  #define A68G_CHAR_CHAR(n, OP)\
  89  void n (NODE_T * p) {\
  90    A68G_CHAR *ch;\
  91    POP_OPERAND_ADDRESS (p, ch, A68G_CHAR);\
  92    VALUE (ch) = (char) (OP (TO_UCHAR (VALUE (ch))));\
  93  }
  94  
  95  A68G_CHAR_CHAR (genie_to_lower, TO_LOWER);
  96  A68G_CHAR_CHAR (genie_to_upper, TO_UPPER);
  97  
  98  // STRING in A68 is defined as MODE STRING = FLEX [] CHAR.
  99  // Below routines appear complex since A68 can alias a  [] CHAR
 100  // to either a row or column in a CHAR matrix. 
 101  // Note that Algol 68 cannot store transient names, nonetheless
 102  // these routines are designed to also operate on [] CHAR in principle.
 103  // To mitigate, operations distinguish between common and generic cases.
 104  // Most STRING values will be 'common', for instance not aliased.
 105  
 106  //! @brief OP + = (CHAR, CHAR) STRING
 107  
 108  void genie_add_char (NODE_T * p)
 109  {
 110    // Right operand.
 111    A68G_CHAR b;
 112    POP_OBJECT (p, &b, A68G_CHAR);
 113    CHECK_INIT (p, INITIALISED (&b), M_CHAR);
 114    // Left operand.
 115    A68G_CHAR a;
 116    POP_OBJECT (p, &a, A68G_CHAR);
 117    CHECK_INIT (p, INITIALISED (&a), M_CHAR);
 118    // Make sum array.
 119    A68G_REF c = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
 120    A68G_REF d = heap_generator_2 (p, M_STRING, 2, SIZE (M_CHAR));
 121    A68G_ARRAY *arr_3; A68G_TUPLE *tup_3; BYTE_T *str_3;
 122    GET_DESCRIPTOR (arr_3, tup_3, &c);
 123    DIM (arr_3) = 1;
 124    SLICE (arr_3) = M_CHAR;
 125    SLICE_SIZE (arr_3) = SIZE (M_CHAR);
 126    SLICE_OFFSET (arr_3) = 0;
 127    FIELD_OFFSET (arr_3) = 0;
 128    ARRAY (arr_3) = d;
 129    LWB (tup_3) = 1;
 130    UPB (tup_3) = 2;
 131    SHIFT (tup_3) = LWB (tup_3);
 132    SPAN (tup_3) = 1;
 133    // Add chars.
 134    str_3 = DEREF (BYTE_T, &ARRAY (arr_3));
 135    MOVE ((BYTE_T *) & str_3[0], (BYTE_T *) & a, SIZE (M_CHAR));
 136    MOVE ((BYTE_T *) & str_3[SIZE (M_CHAR)], (BYTE_T *) & b, SIZE (M_CHAR));
 137    PUSH_REF (p, c);
 138  }
 139  
 140  //! @brief OP ELEM = (INT, STRING) CHAR # ALGOL68C #
 141  
 142  void genie_elem_string (NODE_T * p)
 143  {
 144    A68G_REF z;
 145    POP_REF (p, &z);
 146    CHECK_REF (p, z, M_STRING);
 147    A68G_INT k;
 148    POP_OBJECT (p, &k, A68G_INT);
 149    A68G_ARRAY *arr; A68G_TUPLE *tup;
 150    GET_DESCRIPTOR (arr, tup, &z);
 151    PRELUDE_ERROR (VALUE (&k) < LWB (tup), p, ERROR_INDEX_OUT_OF_BOUNDS, NO_TEXT);
 152    PRELUDE_ERROR (VALUE (&k) > UPB (tup), p, ERROR_INDEX_OUT_OF_BOUNDS, NO_TEXT);
 153    BYTE_T *str = DEREF (BYTE_T, &(ARRAY (arr)));
 154    A68G_CHAR *ch = (A68G_CHAR *) & (str[INDEX_1_DIM (arr, tup, VALUE (&k))]);
 155    PUSH_VALUE (p, VALUE (ch), A68G_CHAR);
 156  }
 157  
 158  //! @brief OP + = (STRING, STRING) STRING
 159  
 160  void genie_add_string (NODE_T * p)
 161  {
 162    const size_t size_char = SIZE (M_CHAR);
 163    // Right operand.
 164    A68G_REF b;
 165    POP_REF (p, &b);
 166    CHECK_INIT (p, INITIALISED (&b), M_STRING);
 167    A68G_ARRAY *arr_2; A68G_TUPLE *tup_2;
 168    GET_DESCRIPTOR (arr_2, tup_2, &b);
 169    int l_2 = ROW_SIZE (tup_2);
 170    // Left operand.
 171    A68G_REF a;
 172    POP_REF (p, &a);
 173    CHECK_REF (p, a, M_STRING);
 174    A68G_ARRAY *arr_1; A68G_TUPLE *tup_1;
 175    GET_DESCRIPTOR (arr_1, tup_1, &a);
 176    int l_1 = ROW_SIZE (tup_1);
 177    // Make sum array.
 178    A68G_REF ref_s = heap_generator (p, M_STRING, DESCRIPTOR_SIZE (1));
 179    A68G_REF new_s = heap_generator_2 (p, M_STRING, l_1 + l_2, size_char);
 180    // Recompute since garbage collection might have moved data.
 181    GET_DESCRIPTOR (arr_1, tup_1, &a);
 182    GET_DESCRIPTOR (arr_2, tup_2, &b);
 183    A68G_ARRAY *arr_3; A68G_TUPLE *tup_3;
 184    GET_DESCRIPTOR (arr_3, tup_3, &ref_s);
 185    DIM (arr_3) = 1;
 186    SLICE (arr_3) = M_CHAR;
 187    SLICE_SIZE (arr_3) = size_char;
 188    SLICE_OFFSET (arr_3) = 0;
 189    FIELD_OFFSET (arr_3) = 0;
 190    ARRAY (arr_3) = new_s;
 191    LWB (tup_3) = 1;
 192    UPB (tup_3) = l_1 + l_2;
 193    SHIFT (tup_3) = LWB (tup_3);
 194    SPAN (tup_3) = 1;
 195    // Add strings.
 196    BYTE_T *sum = DEREF (BYTE_T, &ARRAY (arr_3));
 197    size_t m = 0;
 198    if (ROW_SIZE (tup_1) > 0) {
 199      if (SPAN (tup_1) == 1) {
 200        // Common case. 
 201        size_t n_1 = l_1 * size_char;
 202        BYTE_T *s_1 = DEREF (BYTE_T, &ARRAY (arr_1));
 203        MOVE (sum, & s_1[INDEX_1_DIM (arr_1, tup_1, LWB (tup_1))], n_1);
 204        m = n_1;
 205      } else {
 206        // Generic case. 
 207        BYTE_T *s_1 = DEREF (BYTE_T, &ARRAY (arr_1));
 208        m = 0;
 209        for (INT_T k = LWB (tup_1); k <= UPB (tup_1); k++) {
 210          MOVE ((BYTE_T *) & sum[m], (BYTE_T *) & s_1[INDEX_1_DIM (arr_1, tup_1, k)], size_char);
 211          m += size_char;
 212        }
 213      }
 214    }
 215    if (ROW_SIZE (tup_2) > 0) {
 216      if (SPAN (tup_2) == 1) {
 217        // Common case. 
 218        size_t n_2 = l_2 * size_char;
 219        BYTE_T *s_2 = DEREF (BYTE_T, &ARRAY (arr_2));
 220        MOVE (& sum[m], & s_2[INDEX_1_DIM (arr_2, tup_2, LWB (tup_2))], n_2);
 221      } else {
 222        // Generic case. 
 223        BYTE_T *s_2 = DEREF (BYTE_T, &ARRAY (arr_2));
 224        for (INT_T k = LWB (tup_2); k <= UPB (tup_2); k++) {
 225          MOVE ((BYTE_T *) & sum[m], (BYTE_T *) & s_2[INDEX_1_DIM (arr_2, tup_2, k)], size_char);
 226          m += size_char;
 227        }
 228      }
 229    }
 230    PUSH_REF (p, ref_s);
 231  }
 232  
 233  //! @brief OP * = (INT, STRING) STRING
 234  
 235  void genie_times_int_string (NODE_T * p)
 236  {
 237    A68G_REF a;
 238    POP_REF (p, &a);
 239    A68G_INT k;
 240    POP_OBJECT (p, &k, A68G_INT);
 241    PRELUDE_ERROR (VALUE (&k) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
 242    CHECK_INT_SHORTEN (p, VALUE (&k));
 243    PUSH_REF (p, empty_string (p));
 244    while (VALUE (&k)--) {
 245      PUSH_REF (p, a);
 246      genie_add_string (p);
 247    }
 248  }
 249  
 250  //! @brief OP * = (STRING, INT) STRING
 251  
 252  void genie_times_string_int (NODE_T * p)
 253  {
 254    A68G_INT k;
 255    POP_OBJECT (p, &k, A68G_INT);
 256    A68G_REF a;
 257    POP_REF (p, &a);
 258    PUSH_VALUE (p, VALUE (&k), A68G_INT);
 259    PUSH_REF (p, a);
 260    genie_times_int_string (p);
 261  }
 262  
 263  //! @brief OP * = (INT, CHAR) STRING
 264  
 265  void genie_times_int_char (NODE_T * p)
 266  {
 267    // Pop operands.
 268    A68G_CHAR a;
 269    POP_OBJECT (p, &a, A68G_CHAR);
 270    A68G_INT s_size;
 271    POP_OBJECT (p, &s_size, A68G_INT);
 272    PRELUDE_ERROR (VALUE (&s_size) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
 273    CHECK_INT_SHORTEN (p, VALUE (&s_size));
 274    // Make new string.
 275    A68G_REF z, row; A68G_ARRAY arr; A68G_TUPLE tup;
 276    NEW_ROW_1D (z, row, arr, tup, M_ROW_CHAR, M_CHAR, (int) (VALUE (&s_size)));
 277    BYTE_T *s = ADDRESS (&row);
 278    size_t m = 0;
 279    for (INT_T k = 0; k < VALUE (&s_size); k++) {
 280      A68G_CHAR ch;
 281      STATUS (&ch) = INIT_MASK;
 282      VALUE (&ch) = VALUE (&a);
 283      *(A68G_CHAR *) & s[m] = ch;
 284      m += SIZE (M_CHAR);
 285    }
 286    PUSH_REF (p, z);
 287  }
 288  
 289  //! @brief OP * = (CHAR, INT) STRING
 290  
 291  void genie_times_char_int (NODE_T * p)
 292  {
 293    A68G_INT k;
 294    POP_OBJECT (p, &k, A68G_INT);
 295    A68G_CHAR a;
 296    POP_OBJECT (p, &a, A68G_CHAR);
 297    PUSH_VALUE (p, VALUE (&k), A68G_INT);
 298    PUSH_VALUE (p, VALUE (&a), A68G_CHAR);
 299    genie_times_int_char (p);
 300  }
 301  
 302  //! @brief OP +:= = (REF STRING, STRING) REF STRING
 303  
 304  void genie_plusab_string (NODE_T * p)
 305  {
 306    genie_f_and_becomes (p, M_REF_STRING, genie_add_string);
 307  }
 308  
 309  //! @brief OP +=: = (STRING, REF STRING) REF STRING
 310  
 311  void genie_plusto_string (NODE_T * p)
 312  {
 313    A68G_REF ref_a;
 314    POP_REF (p, &ref_a);
 315    CHECK_REF (p, ref_a, M_REF_STRING);
 316    A68G_REF a = *DEREF (A68G_REF, &ref_a);
 317    CHECK_INIT (p, INITIALISED (&a), M_STRING);
 318    A68G_REF ref_b;
 319    POP_REF (p, &ref_b);
 320    PUSH_REF (p, ref_b);
 321    PUSH_REF (p, a);
 322    genie_add_string (p);
 323    POP_REF (p, DEREF (A68G_REF, &ref_a));
 324    PUSH_REF (p, ref_a);
 325  }
 326  
 327  //! @brief OP *:= = (REF STRING, INT) REF STRING
 328  
 329  void genie_timesab_string (NODE_T * p)
 330  {
 331    A68G_INT k;
 332    POP_OBJECT (p, &k, A68G_INT);
 333    PRELUDE_ERROR (VALUE (&k) < 0, p, ERROR_INVALID_ARGUMENT, M_INT);
 334    A68G_REF ref;
 335    POP_REF (p, &ref);
 336    CHECK_REF (p, ref, M_REF_STRING);
 337    A68G_REF a = *DEREF (A68G_REF, &ref);
 338    CHECK_INIT (p, INITIALISED (&a), M_STRING);
 339    // Multiplication as repeated addition cf. RR.
 340    PUSH_REF (p, empty_string (p));
 341    for (INT_T i = 1; i <= VALUE (&k); i++) {
 342      PUSH_REF (p, a);
 343      genie_add_string (p);
 344    }
 345    // The stack contains a STRING, promote to REF STRING.
 346    POP_REF (p, DEREF (A68G_REF, &ref));
 347    PUSH_REF (p, ref);
 348  }
 349  
 350  //! @brief Difference between two STRINGs in the stack.
 351  
 352  int string_diff (NODE_T * p)
 353  {
 354    // Pop operands.
 355    A68G_REF row2;
 356    POP_REF (p, &row2);
 357    CHECK_INIT (p, INITIALISED (&row2), M_STRING);
 358    A68G_ARRAY *arr_2; A68G_TUPLE *tup_2;
 359    GET_DESCRIPTOR (arr_2, tup_2, &row2);
 360    int len_2 = ROW_SIZE (tup_2);
 361    A68G_REF row1;
 362    POP_REF (p, &row1);
 363    CHECK_INIT (p, INITIALISED (&row1), M_STRING);
 364    A68G_ARRAY *arr_1; A68G_TUPLE *tup_1;
 365    GET_DESCRIPTOR (arr_1, tup_1, &row1);
 366    int len_1 = ROW_SIZE (tup_1);
 367    // Compute string diference.
 368    int dif = 0;
 369    size_t size = (len_1 > len_2 ? len_1 : len_2);
 370    BYTE_T *s_1 = (len_1 > 0 ? DEREF (BYTE_T, &ARRAY (arr_1)) : NO_BYTE);
 371    BYTE_T *s_2 = (len_2 > 0 ? DEREF (BYTE_T, &ARRAY (arr_2)) : NO_BYTE);
 372    INT_T m_1 = INDEX_1_DIM (arr_1, tup_1, LWB (tup_1));
 373    INT_T m_2 = INDEX_1_DIM (arr_2, tup_2, LWB (tup_2));
 374    INT_T m = 0;
 375    if (SPAN (tup_1) == 1 && SPAN (tup_2) == 1) { 
 376      // Common case. 
 377      for (INT_T k = 0; k < size && dif == 0; k++) {
 378        int a = 0, b = 0;
 379        if (len_1 > 0 && k < len_1) {
 380          A68G_CHAR *ch = (A68G_CHAR *) & s_1[m_1 + m];
 381          a = (int) VALUE (ch);
 382        }
 383        if (len_2 > 0 && k < len_2) {
 384          A68G_CHAR *ch = (A68G_CHAR *) & s_2[m_2 + m];
 385          b = (int) VALUE (ch);
 386        }
 387        m += SIZE (M_CHAR);
 388        dif = (TO_UCHAR (a) - TO_UCHAR (b));
 389      }
 390    } else { 
 391      // Generic case.
 392      for (INT_T k = 0; k < size && dif == 0; k++) {
 393        int a = 0, b = 0;
 394        if (len_1 > 0 && k < len_1) {
 395          A68G_CHAR *ch = (A68G_CHAR *) & s_1[m_1 + m];
 396          a = (int) VALUE (ch);
 397        }
 398        if (len_2 > 0 && k < len_2) {
 399          A68G_CHAR *ch = (A68G_CHAR *) & s_2[m_2 + m];
 400          b = (int) VALUE (ch);
 401        }
 402        m += SIZE (M_CHAR);
 403        dif = (TO_UCHAR (a) - TO_UCHAR (b));
 404      }
 405    }
 406    return dif;
 407  }
 408  
 409  // OP (STRING, STRING) BOOL.
 410  
 411  #define A68G_CMP_STRING(n, OP)\
 412  void n (NODE_T * p) {\
 413    int k = string_diff (p);\
 414    PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
 415  }
 416  
 417  A68G_CMP_STRING (genie_eq_string, ==);
 418  A68G_CMP_STRING (genie_ne_string, !=);
 419  A68G_CMP_STRING (genie_lt_string, <);
 420  A68G_CMP_STRING (genie_gt_string, >);
 421  A68G_CMP_STRING (genie_le_string, <=);
 422  A68G_CMP_STRING (genie_ge_string, >=);
 423  
 424  //! @brief PROC char in string = (CHAR, REF INT, STRING) BOOL
 425  
 426  void genie_char_in_string (NODE_T * p)
 427  {
 428    A68G_REF ref_str;
 429    POP_REF (p, &ref_str);
 430    A68G_ROW row = *(A68G_REF *) &ref_str;
 431    CHECK_INIT (p, INITIALISED (&row), M_ROWS);
 432    A68G_ARRAY *arr; A68G_TUPLE *tup;
 433    GET_DESCRIPTOR (arr, tup, &row);
 434    A68G_REF ref_pos;
 435    POP_REF (p, &ref_pos);
 436    A68G_CHAR c;
 437    POP_OBJECT (p, &c, A68G_CHAR);
 438    reset_transput_buffer (PATTERN_BUFFER);
 439    add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_str);
 440    int len = get_transput_buffer_index (PATTERN_BUFFER);
 441    char *q = get_transput_buffer (PATTERN_BUFFER);
 442    char ch = (char) VALUE (&c);
 443    for (INT_T k = 0; k < len; k++) {
 444      if (q[k] == ch) {
 445        A68G_INT pos;
 446        STATUS (&pos) = INIT_MASK;
 447        VALUE (&pos) = k + LOWER_BOUND (tup);
 448        *DEREF (A68G_INT, &ref_pos) = pos;
 449        PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
 450        return;
 451      }
 452    }
 453    PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
 454  }
 455  
 456  //! @brief PROC last char in string = (CHAR, REF INT, STRING) BOOL
 457  
 458  void genie_last_char_in_string (NODE_T * p)
 459  {
 460    A68G_REF ref_str;
 461    POP_REF (p, &ref_str);
 462    A68G_ROW row = *(A68G_REF *) &ref_str;
 463    CHECK_INIT (p, INITIALISED (&row), M_ROWS);
 464    A68G_ARRAY *arr; A68G_TUPLE *tup;
 465    GET_DESCRIPTOR (arr, tup, &row);
 466    A68G_REF ref_pos;
 467    POP_REF (p, &ref_pos);
 468    A68G_CHAR c;
 469    POP_OBJECT (p, &c, A68G_CHAR);
 470    reset_transput_buffer (PATTERN_BUFFER);
 471    add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_str);
 472    int len = get_transput_buffer_index (PATTERN_BUFFER);
 473    char *q = get_transput_buffer (PATTERN_BUFFER);
 474    char ch = (char) VALUE (&c);
 475    for (INT_T k = len - 1; k >= 0; k--) {
 476      if (q[k] == ch) {
 477        A68G_INT pos;
 478        STATUS (&pos) = INIT_MASK;
 479        VALUE (&pos) = k + LOWER_BOUND (tup);
 480        *DEREF (A68G_INT, &ref_pos) = pos;
 481        PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
 482        return;
 483      }
 484    }
 485    PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
 486  }
 487  
 488  //! @brief PROC string in string = (STRING, REF INT, STRING) BOOL
 489  
 490  void genie_string_in_string (NODE_T * p)
 491  {
 492    A68G_REF ref_str;
 493    POP_REF (p, &ref_str);
 494    A68G_ROW row = *(A68G_REF *) &ref_str;
 495    CHECK_INIT (p, INITIALISED (&row), M_ROWS);
 496    A68G_ARRAY *arr; A68G_TUPLE *tup;
 497    GET_DESCRIPTOR (arr, tup, &row);
 498    A68G_REF ref_pos; 
 499    POP_REF (p, &ref_pos);
 500    A68G_REF ref_pat; 
 501    POP_REF (p, &ref_pat);
 502    reset_transput_buffer (PATTERN_BUFFER);
 503    reset_transput_buffer (STRING_BUFFER);
 504    add_a_string_transput_buffer (p, PATTERN_BUFFER, (BYTE_T *) & ref_pat);
 505    add_a_string_transput_buffer (p, STRING_BUFFER, (BYTE_T *) & ref_str);
 506    char *q = strstr (get_transput_buffer (STRING_BUFFER), get_transput_buffer (PATTERN_BUFFER));
 507    if (q != NO_TEXT) {
 508      if (!IS_NIL (ref_pos)) {
 509        A68G_INT pos;
 510        STATUS (&pos) = INIT_MASK;
 511        // ANSI standard leaves pointer difference undefined.
 512        VALUE (&pos) = LOWER_BOUND (tup) + (int) get_transput_buffer_index (STRING_BUFFER) - strlen (q);
 513        *DEREF (A68G_INT, &ref_pos) = pos;
 514      }
 515      PUSH_VALUE (p, A68G_TRUE, A68G_BOOL);
 516    } else {
 517      PUSH_VALUE (p, A68G_FALSE, A68G_BOOL);
 518    }
 519  }
 520  
 521  // [LONG] BYTES are A68's implementation of fixed-length strings.
 522  // Compare to vintage FORTRAN where an INTEGER value held 4 characters,
 523  // In A68G, a [LONG] BYTES value is a fixed-length array of characters, 
 524  // like PASCAL's PACKED ARRAY OF CHAR.
 525  
 526  //! @brief OP ELEM = (INT, BYTES) CHAR
 527  
 528  void genie_elem_bytes (NODE_T * p)
 529  {
 530    A68G_BYTES j;
 531    POP_OBJECT (p, &j, A68G_BYTES);
 532    A68G_INT i;
 533    POP_OBJECT (p, &i, A68G_INT);
 534    PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
 535    if (VALUE (&i) > strlen (VALUE (&j))) {
 536      genie_null_char (p);
 537    } else {
 538      PUSH_VALUE (p, VALUE (&j)[VALUE (&i) - 1], A68G_CHAR);
 539    }
 540  }
 541  
 542  //! @brief PROC bytes pack = (STRING) BYTES
 543  
 544  void genie_bytespack (NODE_T * p)
 545  {
 546    A68G_REF z;
 547    POP_REF (p, &z);
 548    CHECK_REF (p, z, M_STRING);
 549    PRELUDE_ERROR (a68g_string_size (p, z) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_STRING);
 550    A68G_BYTES b;
 551    STATUS (&b) = INIT_MASK;
 552    ASSERT (a_to_c_string (p, VALUE (&b), z) != NO_TEXT);
 553    PUSH_BYTES (p, VALUE (&b));
 554  }
 555  
 556  //! @brief PROC bytes pack = (STRING) BYTES
 557  
 558  void genie_add_bytes (NODE_T * p)
 559  {
 560    A68G_BYTES *i, *j;
 561    POP_OPERAND_ADDRESSES (p, i, j, A68G_BYTES);
 562    PRELUDE_ERROR ((strlen (VALUE (i)) + strlen (VALUE (j))) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
 563    a68g_bufcat (VALUE (i), VALUE (j), A68G_BYTES_WIDTH);
 564  }
 565  
 566  //! @brief OP +:= = (REF BYTES, BYTES) REF BYTES
 567  
 568  void genie_plusab_bytes (NODE_T * p)
 569  {
 570    genie_f_and_becomes (p, M_REF_BYTES, genie_add_bytes);
 571  }
 572  
 573  //! @brief OP +=: = (BYTES, REF BYTES) REF BYTES
 574  
 575  void genie_plusto_bytes (NODE_T * p)
 576  {
 577    A68G_REF z;
 578    POP_REF (p, &z);
 579    CHECK_REF (p, z, M_REF_BYTES);
 580    A68G_BYTES *address = DEREF (A68G_BYTES, &z);
 581    CHECK_INIT (p, INITIALISED (address), M_BYTES);
 582    A68G_BYTES i;
 583    POP_OBJECT (p, &i, A68G_BYTES);
 584    PRELUDE_ERROR ((strlen (VALUE (address)) + strlen (VALUE (&i))) > A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
 585    A68G_BYTES j;
 586    a68g_bufcpy (VALUE (&j), VALUE (&i), A68G_BYTES_WIDTH);
 587    a68g_bufcat (VALUE (&j), VALUE (address), A68G_BYTES_WIDTH);
 588    a68g_bufcpy (VALUE (address), VALUE (&j), A68G_BYTES_WIDTH);
 589    PUSH_REF (p, z);
 590  }
 591  
 592  //! @brief Difference between BYTE strings.
 593  
 594  int compare_bytes (NODE_T * p)
 595  {
 596    A68G_BYTES y;
 597    POP_OBJECT (p, &y, A68G_BYTES);
 598    A68G_BYTES x;
 599    POP_OBJECT (p, &x, A68G_BYTES);
 600    return strcmp (VALUE (&x), VALUE (&y));
 601  }
 602  
 603  // OP (BYTES, BYTES) BOOL.
 604  
 605  #define A68G_CMP_BYTES(n, OP)\
 606  void n (NODE_T * p) {\
 607    int k = compare_bytes (p);\
 608    PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
 609  }
 610  
 611  A68G_CMP_BYTES (genie_eq_bytes, ==);
 612  A68G_CMP_BYTES (genie_ne_bytes, !=);
 613  A68G_CMP_BYTES (genie_lt_bytes, <);
 614  A68G_CMP_BYTES (genie_gt_bytes, >);
 615  A68G_CMP_BYTES (genie_le_bytes, <=);
 616  A68G_CMP_BYTES (genie_ge_bytes, >=);
 617  
 618  //! @brief OP LENG = (BYTES) LONG BYTES
 619  
 620  void genie_leng_bytes (NODE_T * p)
 621  {
 622    A68G_LONG_BYTES a;
 623    a68g_bufset (VALUE (&a), 0, sizeof (VALUE (&a)));
 624    POP_OBJECT (p, (A68G_BYTES *) &a, A68G_BYTES);
 625    PUSH_LONG_BYTES (p, VALUE (&a));
 626  }
 627  
 628  //! @brief OP SHORTEN = (LONG BYTES) BYTES
 629  
 630  void genie_shorten_bytes (NODE_T * p)
 631  {
 632    A68G_LONG_BYTES a;
 633    POP_OBJECT (p, &a, A68G_LONG_BYTES);
 634    PRELUDE_ERROR (strlen (VALUE (&a)) >= A68G_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_BYTES);
 635    PUSH_BYTES (p, VALUE (&a));
 636  }
 637  
 638  //! @brief OP ELEM = (INT, LONG BYTES) CHAR
 639  
 640  void genie_elem_long_bytes (NODE_T * p)
 641  {
 642    A68G_LONG_BYTES j;
 643    POP_OBJECT (p, &j, A68G_LONG_BYTES);
 644    A68G_INT i;
 645    POP_OBJECT (p, &i, A68G_INT);
 646    PRELUDE_ERROR (VALUE (&i) < 1 || VALUE (&i) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_INT);
 647    if (VALUE (&i) > strlen (VALUE (&j))) {
 648      genie_null_char (p);
 649    } else {
 650      PUSH_VALUE (p, VALUE (&j)[VALUE (&i) - 1], A68G_CHAR);
 651    }
 652  }
 653  
 654  //! @brief PROC long bytes pack = (STRING) LONG BYTES
 655  
 656  void genie_long_bytespack (NODE_T * p)
 657  {
 658    A68G_REF z;
 659    POP_REF (p, &z);
 660    CHECK_REF (p, z, M_STRING);
 661    PRELUDE_ERROR (a68g_string_size (p, z) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_STRING);
 662    A68G_LONG_BYTES b;
 663    STATUS (&b) = INIT_MASK;
 664    ASSERT (a_to_c_string (p, VALUE (&b), z) != NO_TEXT);
 665    PUSH_LONG_BYTES (p, VALUE (&b));
 666  }
 667  
 668  //! @brief OP + = (LONG BYTES, LONG BYTES) LONG BYTES
 669  
 670  void genie_add_long_bytes (NODE_T * p)
 671  {
 672    A68G_LONG_BYTES *i, *j;
 673    POP_OPERAND_ADDRESSES (p, i, j, A68G_LONG_BYTES);
 674    PRELUDE_ERROR ((strlen (VALUE (i)) + strlen (VALUE (j))) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_LONG_BYTES);
 675    a68g_bufcat (VALUE (i), VALUE (j), A68G_LONG_BYTES_WIDTH);
 676  }
 677  
 678  //! @brief OP +:= = (REF LONG BYTES, LONG BYTES) REF LONG BYTES
 679  
 680  void genie_plusab_long_bytes (NODE_T * p)
 681  {
 682    genie_f_and_becomes (p, M_REF_LONG_BYTES, genie_add_long_bytes);
 683  }
 684  
 685  //! @brief OP +=: = (LONG BYTES, REF LONG BYTES) REF LONG BYTES
 686  
 687  void genie_plusto_long_bytes (NODE_T * p)
 688  {
 689    A68G_REF z;
 690    POP_REF (p, &z);
 691    CHECK_REF (p, z, M_REF_LONG_BYTES);
 692    A68G_LONG_BYTES *address = DEREF (A68G_LONG_BYTES, &z);
 693    CHECK_INIT (p, INITIALISED (address), M_LONG_BYTES);
 694    A68G_LONG_BYTES i;
 695    POP_OBJECT (p, &i, A68G_LONG_BYTES);
 696    PRELUDE_ERROR ((strlen (VALUE (address)) + strlen (VALUE (&i))) > A68G_LONG_BYTES_WIDTH, p, ERROR_OUT_OF_BOUNDS, M_LONG_BYTES);
 697    A68G_LONG_BYTES j;
 698    a68g_bufcpy (VALUE (&j), VALUE (&i), A68G_LONG_BYTES_WIDTH);
 699    a68g_bufcat (VALUE (&j), VALUE (address), A68G_LONG_BYTES_WIDTH);
 700    a68g_bufcpy (VALUE (address), VALUE (&j), A68G_LONG_BYTES_WIDTH);
 701    PUSH_REF (p, z);
 702  }
 703  
 704  //! @brief Difference between LONG BYTE strings.
 705  
 706  int compare_long_bytes (NODE_T * p)
 707  {
 708    A68G_LONG_BYTES y;
 709    POP_OBJECT (p, &y, A68G_LONG_BYTES);
 710    A68G_LONG_BYTES x;
 711    POP_OBJECT (p, &x, A68G_LONG_BYTES);
 712    return strcmp (VALUE (&x), VALUE (&y));
 713  }
 714  
 715  // OP (LONG BYTES, LONG BYTES) BOOL.
 716  
 717  #define A68G_CMP_LONG_BYTES(n, OP)\
 718    void n (NODE_T * p) {\
 719      int k = compare_long_bytes (p);\
 720      PUSH_VALUE (p, (BOOL_T) (k OP 0), A68G_BOOL);\
 721    }
 722  
 723  A68G_CMP_LONG_BYTES (genie_eq_long_bytes, ==);
 724  A68G_CMP_LONG_BYTES (genie_ne_long_bytes, !=);
 725  A68G_CMP_LONG_BYTES (genie_lt_long_bytes, <);
 726  A68G_CMP_LONG_BYTES (genie_gt_long_bytes, >);
 727  A68G_CMP_LONG_BYTES (genie_le_long_bytes, <=);
 728  A68G_CMP_LONG_BYTES (genie_ge_long_bytes, >=);
 729  
     


© 2002-2026 J.M. van der Veer (jmvdveer@xs4all.nl)