printf()系の実装
正確にはsprintf()の変形のasprintf()が欲しいんだけど事情があって自作したい。
けど情報が無いので取り敢えず作ったものを書いてみる。
で調べたんだけど、可変引数のみの使用方法だったらいくらでも情報が出てくる。
というか、その程度であれば自分で作れる。
まず、苦労したのは%sとかの%を使った方法。
man 2 stdargなんかには以下のようなサンプルがある。
#include <stdio.h> #include <stdarg.h> void foo(char *fmt, ...) { va_list ap; int d; char c, *s; va_start(ap, fmt); while (*fmt) switch (*fmt++) { case 's': /* string */ s = va_arg(ap, char *); printf("string %s\n", s); break; case 'd': /* int */ d = va_arg(ap, int); printf("int %d\n", d); break; case 'c': /* char */ /* need a cast here since va_arg only takes fully promoted types */ c = (char) va_arg(ap, int); printf("char %c\n", c); break; } va_end(ap); }
けどこれって、
foo("s s", "foo", "var")
と使う。
自分が知りたいのは%sのような記法。
さらに、苦労したのは
foo("%s hoge %s", "foo", "var")
のようになっているパターン。
上記をmanのまま使う(%の問題は解決したとして)と"foo"と"var"しか取り出せない。
この辺りのサンプルは見付からなかった。
ということで前置きはここまでで、汚いソースだけどメモしておく。
めんどくさいので解説は無し。
//サンプルなので、メモリーリークがあるけど気にしない(実際は Boehm GCつかっているし)。 char *c2str(char c){ char *ret; ret = malloc(sizeof(char)*2); ret[0] = c; ret[1] = '\0'; return ret; } //関数名は考えるのが苦手なのでとりあえず、asprintf()にしている。 int asprintf(char **strp, char *fmt, ...){ int max, step; int i, len, buf_len, fmt_len; char *buf, *str, c; char *format; va_list argp; fmt_len = strlen(fmt); format = malloc(fmt_len); strncpy(format, fmt, fmt_len); len = 0; step = 1024; max = step; str = malloc(max); i = 0; va_start(argp, fmt); while(i<fmt_len){ if(*format != '%'){ buf = c2str(*format); buf_len = 1; i++; format++; goto CONNECT; } switch(*fmt++){ case 's': buf = va_arg(argp, char *); buf_len = strlen(buf); break; default: continue; } i+=2; format+=2; CONNECT: if(len + buf_len >= max){ max += step; str = realloc(str, step); } strncat(str, buf, buf_len); len += buf_len; } va_end(argp); *strp = str; return len; }
printf()系を使用通りに作るのはかなり大変ですね。