秀丸マクロで sprintf の実装

秀丸マクロで sprintf の実装をしてみました。はじめは どう書く?orgお題:printfの自作 )に投稿するつもりで作っていたのですがさすがに長いので投稿するのはやめておきます。

sprintfToString で 数値を unsigned として扱って文字列化 を秀丸マクロに移植して無理やり一つのサブルーチンにまとめたソースが使われています。

ソースをもっと綺麗にしたいところ。

    call sprintf "[%s][%c][%%][%d][%x][%o][%u][%b]", "String", '#', 123, 0xabc, 511, 0xffffffff, 96;
    message $$return;
    endmacro;

sprintf:
    $$format = $$1;
    $$arg[0]=$$2;$$arg[1]=$$3;$$arg[2]=$$4;$$arg[3]=$$5;$$arg[4]=$$6;$$arg[5]=$$7;$$arg[6]=$$8;$$arg[7]=$$9;
    ##arg[0]=##2;##arg[1]=##3;##arg[2]=##4;##arg[3]=##5;##arg[4]=##6;##arg[5]=##7;##arg[6]=##8;##arg[7]=##9;
    $$dest = "";
    ##argIndex = 0;
    while( $$format != "" ) {
        ##search = strstr( $$format, "%" );
        if( ##search == -1 ) {
            $$dest = $$dest + $$format;
            break;
        }
        $$dest = $$dest + leftstr( $$format, ##search );
        $$format = rightstr( $$format, strlen( $$format ) - ##search );
        $$_format = $$format;
        $$format = rightstr( $$format, strlen( $$format ) - strlen( "%" ) );

        $$fmt = $$format;
        ##specifiedArgIndex = -1;
        while( ( ascii( $$fmt ) >= '0' ) && ( ascii( $$fmt ) <= '9' ) ) {
            $$fmt = rightstr( $$fmt, strlen( $$fmt ) - strlen( char( ascii( $$fmt ) ) ) );
        }
        if( ( ascii( $$fmt ) == '$' ) && ( strlen( $$format ) != strlen( $$fmt ) ) ) {
            ##specifiedArgIndex = val( leftstr( $$format, strlen( $$format ) - strlen( $$fmt ) ) ) - 1;
            $$format = rightstr( $$fmt, strlen( $$fmt ) - strlen( "$" ) );
        }

        $$fmt = $$format;
        while( strstr( " #'+-0", char( ascii( $$fmt ) ) ) >= 0 ) {
            $$fmt = rightstr( $$fmt, strlen( $$fmt ) - 1 );
        }
        $$flag = leftstr( $$format, strlen( $$format ) - strlen( $$fmt ) );
        $$format = $$fmt;

        ##width = 0;
        if( ascii( $$format ) == '*' ) {
            $$format = rightstr( $$format, strlen( $$format ) - strlen( "*" ) );
            $$fmt = $$format;
            while( ( ascii( $$fmt ) >= '0' ) && ( ascii( $$fmt ) <= '9' ) ) {
                $$fmt = rightstr( $$fmt, strlen( $$fmt ) - strlen( char( ascii( $$fmt ) ) ) );
            }
            if( ( ascii( $$fmt ) == '$' ) && ( strlen( $$format ) != strlen( $$fmt ) ) ) {
                ##width = ##arg[ val( leftstr( $$format, strlen( $$format ) - strlen( $$fmt ) ) ) - 1 ];
                $$format = rightstr( $$fmt, strlen( $$fmt ) - strlen( "$" ) );
            } else {
                ##width = ##arg[##argIndex];
                ##argIndex = ##argIndex + 1;
            }
        } else {
            while( ( ascii( $$format ) >= '0' ) && ( ascii( $$format ) <= '9' ) ) {
                ##width = ##width * 10 + ( ascii( $$format ) - '0' );
                $$format = rightstr( $$format, strlen( $$format ) - 1 );
            }
        }
        if( ##width < 0 ) {
            $$flag = $$flag + "-";
            ##width = -##width;
        }

        ##accuracy = -1;
        if( ascii( $$format ) == '.' ) {
            $$format = rightstr( $$format, strlen( $$format ) - strlen( "." ) );
            if( ascii( $$format ) == '*' ) {
                $$format = rightstr( $$format, strlen( $$format ) - strlen( "*" ) );
                $$fmt = $$format;
                while( ( ascii( $$fmt ) >= '0' ) && ( ascii( $$fmt ) <= '9' ) ) {
                    $$fmt = rightstr( $$fmt, strlen( $$fmt ) - strlen( char( ascii( $$fmt ) ) ) );
                }
                if( ( ascii( $$fmt ) == '$' ) && ( strlen( $$format ) != strlen( $$fmt ) ) ) {
                    ##accuracy = ##arg[ val( leftstr( $$format, strlen( $$format ) - strlen( $$fmt ) ) ) - 1 ];
                    $$format = rightstr( $$fmt, strlen( $$fmt ) - strlen( "$" ) );
                } else {
                    ##accuracy = ##arg[##argIndex];
                    ##argIndex = ##argIndex + 1;
                }
            } else {
                ##nextchar = ascii( midstr( $$format, 1, 1 ) );
                if( ( ascii( $$format ) == '-' ) && ( ##nextchar >= '0' ) && ( ##nextchar <= '9' ) ) {
                    $$format = rightstr( $$format, strlen( $$format ) - strlen( "-" ) );
                }
                ##accuracy = 0;
                while( ( ascii( $$format ) >= '0' ) && ( ascii( $$format ) <= '9' ) ) {
                    ##accuracy = ##accuracy * 10 + ( ascii( $$format ) - '0' );
                    $$format = rightstr( $$format, strlen( $$format ) - 1 );
                }
            }
            if( ##accuracy < 0 ) {
                ##accuracy = 0;
            }
        }

        ##conversionSpecifier = 0;
        if( strstr( "diouxXbBcs%", char( ascii( $$format ) ) ) >= 0 ) {
            ##conversionSpecifier = ascii( $$format );
            $$format = rightstr( $$format, strlen( $$format ) - 1 );
        }

        if ( ##conversionSpecifier == 0 ) {
            $$dest = $$dest + leftstr( $$_format, strlen( $$_format ) - strlen( $$format ) );
        } else if( ##conversionSpecifier == '%' ) {
            $$dest = $$dest + "%";
        } else {
            if( ##specifiedArgIndex >= 0 ) {
                ##arg = ##arg[##specifiedArgIndex];
                $$arg = $$arg[##specifiedArgIndex];
            } else {
                ##arg = ##arg[##argIndex];
                $$arg = $$arg[##argIndex];
                ##argIndex = ##argIndex + 1;
            }
            call sprintfConvert ##arg, $$arg, $$flag, ##width, ##accuracy, ##conversionSpecifier;
            $$dest = $$dest + $$return;
        }
    }
    return $$dest;

sprintfConvert:
    ##arg = ##1;
    $$arg = $$2;
    $$flag = $$3;
    ##width = ##4;
    ##accuracy = ##5;
    ##conversionSpecifier = ##6;
    while( $$flag != "" ) {
        ##flag[ascii( $$flag )] = true;
        $$flag = rightstr( $$flag, strlen( $$flag ) - 1 );
    }

    if( ##conversionSpecifier == 'c' ) {
        $$converted = char( ##arg );
    } else if( ##conversionSpecifier == 's' ) {
        if( ##accuracy >= 0 ) {
            $$converted = leftstr( $$arg, ##accuracy );
        } else {
            $$converted = $$arg;
        }
    } else if( strstr( "diuoxXbB", char( ##conversionSpecifier ) ) >= 0 ) {
        ##signed = ( ( strstr( "di", char( ##conversionSpecifier ) ) >= 0 ) || ##flag['+'] || ##flag[' '] );
        if( ##signed ) {
            ##isNegative = ( ##arg < 0 );
            if( ##isNegative ) {
                ##arg = -##arg;
            }
        }
        $$prefix = "";
        if( ( ##flag['#'] ) && ( ##arg != 0 ) ) {
            if( strstr( "xX", char( ##conversionSpecifier ) ) >= 0 ) {
                $$prefix = "0X" + $$prefix;
            } else if( strstr( "bB", char( ##conversionSpecifier ) ) >= 0 ) {
                $$prefix = "0B" + $$prefix;
            }
        }
        if( ##signed ) {
            ##sign = 0;
            if( ##isNegative ) {
                ##sign = '-';
            } else if( ##flag['+'] ) {
                ##sign = '+';
            } else if( ##flag[' '] ) {
                ##sign = ' ';
            }
            $$prefix = char( ##sign ) + $$prefix;
        }
        if( strstr( "xX", char( ##conversionSpecifier ) ) >= 0 ) {
            ##radix = 16;
        } else if( ##conversionSpecifier == 'o' ) {
            ##radix = 8;
        } else if( strstr( "bB", char( ##conversionSpecifier ) ) >= 0 ) {
            ##radix = 2;
        } else {
            ##radix = 10;
        }
        if( ( ##accuracy == 0 ) && ( ##arg == 0 ) ) {
            $$converted = "";
        } else {
            call sprintfToString ##arg, ##radix;
            $$converted = $$return;
        }
        ##i = 0;
        if( ##accuracy >= 0 ) {
            ##i = ##accuracy - strlen( $$converted );
        } else if( ##flag['0'] && ( !##flag['-'] ) ) {
            ##i = ##width - strlen( $$converted ) - strlen( $$prefix );
        }
        while( ##i > 0 ) {
            $$converted = "0" + $$converted;
            ##i = ##i - 1;
        }
        if( ( ##conversionSpecifier == 'o' ) && ( ##flag['#'] ) && ( ascii( $$converted ) != '0' ) ) {
            $$converted = "0" + $$converted;
        }
        if( ( strstr( "diu", char( ##conversionSpecifier ) ) >= 0 ) && ##flag['\''] ) {
            ##i = strlen( $$converted ) - 3;
            while( ##i > 0 ) {
                $$converted = leftstr( $$converted, ##i ) + "'" + rightstr( $$converted, strlen( $$converted ) - ##i );
                ##i = ##i - 3;
            }
            if( ##flag['0'] && ( ##accuracy < 0 ) && ( !##flag['-'] ) ) {
                if( ##i == 0 ) {
                    $$converted = "'" + $$converted;
                }
                while( ( strlen( $$converted ) + strlen( $$prefix ) > ##width ) && ( strstr( "0'", leftstr( $$converted, 1 ) ) >= 0 ) ) {
                    $$converted = rightstr( $$converted, strlen( $$converted ) - 1 );
                }
            }
        }
        $$converted = $$prefix + $$converted;
        if( strstr( "xb", char( ##conversionSpecifier ) ) >= 0 ) {
            $$converted = tolower( $$converted );
        }
    }
    ##i = ##width - strlen( $$converted );
    $$space = "";
    while( ##i > 0 ) {
        $$space = $$space + " ";
        ##i = ##i - 1;
    }
    if( ##flag['-'] ) {
        $$converted = $$converted + $$space;
    } else {
        $$converted = $$space + $$converted;
    }

    return $$converted;

sprintfToString:
    $$digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    ##x = ##1;
    ##radix = ##2;
    ##val = ##x & 0x7fffffff;
    while( true ) {
        $$y = "";
        while( true ) {
            ##digit = ##val % ##radix;
            if( ##digit < 0 ) ##digit = -##digit;
            $$y = midstr( $$digits, ##digit, 1 ) + $$y;
            ##val = ##val / ##radix;
            if( ##val == 0 ) break;
        }
        if( ##x >= 0 ) break;
        if( strlen( $$x ) > 0 ) break;
        $$x = $$y;
        ##val = 0x80000000;
    }
    if( ##x >= 0 ) return $$y;
    ##xindex = strlen( $$x ) - 1;
    ##yindex = strlen( $$y ) - 1;
    ##kuri = 0;
    while( ( ##xindex >= 0 ) || ( ##yindex >= 0 ) || ( ##kuri != 0 ) ) {
        ##xval = 0;
        ##yval = 0;
        if( ##xindex >= 0 ) ##xval = strstr( $$digits, midstr( $$x, ##xindex, 1 ) );
        if( ##yindex >= 0 ) ##yval = strstr( $$digits, midstr( $$y, ##yindex, 1 ) );
        ##val  = ##xval + ##yval + ##kuri;
        ##kuri = ##val / ##radix;
        ##val  = ##val % ##radix;
        $$dest = midstr( $$digits, ##val, 1 ) + $$dest;
        ##xindex = ##xindex - 1;
        ##yindex = ##yindex - 1;
    }
    return $$dest;

インフォメーション

公開日時
2007年12月6日 午後10時26分16秒
最終更新日時
2007年12月20日 午後10時31分45秒
カテゴリ
秀丸エディタ