void is_string(int s) {
  if (!Mstringp(s)) {
    printf("not a string");
    writeln();
    cleanup_();
  }
  return;
}

int make_string_integer(int n) {
  return make_string(get_integer_val(n));
}

int string_length_integer(int s) {
  return make_integer(MstrSizeRef(s));
}

int string_ref(int s, int n) {
  if (n > MstrSizeRef(s) - 1) {
    printf("string reference out of range ");
    write_int(n);
    printf(" exceeds ");
    write_int(MstrSizeRef(s) - 1);
    writeln();
    cleanup_();
  }
  return MmakeChar(Mstrref(s, n));
}

int string_ref_integer(int s, int n) {
  return string_ref(s, get_integer_val(n));
}

void string_set(int s, int n, int int_ch) {
  int temp;

  if (n > MstrSizeRef(s) - 1) {
    printf("string reference out of range ");
    write_int(n);
    printf(" exceeds ");
    write_int(MstrSizeRef(s) - 1);
    printf(" character ");
    putchar(MgetChar(int_ch));
    writeln();
    cleanup_();
  }
  Mstrset(s, n, MgetChar(int_ch));
  return;
}

int string_set_integer(int s, int n, int int_ch) {
  n = get_integer_val(n);
  string_set(s, n, int_ch);
  return 0;
}

int stringeq(int x, int y) {
  int processing;
  int ret;
  int length_x;
  int length_y;
  int i;

  is_string(x);
  is_string(y);

  length_x = MstrSizeRef(x);
  length_y = MstrSizeRef(y);
  if (length_x != length_y)
    return Mfalse;

  processing = 1;
  ret = Mtrue; // by default
  i = 0;
  while (processing) {
    if (i < length_x)
      if (string_ref(x, i) != string_ref(y, i)) {
	processing = 0;
        ret = Mfalse;
      }
      else
        i = i + 1;
    else
      processing = 0;
  }

  return ret;
}

int string_compare(int x, int y, int is_case_insensitive) {
  int processing;
  int ret;
  int i;
  int length_x;
  int diff;

  // Return < 0 if x is alphabetically first, > 0 if y is first,
  // 0 if the same.

  is_string(x);
  is_string(y);

  length_x = MstrSizeRef(x);

  diff = 0;
  i = 0;
  processing = 1;
  while (processing) {
    if (i < length_x) {
      if (is_case_insensitive)
        diff =
          toupper(MgetChar(string_ref(x, i))) -
          toupper(MgetChar(string_ref(y, i)));
      else
        diff =
          MgetChar(string_ref(x, i)) -
          MgetChar(string_ref(y, i));
  
      if (diff != 0) {
	processing = 0;
        ret = diff;
      }
      else
        i = i + 1;
    }
    else
      processing = 0;
  }

  if (diff != 0)
    return diff;
  else
    return length_x - MstrSizeRef(y);
}

int string_lt(int x, int y) {
  if (string_compare(x, y, 0) < 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_gt(int x, int y) {
  if (string_compare(x, y, 0) > 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_le(int x, int y) {
  if (string_compare(x, y, 0) <= 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ge(int x, int y) {
  if (string_compare(x, y, 0) >= 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ci_lt(int x, int y) {
  if (string_compare(x, y, 1) < 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ci_gt(int x, int y) {
  if (string_compare(x, y, 1) > 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ci_le(int x, int y) {
  if (string_compare(x, y, 1) <= 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ci_ge(int x, int y) {
  if (string_compare(x, y, 1) >= 0)
    return Mtrue;
  else
    return Mfalse;
}

int string_ci_eq(int x, int y) {
  if (string_compare(x, y, 1) == 0)
    return Mtrue;
  else
    return Mfalse;
}

int make_string(int n) {
  int i;
  int s;
  s = make_vector_core(1 + reducesize(n), STRINGSUBTYPE);
  Mvecset(s, 1, n);
  for (i = 0; i < n; i++)
    string_set(s, i, ' ');
  return s;
}

int make_string_with_fill(int n, int ch) {
  int i;
  int s;
  s = make_vector_core(1 + reducesize(n), STRINGSUBTYPE);
  Mvecset(s, 1, n);
  for (i = 0; i < n; i++)
    string_set(s, i, ch);
  return s;
}

int string_to_symbol(int s) {
  int string_size;
  int symbol_idx;
  int symbol;

  is_string(s);

  string_size = MstrSizeRef(s);
  symbol = make_symbol(string_size);
  s = stack_arg1; // trick ???? in case gc clobbers location of string
  for (symbol_idx = 0; symbol_idx < string_size; symbol_idx++)
    symbol_set(
      symbol,
      symbol_idx,
      string_ref(s, symbol_idx));
  return intern(symbol);
}


int symbol_to_string(int symbol) {
  int symbol_size;
  int string_idx;
  int s;

  symbol_size = MstrSizeRef(symbol);
  s = make_string(symbol_size);
  symbol = stack_arg1; // trick ???? in case gc clobbers location of symbol
  for (string_idx = 0; string_idx < symbol_size; string_idx++)
    string_set(
      s,
      string_idx,
      symbol_ref(symbol, string_idx));
  return s;
}

int list_to_string(int l) {
  int s;
  int n;
  int size;

  size = list_length(l);
  s = make_string(size);
  for (n = 0; n < size; n++) {
    string_set(s, n, Mcar(l));
    l = kdr(l);
  }
  return s;
}

int make_string_integer_with_fill(int n, int ch) {
  return make_string_with_fill(get_integer_val(n), MgetChar(ch));
}
