Printf

40
printf @akitsukada 2011923日金曜日

description

コマンドなんでも読書会用資料

Transcript of Printf

Page 1: Printf

printf@akitsukada

2011年9月23日金曜日

Page 2: Printf

まず

読んだ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日金曜日

Page 3: Printf

man は PRINTF(1)の方

PRINTF(3)はC言語のいわゆるprintf()

シェルのコマンドprintfはPRINTF(1)

man “歴史”より

printf は、4.3BSD-Reno で登場しました。それは標準ライブラリ関数printf(3)をモデルにしています。

2011年9月23日金曜日

Page 4: Printf

使い方おさらい

printf format [arguments ...]

format

普通の文字列

エスケープシーケンス

フラグ&フォーマット文字

arguments

formatのフォーマット文字にあてはめる値

2011年9月23日金曜日

Page 5: Printf

エスケープシーケンス\a <ベル> 文字を書きます。

\b <バックスペース> 文字を書きます。

\c この文字列中の残りの文字を無視します。

\f <フォームフィード> 文字を書きます。

\n <改行> 文字を書きます。

\r <復帰> 文字を書きます。

\t <タブ> 文字を書きます。

\v <垂直タブ> 文字を書きます。

\' <シングルクォート> 文字を書きます。

\\ <バックスラッシュ> 文字を書きます。

\num 文字コード を指定

\0num 1 から 3 桁の 8 進数 num で表される ASCII コードの 8 ビット文字を書きます。

2011年9月23日金曜日

Page 6: Printf

フラグ&フォーマット文字

フラグ

“#” 数値を‘別形式’で表示します

“-” 指定したフィールド幅で左詰め

“+” 符号付きフォーマットのとき左端に符号をつけます

“ ” 符号付きフォーマットのとき左をスペースでパディングします正の数のときは符号なし 負の数のときは符号付です(e.g.[ -1])

“0” スペースでなく0でパディングします負の数のとき、スペースと違って符号が一番左にきます(e.g.[-0001])

2011年9月23日金曜日

Page 7: Printf

フラグ&フォーマット文字

フォーマット文字(%に続く文字)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日金曜日

Page 8: Printf

フラグ&フォーマット文字

フォーマット文字の処理については実質的にC言語のasprintfに任せるだけ

与えられた %hoge の記述を一つずつL75~L90の関数型マクロPFに渡すことが このprintf(1)の仕事

2011年9月23日金曜日

Page 9: Printf

処理を追う$ printf "[%s]\n[%2.2f]\n[%%]\n" abcdf 1.034[abcdf][1.03][%]

2011年9月23日金曜日

Page 10: Printf

処理を追う$ 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日金曜日

Page 11: Printf

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日金曜日

Page 12: Printf

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日金曜日

Page 13: Printf

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日金曜日

Page 14: Printf

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日金曜日

Page 15: Printf

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日金曜日

Page 16: Printf

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日金曜日

Page 17: Printf

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日金曜日

Page 18: Printf

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日金曜日

Page 19: Printf

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日金曜日

Page 20: Printf

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日金曜日

Page 21: Printf

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日金曜日

Page 22: Printf

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日金曜日

Page 23: Printf

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日金曜日

Page 24: Printf

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日金曜日

Page 25: Printf

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日金曜日

Page 26: Printf

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日金曜日

Page 27: Printf

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日金曜日

Page 28: Printf

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日金曜日

Page 29: Printf

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日金曜日

Page 30: Printf

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日金曜日

Page 31: Printf

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日金曜日

Page 32: Printf

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日金曜日

Page 33: Printf

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日金曜日

Page 34: Printf

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日金曜日

Page 35: Printf

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日金曜日

Page 36: Printf

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日金曜日

Page 37: Printf

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日金曜日

Page 38: Printf

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日金曜日

Page 39: Printf

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日金曜日

Page 40: Printf

おわり

2011年9月23日金曜日