Printf
-
Upload
akitsukada -
Category
Technology
-
view
1.050 -
download
2
description
Transcript of Printf
printf@akitsukada
2011年9月23日金曜日
まず
読んだprintf
freebsd 8.2.0 stable
usr.bin/printf/printf.c
http://svn.freebsd.org/base/stable/8/usr.bin/printf/
gcc printf.c
で問題なくコンパイル・実行できて試しやすく読みやすかったです。
2011年9月23日金曜日
man は PRINTF(1)の方
PRINTF(3)はC言語のいわゆるprintf()
シェルのコマンドprintfはPRINTF(1)
man “歴史”より
printf は、4.3BSD-Reno で登場しました。それは標準ライブラリ関数printf(3)をモデルにしています。
2011年9月23日金曜日
使い方おさらい
printf format [arguments ...]
format
普通の文字列
エスケープシーケンス
フラグ&フォーマット文字
arguments
formatのフォーマット文字にあてはめる値
2011年9月23日金曜日
エスケープシーケンス\a <ベル> 文字を書きます。
\b <バックスペース> 文字を書きます。
\c この文字列中の残りの文字を無視します。
\f <フォームフィード> 文字を書きます。
\n <改行> 文字を書きます。
\r <復帰> 文字を書きます。
\t <タブ> 文字を書きます。
\v <垂直タブ> 文字を書きます。
\' <シングルクォート> 文字を書きます。
\\ <バックスラッシュ> 文字を書きます。
\num 文字コード を指定
\0num 1 から 3 桁の 8 進数 num で表される ASCII コードの 8 ビット文字を書きます。
2011年9月23日金曜日
フラグ&フォーマット文字
フラグ
“#” 数値を‘別形式’で表示します
“-” 指定したフィールド幅で左詰め
“+” 符号付きフォーマットのとき左端に符号をつけます
“ ” 符号付きフォーマットのとき左をスペースでパディングします正の数のときは符号なし 負の数のときは符号付です(e.g.[ -1])
“0” スペースでなく0でパディングします負の数のとき、スペースと違って符号が一番左にきます(e.g.[-0001])
2011年9月23日金曜日
フラグ&フォーマット文字
フォーマット文字(%に続く文字)diouXx 符号つき 10 進数 (d または i)、符号なし 8進数 (o)、符号なし 10 進数
(u)、符号なし 16 進数 (X または x)
fF `[-]ddd.ddd' のスタイルで表示、精度はデフォルトで6
eE `[-d.ddd+-dd]' で表示、精度はデフォルトで6
gG 最小の長さで最大の精度が得られるように、f (F) または e (E) で表示
aA `[-h.hhh+-pd]' のように、16 進小数点の前は 1 桁で、小数点の後ろは引数で指定した精度指定と同じだけの桁数で表示
c 引数の最初の文字を表示
s 精度で指定した文字数分表示、指定しなければすべて表示
b sと同じだが引数の中のバックスラッシュをエスケープ文字として解釈
% %自体を表示
2011年9月23日金曜日
フラグ&フォーマット文字
フォーマット文字の処理については実質的にC言語のasprintfに任せるだけ
与えられた %hoge の記述を一つずつL75~L90の関数型マクロPFに渡すことが このprintf(1)の仕事
2011年9月23日金曜日
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034[abcdf][1.03][%]
2011年9月23日金曜日
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034[abcdf][1.03][%]
[abcde]\n[1.03]\n[%]\n
次の塊ごとに分解・出力される
[ ... L151 fwrite(start, 1, fmt - start, stdout);abcde ... L289 PF(start, p); => L87 (void)fputs(b, stdout);]\n[ ... L151 fwrite(start, 1, fmt - start, stdout);1.03 ... L318 PF(start, p); => L87 (void)fputs(b, stdout);]\n[ ... L151 fwrite(start, 1, fmt - start, stdout);%% ... L154 putchar('%');]\n ... L151 fwrite(start, 1, fmt - start, stdout);
それぞれ次の場所で出力される
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 escape
書式文字列中のエスケープシーケンス
(を表現する文字列)を
本物のエスケープシーケンスに置換する
例:ab\ncd↓abcd
\cがあった場合chopped == 1となる
lenは処理後の長さ
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 escape
今回の入力で言うと
escape前の fmt:
[%s]\n[%2.2f]\n[%%]\n len: 21
escape後の fmt: [%s]\n [%2.2f]\n [%%]\n
len: 18
...となる。
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 gargv
宣言:L104static char **gargv;
この行(L146)で二つ目の引数“abcde”が代入される
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 表示処理
L147~L177のforループがprintfの心臓部
このforループ内で直接fwrite()やputchar()で
文字を出力したりdoformat()を呼び出して出力したりする。
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
start:char *[%s]\n[%2.2f]\n[%%]\n
fmt:char *[%s]\n[%2.2f]\n[%%]\n
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
startから最初の%までを表示
start:char *[%s]\n[%2.2f]\n[%%]\n※黒字がpointerの指す先
fmt:char *[%s]\n[%2.2f]\n[%%]\n
fmt - start == 1
fwrite( “[%s]\n[%2.2f]\n[%%]\n”, 1, 1, stdout);
=> “[“ を出力
[
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
fmt[1]は s なので
fmt:char *[%s]\n[%2.2f]\n[%%]\n
L157 実行 fmt = doformat( fmt, &rval );
[
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
doformat
%hogehoge の 解釈、出力をうまいことやる ※コード的には、 いろんな箇所で 出力を実行されるのは あまりうまくないと 思う...
[
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
精度と位取り
とりあえず 一つ目の書式は%sなのでこの辺飛ばします
startとfmt
start:char *[%s]\n[%2.2f]\n[%%]\n
fmt:char *[%s]\n[%2.2f]\n[%%]\n
[
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
285 case 's': {286 const char *p;287 288 p = getstr();289 PF(start, p);290 break;291 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 一旦fmtを
nullターミネート
convch:char == ‘s’nextch:char == ‘]’
fmt:char *[%s\0\n[%2.2f]\n[%%]\n
start:char *[%s\0\n[%2.2f]\n[%%]\n
[
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
285 case 's': {286 const char *p;287 288 p = getstr();289 PF(start, p);290 break;291 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
convch == ‘s’なので ここ
442 static const char *443 getstr(void)444 {445 if (!*gargv)446 return ("");447 return (*gargv++);448 }
getstr()は現在の*gargv(==“abcde”)を返しつつ
*gargvを一つ進める(==“1.034”)
[
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
285 case 's': {286 const char *p;287 288 p = getstr();289 PF(start, p);290 break;291 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
75 #define PF(f, func) do { \ 76 char *b = NULL; \ 77 if (havewidth) \ 78 if (haveprec) \ 79 (void)asprintf(&b, f, fieldwidth, precision, func); \ 80 else \ 81 (void)asprintf(&b, f, fieldwidth, func); \ 82 else if (haveprec) \ 83 (void)asprintf(&b, f, precision, func); \ 84 else \ 85 (void)asprintf(&b, f, func); \ 86 if (b) { \ 87 (void)fputs(b, stdout); \ 88 free(b); \ 89 } \ 90 } while (0)
PF(start, p);
start:char*[%s\0\n[%2.2f]\n[%%]\n
=> “%s”
p:char*“abcdf”
“abcdf”出力!
この時点でstdoutに出力されている文字
[abcdf
[abcde
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
285 case 's': {286 const char *p;287 288 p = getstr();289 PF(start, p);290 break;291 }
330 *fmt = nextch;331 return (fmt);332 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 nullターミネート
を元の文字に戻す
nextch:char == ‘]’
fmt:char *[%s\0\n[%2.2f]\n[%%]\n
! ! ![%s]\n[%2.2f]\n[%%]\n
157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;
doformat前のfmt:[%s]\n[%2.2f]\n[%%]\n
! ! から ! !
fmt:char *[%s]\n[%2.2f]\n[%%]\n
start:char *[%s]\n[%2.2f]\n[%%]\n
[abcde
2011年9月23日金曜日
149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout);152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
同様に進み
fmt:char *[%s]\n[%2.2f]\n[%%]\n
start:char *[%s]\n[%2.2f]\n[%%]\n
fwrite( start, // ]\n[%2... 1, // 1 fmt - start, // 3 stdout );
=> “]\n[“ を出力
[abcde][
2011年9月23日金曜日
143 fmt = format = *argv;144 chopped = escape(fmt, 1, &len); /* backslash interpretation */145 rval = end = 0;146 gargv = ++argv;147 for (;;) {148 start = fmt;149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout); 152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }166 167 if (end == 1) {168 warnx1("missing format character", NULL, NULL); 169 return (1);170 }171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);174 /* Restart at the beginning of the format string. */175 fmt = format;176 end = 1;177 }178 /* NOTREACHED */
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
fmt[1]は 2 なので
fmt:char *[%s]\n[%2.2f]\n[%%]\n
L157 実行 fmt = doformat( fmt, &rval );
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 startとfmt
start:char *[%s]\n[%2.2f]\n[%%]\n
fmt:char *[%s]\n[%2.2f]\n[%%]\n
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
strspn
fmt:char *[%s]\n[%2.2f]\n[%%]\n
から、skip1 [#’-+ 0]を
とばす
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
fmt:char*[%s]\n[%2.2f]\n[%%]\n
*fmt == ‘2’なので
havewidth == 0となり、
‘.’までの数字部分がスキップされる。
fmt:char*[%s]\n[%2.2f]\n[%%]\n
となる。
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
fmt:char*[%s]\n[%2.2f]\n[%%]\n
*fmt == ‘.’なので++fmt; で
fmt:char*[%s]\n[%2.2f]\n[%%]\n
となる。
ちなみに start はfmt:start*
[%s]\n[%2.2f]\n[%%]\n
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {185 static const char skip1[] = "#'-+ 0";186 static const char skip2[] = "0123456789";
191 fmt = start + 1;192 /* skip to field width */193 fmt += strspn(fmt, skip1);194 if (*fmt == '*') {195 if (getint(&fieldwidth))196 return (NULL);197 havewidth = 1;198 ++fmt;199 } else {200 havewidth = 0;201 202 /* skip to possible '.', get following precision */203 fmt += strspn(fmt, skip2);204 }205 if (*fmt == '.') {206 /* precision present? */207 ++fmt;208 if (*fmt == '*') {209 if (getint(&precision))210 return (NULL);211 haveprec = 1;212 ++fmt;213 } else {214 haveprec = 0;215 216 /* skip to conversion char */217 fmt += strspn(fmt, skip2);218 }219 } else220 haveprec = 0;
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
fmt:char*[%s]\n[%2.2f]\n[%%]\n
*fmt == ‘2’なので
strspnでskip2を飛ばして
fmt:char*[%s]\n[%2.2f]\n[%%]\n
となる。haveprecは0。
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
285 case 's': {286 const char *p;287 288 p = getstr();289 PF(start, p);290 break;291 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 一旦fmtを
nullターミネート
convch:char == ‘f’nextch:char == ‘]’
fmt:char *[%s]\n[%2.2f\0\n[%%]\n
start:char *[%s\0\n[%2.2f\0\n[%%]\n
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
309 case 'e': case 'E':310 case 'f': case 'F':311 case 'g': case 'G':312 case 'a': case 'A': {313 long double p;314 315 if (getfloating(&p, mod_ldbl))316 *rval = 1;317 if (mod_ldbl)318 PF(start, p);319 else320 PF(start, (double)p);321 break;322 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
convch == ‘s’なので ここ
507 static int508 getfloating(long double *dp, int mod_ldbl)509 {510 char *ep;511 int rval;512
526 *dp = strtod(*gargv, &ep);
getfloating()は現在の*gargv(==“1.034”)を第一引数に入れつつ*gargvを一つ進める
(== null)
[abcde][
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
247 convch = *fmt;248 nextch = *++fmt;249 *fmt = '\0';
250 switch (convch) {251 case 'b': {252 size_t len;253 char *p;254 int getout;255
309 case 'e': case 'E':310 case 'f': case 'F':311 case 'g': case 'G':312 case 'a': case 'A': {313 long double p;314 315 if (getfloating(&p, mod_ldbl))316 *rval = 1;317 if (mod_ldbl)318 PF(start, p);319 else320 PF(start, (double)p);321 break;322 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
75 #define PF(f, func) do { \ 76 char *b = NULL; \ 77 if (havewidth) \ 78 if (haveprec) \ 79 (void)asprintf(&b, f, fieldwidth, precision, func); \ 80 else \ 81 (void)asprintf(&b, f, fieldwidth, func); \ 82 else if (haveprec) \ 83 (void)asprintf(&b, f, precision, func); \ 84 else \ 85 (void)asprintf(&b, f, func); \ 86 if (b) { \ 87 (void)fputs(b, stdout); \ 88 free(b); \ 89 } \ 90 } while (0)
asprintf( &b, // 1.03 “%2.2f”, 1.034 );1.03 出力!!
PF(start, p);
start:char*[%s]\n[%2.2f\0\n[%%]\n=> “%2.2f”
p:long double1.034
[abcde][1.03
2011年9月23日金曜日
182 static char *183 doformat(char *start, int *rval)184 {
309 case 'e': case 'E':310 case 'f': case 'F':311 case 'g': case 'G':312 case 'a': case 'A': {313 long double p;314 315 if (getfloating(&p, mod_ldbl))316 *rval = 1;317 if (mod_ldbl)318 PF(start, p);319 else320 PF(start, (double)p);321 break;322 }330 *fmt = nextch;331 return (fmt);332 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034 nullターミネート
を元の文字に戻す
nextch:char == ‘]’
fmt:char *[%s]\n[%2.2f\0\n[%%]\n
! ! ![%s]\n[%2.2f]\n[%%]\n
157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;
doformat前のfmt:[%s]\n[%2.2f]\n[%%]\n
! ! から ! !
fmt:char *[%s]\n[%2.2f]\n[%%]\n
start:char *[%s]\n[%2.2f]\n[%%]\n
[abcde][1.03
2011年9月23日金曜日
149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout);152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
同様に進み
fmt:char *[%s]\n[%2.2f]\n[%%]\n
fm[%s]\n[%2.2f]\n[%%]\n
fwrite( start, // ]\n[%%... 1, // 1 fmt - start, // 3 stdout );
=> “]\n[“ を出力
[abcde][1.03][
2011年9月23日金曜日
149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout);152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
同様に進み
% 出力!
fmt:char *[%s]\n[%2.2f]\n[%%]\n
start:char *[%s]\n[%2.2f]\n[%%]\n
[abcde][1.03][%
2011年9月23日金曜日
149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout);152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }
171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
最後に
]\n 出力!
fmt:char *[%s]\n[%2.2f]\n[%%]\n?
start:char *[%s]\n[%2.2f]\n[%%]\n
[abcde][1.03][%]
2011年9月23日金曜日
149 while (fmt < format + len) {150 if (fmt[0] == '%') {151 fwrite(start, 1, fmt - start, stdout);152 if (fmt[1] == '%') {153 /* %% prints a % */154 putchar('%');155 fmt += 2;156 } else {157 fmt = doformat(fmt, &rval);158 if (fmt == NULL)159 return (1);160 end = 0;161 }162 start = fmt;163 } else164 fmt++;165 }
171 fwrite(start, 1, fmt - start, stdout);172 if (chopped || !*gargv)173 return (rval);
処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034
0を返して終了
[abcde][1.03][%]
2011年9月23日金曜日
おわり
2011年9月23日金曜日