strtokっぽいものを入れ子にしたい。

strtok、便利ですね。マニュアルには「Never use these functions」なんて脅し文句が書いてありますが、気にしない。

ところでstrtokはスタティックな変数にポインターを保存しているので、入れ子にできないんですね。代替にstrtok_rという関数がありますが、なんかMinGWに入っていないっぽい。

じゃあ仕方ないので作ってみるか、と作ってみることにしました。引数を変更したりはしないし、確かマルチスレッドではグローバル変数だけが共有されると思ったので*1、スレッドセーフだと思います。

#include <stdio.h>
#include <string.h>

int tokenizer(char *, int, char *, char);

int main(int argc, char **argv){
     int p1=0, p2=0, p3=0;
     char buf1[256], buf2[256], buf3[256];
     while((p1=tokenizer(argv[1], p1, buf1, '?')) != -1){
          printf("tokenize1: %s\n", buf1);
          p2=0;
          while((p2=tokenizer(buf1, p2, buf2, '&')) != -1){
               printf("    tokenize2: %s\n", buf2);
               p3=0;
               while((p3=tokenizer(buf2, p3, buf3, '=')) != -1){
                    printf("        tokenize3: %s\n", buf3);
               }
          }
     }
     printf("argv: %s\n", argv[1]);
}

int tokenizer(char *str, int p, char *buf, char d)
{
     int i=0;
     while((buf[i]=str[p+i]) != '\0'){
          if(buf[i++] == d){
               buf[i-1]='\0';
               break;
          }
     }
     buf[i] = '\0';
     return (i==0) ? -1 : p+i;
}
$ ./tokenize.exe "aaaaaa?bb=ccc&dddd=ee&f=g"
tokenize1: aaaaaa
    tokenize2: aaaaaa
        tokenize3: aaaaaa
tokenize1: bb=ccc&dddd=ee&f=g
    tokenize2: bb=ccc
        tokenize3: bb
        tokenize3: ccc
    tokenize2: dddd=ee
        tokenize3: dddd
        tokenize3: ee
    tokenize2: f=g
        tokenize3: f
        tokenize3: g
argv: aaaaaa?bb=ccc&dddd=ee&f=g

イメージとしてはURLの文字切り分けのような感じで。argvも変更されてないでしょ、と。

*1:pthreadではそう