/* Copyright 1996 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.
 */
/*riscos.c - useful functions for windowing applications*/

/*From CLib*/
#include <stdarg.h>
#include <stdio.h>
#include <string.h>

/*From OSLib*/
#include "messagetrans.h"
#include "macros.h"
#include "os.h"
#include "territory.h"
#include "wimp.h"

/*From Support*/
#include "m.h"
#include "riscos.h"
#include "trace.h"

#ifndef BOOTCMDS
static char *Decimal_Point = ".";
static int Decimal_Point_Len = 1;
#endif

#ifndef BOOTCMDS
static os_error *Error_Lookup (int errnum, char *token, va_list list)

{  char *p [4];
   int i;
   os_error error;

   tracef ("Error_Lookup (%d, %s)\n" _ errnum _ token);

   /*Assume that 4 args are always given.*/
   for (i = 0; i < 4; i++) p [i] = va_arg (list, char *);

   error.errnum = errnum;
   riscos_strcpy (error.errmess, token);

   return xmessagetrans_error_lookup (&error, NULL,
         NULL, 0, p [0], p [1], p [2], p [3]);
}
#endif
#ifndef BOOTCMDS
/*------------------------------------------------------------------------*/
os_error *riscos_territory (territory_t t)

{  os_error *error = NULL;

   /*Fix MED-3471: use "." if there is no territory yet. A correct
      application will call this function again if the territory changes.
      JRC 12th Dec 1994*/
   if (xterritory_read_string_symbols (t, territory_SYMBOL_DECIMAL_POINT,
         &Decimal_Point) != NULL)
      Decimal_Point = ".";

   Decimal_Point_Len = strlen (Decimal_Point);

/*finish:*/
   return error;
}
/*------------------------------------------------------------------------*/
os_error *riscos_error_lookup (int errnum, char *token, ...)

{  va_list list;
   os_error *error;

   tracef ("riscos_error_lookup (%d, %s)\n" _ errnum _ token);

   va_start (list, token);
   error = Error_Lookup (errnum, token, list);
   va_end (list);

   return error;
}
#endif
#if TRACE
/*------------------------------------------------------------------------*/
void riscos__assert (char *file, int line, char *msg)

{  os_error error;
   int len;

   tracef ("riscos__assert\n");

   error.errnum = 1;
   sprintf (error.errmess, "\"%.*s\", line %d: %n",
         sizeof error.errmess - 11 - UNSIGNED_WIDTH - 1, file, line, &len);
   riscos_strncpy (&error.errmess [len], msg, os_ERROR_LIMIT - len - 1);

   (void) xwimp_report_error (&error, wimp_ERROR_BOX_SHORT_TITLE,
         "Assertion failure", NULL);
}
#endif
/*------------------------------------------------------------------------*/
int riscos_strlen (char *s)

  /* Calculates the length of a string in the traditional RiSC O S way.
   */

{  int l = 0;

   while (s [l] >= ' ')
      l++;

   return l;
}
#ifndef BOOTCMDS
/*------------------------------------------------------------------------*/
char *riscos_strcpy (char *s1, char *s)

  /* Copy a string in the traditional RiSC O S way.
   */

{  int i = 0;

   while ((s1 [i] = s [i]) >= ' ')
      i++;
   s1 [i] = '\0';

   return s1;
}
#endif
#ifndef BOOTCMDS
/*------------------------------------------------------------------------*/
int riscos_strcmp (char *s0, char *s1)

  /* Compares 2 traditional RiSC O S strings.
   */

{  tracef ("riscos_strcmp (\"%.*s\", \"%.*s\")\n" _
         riscos_strlen (s0) _ s0 _ riscos_strlen (s1) _ s1);

   for (;;)
   {  char c0 = *s0++, c1 = *s1++;

      if (c0 < ' ')
         if (c1 < ' ')
            return (tracef ("-> 0\n"), 0);
         else
            return (tracef ("-> -1\n"), -1);
      else
         if (c1 < ' ')
            return (tracef ("-> 1\n"), 1);
         else
            if (c0 != c1) return (tracef ("-> %d\n" _ c0 - c1), c0 - c1);
   }
}
#endif
/*------------------------------------------------------------------------*/
char *riscos_strncpy (char *s1, char *s, int n)

 /* Copy a RISC O S string of limited length, like
  * sprintf (s1, "%.*s", MIN (n, riscos_strlen (s)), s);
  */

{  int i;

   /*Copy up to |n| characters of the string*/
   for (i = 0; s [i] >= ' ' && i < n; i++)
      s1 [i] = s [i];

   /*Append a terminator.*/
   s1 [i] = '\0';

   return s1;
}
#ifndef BOOTCMDS
/*------------------------------------------------------------------------*/
char *riscos_format_dec (char *s, int i, int width, int prec)

{  tracef ("riscos_format_dec (%d)\n" _ i);

   if (sprintf (s, "%*.*d", width, prec, i) < 1)
      CLEAR (s);

   return s;
}
#ifndef PICKER
/*------------------------------------------------------------------------*/
char *riscos_format_hex (char *s, int i, int width, int prec)

{  tracef ("riscos_format_hex (0x%X)\n" _ i);

   if (sprintf (s, "%*.*X", width, prec, i) < 1)
      CLEAR (s);

   return s;
}
#endif
/*------------------------------------------------------------------------*/
char *riscos_format_char (char *s, char c)

{  tracef ("riscos_format_char ('%c')\n" _ c);

   if (sprintf (s, "%c", c) < 1)
      CLEAR (s);

   return s;
}
/*------------------------------------------------------------------------*/
char *riscos_format_fixed (char *s, int mul, int div, int width, int prec)

   /*Like |sprintf (s, "*.*f", width, prec, mul/div)|, but using integers
      only. |Div| must be > 0.*/

{  int i, scale;

   tracef ("riscos_format_fixed (%d/%d)\n" _ mul _ div);

   scale = 1;
   for (i = 0; i < prec; i++) scale *= 10;

   i = SGN (mul)*((unsigned) ABS (mul)/div);

   if (prec > 0)
   {  int f = (scale*ABS (mul)/div)%scale;

      if (sprintf (s, "%*d%s%*.*d\n", MAX (width - prec - 1, 0), i,
            Decimal_Point, prec, prec, f) < 2)
         CLEAR (s);
   }
   else
   {  if (sprintf (s, "%*d\n", width, i) < 1)
         CLEAR (s);
   }

   return s;
}
/*------------------------------------------------------------------------*/
int riscos_scan_dec (char *s, int *i_out)

{  int i, width;

   tracef ("riscos_scan_dec\n");

   if (sscanf (s, "%d%n", &i, &width) < 1)
      return 0;

   if (i_out != NULL) *i_out = i;
   return width;
}
#endif
#ifndef BOOTCMDS
#ifndef PICKER
/*------------------------------------------------------------------------*/
int riscos_scan_hex (char *s, int *i_out)

{  int i, width;

   tracef ("riscos_scan_hex\n");

   if (sscanf (s, "%x%n", &i, &width) < 1)
      return 0;

   if (i_out != NULL) *i_out = i;
   return width;
}
#endif
#endif
#ifndef BOOTCMDS
/*------------------------------------------------------------------------*/
int riscos_scan_fixed (char *s, int *mul_out, int div)

{  int mul = 0, place, sgn = 1;
   char *cc = s;

   tracef ("riscos_scan_fixed (s \"%s\", div %d)\n" _ s _ div);

   /*Skip leading spaces.*/
   cc += strspn (s, " \t\xA0");
      /*Fix MED-4986: '\n' is a terminator! J R C 16th Mar 1995*/

   if (*cc == '-') sgn = -1, cc++;

   for (; ISDIGIT (*cc); cc++)
      mul = 10*mul + DIGIT (*cc);

   tracef ("SGN %d, INT %d\n" _ sgn _ mul);
   mul *= div;

   if (strncmp (cc, Decimal_Point, Decimal_Point_Len) == 0)
      cc += Decimal_Point_Len;

   /*Add in the fractional part too.*/
   for (place = 10; ISDIGIT (*cc); cc++, place *= 10)
      mul += div*DIGIT (*cc)/place;
   tracef ("MUL %d\n" _ mul);

   if (mul_out != NULL) *mul_out = sgn*mul;
   return cc - s;
}
#endif