/* 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.
 */
/* File:    messages.c
 * Purpose: accessing an Object modules messages file (inc error reporting)
 * Author:  Timothy Roddis
 * History: 24-Jan-94: IDJ: created from original TGR sources
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "kernel.h"
#include "swis.h"

#include "const.h"
#include "macros.h"
#include "objects.toolbox.h"
#include "services.h"
#include "debug.h"
#include "mem.h"
#include "twimp.h"
#include "style.h"

#include "messages.h"

static int             messages_fd[4];                     /* the messages file descriptor */
static _kernel_oserror global_error_block={0,0};



/* ------------------------------------ raising errors ---------------------------------------- */


extern _kernel_oserror *make_error (int err_num, int num_args, ...)
{
   /*
    * Generate a RISC OS error block.
    */

   va_list           ap;
   char             *s,
                     token [4];
   int               i=4;
   _kernel_oserror  *e;
   _kernel_swi_regs  regs = {0,0,0,0,0,0,0,0};

   global_error_block.errnum = err_num;

   num_args = (num_args>4)?4:num_args;

   for (va_start (ap, num_args); num_args--; i++)
   {
      s         = va_arg (ap, char *);
      regs.r[i] = (int) ((s && *s) ? s : NULL); /* copy (pointer to args)s into registers */
   }

   sprintf (token, "E%02x", err_num&0x3f);

   DEBUG debug_output ("error", "make_error: looking for %s\n", token);

   regs.r[0] = (int) messages_fd;
   regs.r[1] = (int) token;
   regs.r[2] = (int) global_error_block.errmess;
   regs.r[3] = sizeof global_error_block - sizeof global_error_block.errnum; /* 252! */

   e = _kernel_swi (MessageTrans_Lookup, &regs, &regs); /* Hope this doesn't return an error */

   DEBUG
   {
      if (e != NULL) debug_output ("error", "make_error: msgtrans error (%s)\n", e->errmess);
   }

   va_end (ap);

   return &global_error_block;
}



extern _kernel_oserror *make_error_hex (int err_num, int num_args, ...)
{
   /*
    * Generate a RISC OS error block, with integer params printed in hex.
    */

   va_list           ap;
   char              arg[4][11] = { "\0","\0","\0","\0" };
   int               i,
                     n;

   num_args = (num_args>4)?4:num_args;
   va_start (ap, num_args);

   for (i=0; i<num_args; i++)
   {
      n = va_arg (ap, int);
      sprintf (arg[i], "0x%x",n);
   }

   va_end(ap);

   return make_error (err_num, num_args, arg[0], arg[1], arg[2], arg[3]);
}



extern void raise_toolbox_error (int err_num, ObjectID object_id, ComponentID component_id, int num_args, ...)
{
   /*
    * Raise a Toolbox_Error event
    */

   ToolboxErrorEvent error_block;

   va_list           ap;
   char             *s,
                     token [4];
   int               i=4;
   _kernel_oserror  *e;
   _kernel_swi_regs  regs = {0,0,0,0,0,0,0,0};

   error_block.errnum = err_num;

   num_args = (num_args>4)?4:num_args;

   for (va_start (ap, num_args); num_args--; i++)
   {
      s         = va_arg (ap, char *);
      regs.r[i] = (int) ((s && *s) ? s : NULL); /* copy (pointer to args)s into registers */
   }

   regs.r[0] = (int) messages_fd;
   regs.r[1] = (int) token;
   regs.r[2] = (int) error_block.errmess;
   regs.r[3] = sizeof global_error_block - sizeof global_error_block.errnum; /* 252! */

   e = _kernel_swi (MessageTrans_Lookup, &regs, &regs); /* Hope this doesn't return an error */

   error_block.hdr.event_code = Toolbox_Error;

   regs.r[0] = 0;
   regs.r[1] = (int) object_id;
   regs.r[2] = component_id;
   regs.r[3] = (int) &error_block;

   e = _kernel_swi (Toolbox_RaiseToolboxEvent, &regs, &regs);

   va_end (ap);
}



extern void raise_toolbox_error_hex (int err_num, ObjectID object_id, ComponentID component_id, int num_args, ...)
{
   /*
    * Raise a Toolbox_Error event, with integer parameters printed in hex
    */

   va_list           ap;
   char              arg[4][11] = { "\0","\0","\0","\0" };
   int               i=0,
                     n;

   num_args = (num_args>4)?4:num_args;
   va_start (ap, num_args);

   for (i=0; i<num_args; i++)
   {
      n = va_arg (ap, int);
      sprintf (arg[i], "0x%x",n);
   }

   raise_toolbox_error_hex (err_num, object_id, component_id, num_args, arg[0], arg[1], arg[2], arg[3]);

   va_end(ap);
}



extern void raise_toolbox_oserror (_kernel_oserror *e, ObjectID object_id, ComponentID component_id)
{
   /*
    * Raise a Toolbox_Error event, given a RISC OS error block
    */

   ToolboxErrorEvent error_block;
   _kernel_swi_regs  regs;

   error_block.errnum = e->errnum;
   strcpy (error_block.errmess, e->errmess);

   error_block.hdr.event_code = Toolbox_Error;
   error_block.hdr.size       = 256-20-sizeof(ToolboxEventHeader)-sizeof(ObjectID)-sizeof(ComponentID);

   regs.r[0] = 0;
   regs.r[1] = (int) object_id;
   regs.r[2] = component_id;
   regs.r[3] = (int) &error_block;

   e = _kernel_swi (Toolbox_RaiseToolboxEvent, &regs, &regs);
}


/* --------------------------------------- message file handling ------------------------------ */


extern _kernel_oserror *messages_file_open (char *messages_filename)
{
    _kernel_swi_regs regs;

    regs.r[0] = (int)messages_fd;
    regs.r[1] = (int)messages_filename;
    regs.r[2] = 0;   /* use RMA */
    return _kernel_swi(MessageTrans_OpenFile, &regs, &regs);
}


extern _kernel_oserror *messages_file_close (void)
{
    _kernel_swi_regs regs;

    regs.r[0] = (int)messages_fd;
    return _kernel_swi (MessageTrans_CloseFile, &regs, &regs);

}


extern _kernel_oserror *messages_file_lookup (char *token, char *buffer, int *buffer_size, int num_args, ...)
{
   va_list           ap;
   char             *s;
   int               i    = 4;
   _kernel_oserror  *e    = NULL;
   _kernel_swi_regs  regs = {0,0,0,0,0,0,0,0};

   num_args = (num_args>4)?4:num_args;

   for (va_start (ap, num_args); num_args--; i++)
   {
      s         = va_arg (ap, char *);
      regs.r[i] = (int) ((s && *s) ? s : NULL); /* copy (pointer to args)s into registers */
   }

   regs.r[0] = (int) messages_fd;
   regs.r[1] = (int) token;
   regs.r[2] = (int) buffer;
   regs.r[3] = (buffer && buffer_size)?*buffer_size:0;

   e = _kernel_swi (MessageTrans_Lookup, &regs, &regs); /* Hope this doesn't return an error */

   if (buffer == NULL && buffer_size != NULL)
       *buffer_size = regs.r[3]+1;   /* add one to allow for terminator */

   va_end (ap);

   return e;
}