/* * call-seq: * str.succ => new_str * str.next => new_str * * Returns the successor to <i>str</i>. The successor is calculated by * incrementing characters starting from the rightmost alphanumeric (or * the rightmost character if there are no alphanumerics) in the * string. Incrementing a digit always results in another digit, and * incrementing a letter results in another letter of the same case. * Incrementing nonalphanumerics uses the underlying character set's * collating sequence. * * If the increment generates a ``carry,'' the character to the left of * it is incremented. This process repeats until there is no carry, * adding an additional character if necessary. * * "abcd".succ #=> "abce" * "THX1138".succ #=> "THX1139" * "<<koala>>".succ #=> "<<koalb>>" * "1999zzz".succ #=> "2000aaa" * "ZZZ9999".succ #=> "AAAA0000" * "***".succ #=> "**+" */ static VALUE rb_str_succ(orig) VALUE orig; { VALUE str; char *sbeg, *s; int c = -1; long n = 0; str = rb_str_new5(orig, RSTRING(orig)->ptr, RSTRING(orig)->len); OBJ_INFECT(str, orig); if (RSTRING(str)->len == 0) return str; sbeg = RSTRING(str)->ptr; s = sbeg + RSTRING(str)->len - 1; while (sbeg <= s) { if (ISALNUM(*s)) { if ((c = succ_char(s)) == 0) break; n = s - sbeg; } s--; } if (c == -1) { /* str contains no alnum */ sbeg = RSTRING(str)->ptr; s = sbeg + RSTRING(str)->len - 1; c = '\001'; while (sbeg <= s) { if ((*s += 1) != 0) break; s--; } } if (s < sbeg) { RESIZE_CAPA(str, RSTRING(str)->len + 1); s = RSTRING(str)->ptr + n; memmove(s+1, s, RSTRING(str)->len - n); *s = c; RSTRING(str)->len += 1; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; } return str; }