/*
 *  call-seq:
 *     str.index(substring [, offset])   => fixnum or nil
 *     str.index(fixnum [, offset])      => fixnum or nil
 *     str.index(regexp [, offset])      => fixnum or nil
 *  
 *  Returns the index of the first occurrence of the given <i>substring</i>,
 *  character (<i>fixnum</i>), or pattern (<i>regexp</i>) in <i>str</i>. Returns
 *  <code>nil</code> if not found. If the second parameter is present, it
 *  specifies the position in the string to begin the search.
 *     
 *     "hello".index('e')             #=> 1
 *     "hello".index('lo')            #=> 3
 *     "hello".index('a')             #=> nil
 *     "hello".index(101)             #=> 1
 *     "hello".index(/[aeiou]/, -3)   #=> 4
 */

static VALUE
rb_str_index_m(argc, argv, str)
    int argc;
    VALUE *argv;
    VALUE str;
{
    VALUE sub;
    VALUE initpos;
    long pos;

    if (rb_scan_args(argc, argv, "11", &sub, &initpos) == 2) {
        pos = NUM2LONG(initpos);
    }
    else {
        pos = 0;
    }
    if (pos < 0) {
        pos += RSTRING(str)->len;
        if (pos < 0) {
            if (TYPE(sub) == T_REGEXP) {
                rb_backref_set(Qnil);
            }
            return Qnil;
        }
    }

    switch (TYPE(sub)) {
      case T_REGEXP:
        pos = rb_reg_adjust_startpos(sub, str, pos, 0);
        pos = rb_reg_search(sub, str, pos, 0);
        break;

      case T_FIXNUM:
      {
          int c = FIX2INT(sub);
          long len = RSTRING(str)->len;
          unsigned char *p = RSTRING(str)->ptr;

          for (;pos<len;pos++) {
              if (p[pos] == c) return LONG2NUM(pos);
          }
          return Qnil;
      }

      default: {
          VALUE tmp;

          tmp = rb_check_string_type(sub);
          if (NIL_P(tmp)) {
              rb_raise(rb_eTypeError, "type mismatch: %s given",
                       rb_obj_classname(sub));
          }
          sub = tmp;
      }
        /* fall through */
      case T_STRING:
        pos = rb_str_index(str, sub, pos);
        break;
    }

    if (pos == -1) return Qnil;
    return LONG2NUM(pos);
}