/*
 * このファイルのコードは、TINETに含まれる netapp_subr.c から
 * 抜き出し、変更したものを使用しています。
 */
/*
 *  TINET (TCP/IP Protocol Stack)
 * 
 *  Copyright (C) 2001-2009 by Dep. of Computer Science and Engineering
 *                   Tomakomai National College of Technology, JAPAN
 *
 *  上記著作権者は，以下の (1)〜(4) の条件か，Free Software Foundation 
 *  によって公表されている GNU General Public License の Version 2 に記
 *  述されている条件を満たす場合に限り，本ソフトウェア（本ソフトウェア
 *  を改変したものを含む．以下同じ）を使用・複製・改変・再配布（以下，
 *  利用と呼ぶ）することを無償で許諾する．
 *  (1) 本ソフトウェアをソースコードの形で利用する場合には，上記の著作
 *      権表示，この利用条件および下記の無保証規定が，そのままの形でソー
 *      スコード中に含まれていること．
 *  (2) 本ソフトウェアを，ライブラリ形式など，他のソフトウェア開発に使
 *      用できる形で再配布する場合には，再配布に伴うドキュメント（利用
 *      者マニュアルなど）に，上記の著作権表示，この利用条件および下記
 *      の無保証規定を掲載すること．
 *  (3) 本ソフトウェアを，機器に組み込むなど，他のソフトウェア開発に使
 *      用できない形で再配布する場合には，次の条件を満たすこと．
 *    (a) 再配布に伴うドキュメント（利用者マニュアルなど）に，上記の著
 *        作権表示，この利用条件および下記の無保証規定を掲載すること．
 *  (4) 本ソフトウェアの利用により直接的または間接的に生じるいかなる損
 *      害からも，上記著作権者およびTOPPERSプロジェクトを免責すること．
 *
 *  本ソフトウェアは，無保証で提供されているものである．上記著作権者お
 *  よびTOPPERSプロジェクトは，本ソフトウェアに関して，その適用可能性も
 *  含めて，いかなる保証も行わない．また，本ソフトウェアの利用により直
 *  接的または間接的に生じたいかなる損害に関しても，その責任を負わない．
 * 
 *  @(#) $Id: netapp_subr.c,v 1.5 2009/12/24 05:44:56 abe Exp abe $
 */

/* 
 *  ネットワーク応用プログラムサポートルーチン
 */

#include <stdarg.h>
#include <string.h>

#include <s_services.h>
#include <t_services.h>
#include "kernel_id.h"

typedef signed int		int_t;		/* 自然なサイズの符号付き整数 */
typedef unsigned int		uint_t;		/* 自然なサイズの符号無し整数 */

typedef signed long		long_t;		/* 長めのサイズの符号付き整数 */
typedef unsigned long		ulong_t;	/* 長めのサイズの符号無し整数 */

typedef int			bool_t;		/* 真偽値 */

#ifndef true
#define true			1		/* 真 */
#endif /* true */

#ifndef false
#define false			0		/* 偽 */
#endif /* false */

/*
 *  シリアルポートへの書式付文字列出力ライブラリ
 */

#define EOF		(-1)

/*
 *  数値変換のための変換表
 */

const char radhex[] = "0123456789abcdef";
const char radHEX[] = "0123456789ABCDEF";

void
cons_putstring(char *str)
{
	cons_write(str, strlen(str));
}

/*
 *  cons_putchar -- シリアルポートへの文字出力
 */

void
cons_putchar (char ch)
{
	if (ch == '\n')
	    cons_write("\r\n", 2);
	else
	    cons_write(&ch, 1);
	}

/*
 *  cons_putnumber -- cons_printf の数値変換
 */

int_t
cons_putnumber(ulong_t 	val, int_t radix,
         const char *radchar, int_t width, bool_t minus, char padchar)
{
	char	digits[24];
	int_t	ix, pad, pchars;
	bool_t	left;

	if (width < 0) {
		width = -width;
		left = true;
		}
	else
		left = false;

	ix = 0;
	do {
		digits[ix ++] = radchar[val % radix];
		val /= radix;
		} while (val != 0);

	if (minus)
		digits[ix ++] = '-';

	if (width > ix)
		pchars = width;
	else
		pchars = ix;

	pad = ix;
	if (!left)	/* 右詰め */
		for ( ; pad < width; pad ++)
			cons_putchar(padchar);

	while (ix -- > 0)
		cons_putchar(digits[ix]);

	if (left)	/* 左詰め */
		for ( ; pad < width; pad ++)
			cons_putchar(padchar);

	return pchars;
	}

/*
 *  cons_printf -- シリアルポートへの書式付文字列出力
 */

void
cons_printf (const char *fmt, ...)
{
	va_list	ap;
	long_t	val;
	char	padchar, *str;
	int_t	ch, width, longflag, left;

	va_start(ap, fmt);
	while ((ch = *fmt ++) != '\0') {
		if (ch != '%') {		/* 書式指定以外 */
			cons_putchar((char)ch);
			continue;
			}

		width = longflag = 0;
		padchar = ' ';

		if (ch == '-') {		/* 左詰め */
			fmt ++;
			left = -1;
			}
		else
			left = 1;

		if ((ch = *fmt ++) == '0') {	/* 上位桁の 0 */
			padchar = '0';
			ch = *fmt ++;
			}

		while ('0' <= ch && ch <= '9') {	/* 出力幅 */
			width = width * 10 + ch - '0';
			ch = *fmt ++;
			}

		while (ch == 'l') {		/* long (long) の指定 */
			longflag ++;
			ch = *fmt ++;
			}

		switch (ch) {
		case 'd':
			val = longflag ? (ulong_t)va_arg(ap, long_t)
			               : (ulong_t)va_arg(ap, int_t);
			if (val >= 0)
				cons_putnumber(val, 10, radhex, width * left, false, padchar);
			else
				cons_putnumber(-val, 10, radhex, width * left, true, padchar);
			break;

		case 'u':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
			cons_putnumber(val, 10, radhex, width * left, false, padchar);
			break;

		case 'x':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
			cons_putnumber(val, 16, radhex, width * left, false, padchar);
			break;

		case 'X':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
			cons_putnumber(val, 16, radHEX, width * left, false, padchar);
			break;

		case 'c':
			ch = va_arg(ap, int_t);
			cons_putchar((char)ch);
			break;

		case 's':
			str = va_arg(ap, char*);
			while ((ch = *str ++) != '\0') {
				cons_putchar((char)ch);
				width --;
				}
			while (width -- > 0)
				cons_putchar(' ');
			break;

		case '%':
			cons_putchar('%');
			break;

		case '0':
			fmt --;
			break;

		default:
			break;
			}

		}
	va_end(ap);
	}

int
str_putnumber(char **bp, ulong_t 	val, int_t radix,
         const char *radchar, int_t width, bool_t minus, char padchar)
{
        char    digits[24];
        int     ix, pad, pchars;
        BOOL    left;
	char *sp = *bp;

        if (width < 0) {
                width = -width;
                left = TRUE;
	} else
                left = FALSE;

        ix = 0;
        do {
                digits[ix ++] = radchar[val % radix];
                val /= radix;
	} while (val != 0);

        if (minus)
                digits[ix ++] = '-';

        if (width > ix)
                pchars = width;
        else
                pchars = ix;

	pad = ix;
        if (!left)      /* right adjust */
                for ( ; pad < width; pad ++)
			*sp++ = padchar;

        while (ix -- > 0)
                *sp++ = digits[ix];

        if (left)       /* left adjust */
                for ( ; pad < width; pad ++)
                        *sp++ = padchar;
	*sp = '\0';
	*bp = sp;

        return pchars;
}

char *
str_printf (char *buffp, const char *fmt, ...)
{
        va_list ap;
        long_t val;
        char    padchar, *str;
        int     ch, width, longflag, left;
	UW addr;

        va_start(ap, fmt);
        while ((ch = *fmt ++) != '\0') {
                if (ch != '%') {                /* 書式指定以外 */
                        *buffp++ = (char)ch;
                        continue;
		}

                width = longflag = 0;
                padchar = ' ';

                if (ch == '-') {                /* 左詰め */
                        fmt ++;
                        left = -1;
		} else
                        left = 1;

                if ((ch = *fmt ++) == '0') {    /* 上位桁の 0 */
                        padchar = '0';
                        ch = *fmt ++;
		}

                while ('0' <= ch && ch <= '9') {        /* 出力幅 */
                        width = width * 10 + ch - '0';
                        ch = *fmt ++;
		}

                while (ch == 'l') {             /* long (long) の指定 */
                        longflag ++;
                        ch = *fmt ++;
		}

                switch (ch) {
                case 'd':
			val = longflag ? (ulong_t)va_arg(ap, long_t)
			               : (ulong_t)va_arg(ap, int_t);
                        if (val >= 0)
                                str_putnumber(&buffp, val, 10, radhex, width * left, FALSE, padchar);
                        else
                                str_putnumber(&buffp, -val, 10, radhex, width * left, TRUE, padchar);
                        break;

                case 'u':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
                        str_putnumber(&buffp, val, 10, radhex, width * left, FALSE, padchar);
                        break;

                case 'x':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
                        str_putnumber(&buffp, val, 16, radhex, width * left, FALSE, padchar);
                        break;

                case 'X':
			val = longflag ? (ulong_t)va_arg(ap, ulong_t)
			               : (ulong_t)va_arg(ap, uint_t);
                        str_putnumber(&buffp, val, 16, radHEX, width * left, FALSE, padchar);
                        break;

                case 'c':
                        ch = va_arg(ap, int);
			*buffp++ = (char) ch;
                        break;

                case 's':
                        str = va_arg(ap, char*);
                        while ((ch = *str ++) != '\0') {
				*buffp++ = (char)ch;
                                width --;
			}
                        while (width -- > 0)
				*buffp++ = ' ';
                        break;

                case '%':
                        *buffp++ = '%';
                        break;

                case '0':
                        fmt --;
                        break;

                default:
                        break;
		}
	}
	*buffp = '\0';
        va_end(ap);
	return buffp;
}
