/* Copyright 1997 Acorn Computers Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifdef TRACE

  /* -*-C-*-
   *
   * Copyright(c) 1994 Acorn Computers Ltd., Cambridge, England
   *
   * svcprint.c
   *
   * print debugging information down the TML tube link.
   *
   * provides:
   *	     %s - string
   *	     %C - character in range 20->7F (space printed if outside range)
   *	     %c - any character
   *	     %X - reverses order of bytes if >2 (or >4) specified as width
   *	     %x - hex
   *	     %B - reverses order of bytes if >2 (or >4) specified as width
   *	     %b - binary
   *	     %D - reverses order of bytes if >2 (or >4) specified as width
   *	     %d - decimal
   *	     %p - pointer ("@xxxxxxxx")
   *
   * field width can be specified by placing a decimal number after the "%"
   * character... if the width is started by a "0" then numbers are padded
   * with "0"...
   *
   * standard format specifiers o,u,e,f and g are NOT supported
   *
   */

  #include "kernel.h"
  #include "swis.h"
  #include "svcprint.h"

  #include "inetlib.h"

  #ifndef NULL
  # define NULL	((void *)0)
  #endif

  #ifdef DEBUG
  /*int debug = 1;*/
  #endif

  /**********************************************************************/

  /*
   * call processor mode independant character output routine
   */
  static void oswrch(unsigned char ch)
  {
      _kernel_swi_regs regset;

      /*
       * use HostFS_WriteC (SWI 0x40102) to print the character
       */
      regset.r[0] = ch;
      (void)_kernel_swi(0x40102, &regset, &regset);
  }

  /**********************************************************************/

  /*
   * Printn prints a number n in base b, minimum width w adding pad chars
   * if needed.
   */
  static void printn(unsigned n, unsigned b, int w, char pad)
  {
      if( n >= b )
      {
  	printn(n / b, b, --w, pad);
  	oswrch("0123456789abcdef"[n % b]);
      }
      else
      {
  	while (--w > 0)
  	    oswrch(pad);

  	oswrch("0123456789abcdef"[n]);
      }
  }

  /**********************************************************************/

  static void prf(char *format, unsigned *argp, ...)
  {
      register int b; /* base to be used when displaying numbers */
      register int c; /* current character read from format string */
      register int w; /* field width */
      char pad;	    /* field padding character */
      unsigned val;   /* value of argument */

    loop:
      val = *argp;
      w = 0;
      pad = ' ';

      while( (c = *format++) != '%' )
      {
  	if( c == '\0' )
  	    return;
  	if( c == '\n' )
  	    oswrch('\r');
  	oswrch(c);
      }

    again:
      /*
       * we have a special format command
       */
      c = *format++;
      switch( c )
      {
        case 's':
  	{
  	    /* string */
  	    char *p = (char *)*argp++;
  	    int	 width = 0;

  	    if (p != NULL)
  	    {
  		/* NOT a NULL pointer */
  		while (*p)
  		{
  		    oswrch(*p++);
  		    width++;
  		}
  	    }

  	    while( width++ < w )
  		oswrch(' ');
  	    goto loop;
  	}

        case 'C':
  	if( (*argp < ' ') || (*argp > '~') )
  	{
  	    oswrch(' ');
  	    argp++;
  	    goto loop;
  	}

        case 'c':
  	/* character */
  	oswrch(*argp++);
  	goto loop;

        case '0':
  	if (w == 0)
  	    pad = '0';

        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
  	/* field width */
  	w = (w * 10) + ((int) c - '0');
  	goto again;

        case 'X':
  	/* hex number */
  	if (w > 4)
  	    val = (unsigned)ntohl(val);
  	else
  	{
  	    if (w > 2)
  		val = (unsigned)ntohs(val);
  	}

  	/*
  	 * NB
  	 *
  	 * fall through to set base
  	 */

        case 'x':
  	/* hex number */
  	b = 16;
  	goto number;

        case 'p':
        	/* pointer */
        	oswrch('@');
        	w = 8;
        	pad = '0';
        	b = 16;
        	goto number;

        case 'B':
  	/* binary number */
  	if (w > 4)
  	    val = (unsigned)ntohl(val);
  	else
  	{
  	    if( w > 2 )
  		val = (unsigned)ntohs(val);
  	}

  	/*
  	 * NB
  	 *
  	 * fall through to set base
  	 */

        case 'b':
  	/* binary number */
  	b = 2;
  	goto number;

        case 'D':
  	/* decimal number */
  	if (w > 4)
  	    val = (unsigned)ntohl(val);
  	else
  	{
  	    if (w > 2)
  		val = (unsigned)ntohs(val);
  	}

  	/*
  	 * NB
  	 *
  	 * fall through to set base
  	 */

        case 'd':
  	b = 10;
  	/*
  	 * NB
  	 *
  	 * fall through to write number
  	 */

        number:
  	printn(val,b,w,pad);
  	argp++;

  	break;
      } /* switch */

      goto loop;
  }


  /**********************************************************************/

  #if 0
  # define USETUBE
  #endif /* 0/1 */

  void Printf(char *format, ...)
  {
      unsigned *argp = (unsigned *)&format;
      static int inprf;

  #ifdef USETUBE
      _kernel_swi_regs reglist;
      _kernel_oserror *err;
  /*     int s = splhi(); */

      if( (err = _kernel_swi(0x40100, &reglist, &reglist)) != NULL )
      {
  	prf("HostVDU: ", 0);
  	prf(err->errmess, 0);
  /*	splx(s); */
  	return;
      }
  #endif /* USETUBE */

      /*int s = splhi();*/
      if (inprf)
          return;

      inprf=1;
      prf(format, (argp + 1));
      inprf=0;
      /*splx(s);*/

  #ifdef USETUBE
      if( (err = _kernel_swi(0x40101, &reglist, &reglist)) != NULL )
      {
  	prf("TubeVDU: ", 0);
  	prf(err->errmess, 0);
  /*	splx(s); */
  	return;
      }
  /*    splx(s); */
  #endif /* USETUBE */
  }


  /**********************************************************************/

  /* EOF svcprint.c */

#else

  void svcprint_keep_compiler_happy(void)
  {
    int a;
    a = 0;
  }

#endif