/* 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

  /* Undef USE_TML to use a debug file 'TMLDebug' in PipeFS rather */
  /* than the TML card output routines.                            */

  #define USE_TML

  #ifdef USE_TML

    /* -*-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

    /* Make Printf use a PipeFS file instead of outputting to a TML card. */
    /* Because the routine calls fopen then fclose to avoid needing any   */
    /* initialisation or finalisation calls, do something like:           */
    /*                                                                    */
    /* REPEAT:OSCLI "Type Pipe:$.TMLDebug":UNTIL FALSE                    */
    /*                                                                    */
    /* in a Task Window to list the output during run-time (assuming this */
    /* was for a multitasking Wimp application). It isn't ideal, but it   */
    /* works out as better than nothing.                                  */
    /*                                                                    */
    /* History:                                                           */
    /*                                                                    */
    /* 11/08/97 (ADH): Created                                            */

    #include <stdlib.h>
    #include <stdarg.h>
    #include <stdio.h>

    void Printf(char * format, ...)
    {
      va_list   ptr;
      FILE    * fp;

      #define Debug_FileName "Devices:Parallel"

      fp = fopen(Debug_FileName, "wab");
      if (!fp) fp = fopen(Debug_FileName, "wb");
      if (!fp) return;

      setvbuf(fp, NULL, _IONBF, 0);

      va_start(ptr, format);
      vfprintf(fp, format, ptr);
      va_end(ptr);

      fclose(fp);
    }

  #endif

#else

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

#endif