summaryrefslogtreecommitdiff
path: root/module/module.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/module.c')
-rw-r--r--module/module.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/module/module.c b/module/module.c
new file mode 100644
index 0000000..ef2a5da
--- /dev/null
+++ b/module/module.c
@@ -0,0 +1,192 @@
+/* Iconv module interface */
+
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/errno.h>
+
+#include <iconv/iconv.h>
+
+#include "swis.h"
+
+#include "errors.h"
+#include "header.h"
+#include "module.h"
+
+#define ALIASES_FILE "Unicode:Files.Aliases"
+
+static _kernel_oserror ErrorGeneric = { 0x0, "" };
+
+static size_t iconv_convert(_kernel_swi_regs *r);
+static int errno_to_iconv_error(int num);
+
+/* Module initialisation */
+_kernel_oserror *mod_init(const char *tail, int podule_base, void *pw)
+{
+ UNUSED(tail);
+ UNUSED(podule_base);
+ UNUSED(pw);
+
+ /* ensure the !Unicode resource exists */
+ if (!getenv("Unicode$Path")) {
+ strncpy(ErrorGeneric.errmess, "!Unicode resource not found.",
+ 252);
+ return &ErrorGeneric;
+ }
+
+ if (iconv_initialise(ALIASES_FILE) == false) {
+ strncpy(ErrorGeneric.errmess, "Unicode:Files.Aliases not "
+ "found. Please read the Iconv installation "
+ "instructions.", 252);
+ return &ErrorGeneric;
+ }
+
+ return NULL;
+}
+
+/* Module finalisation */
+_kernel_oserror *mod_fini(int fatal, int podule_base, void *pw)
+{
+ UNUSED(fatal);
+ UNUSED(podule_base);
+ UNUSED(pw);
+
+ iconv_finalise();
+
+ return NULL;
+}
+
+/* SWI handler */
+_kernel_oserror *swi_handler(int swi_off, _kernel_swi_regs *regs, void *pw)
+{
+ unsigned int ret;
+
+ UNUSED(pw);
+
+ if (swi_off > 5)
+ return error_BAD_SWI;
+
+ switch (swi_off) {
+ case 0: /* Iconv_Open */
+ if ((ret = (unsigned int)
+ iconv_open((const char*)regs->r[0],
+ (const char*)regs->r[1])) == -1) {
+ ErrorGeneric.errnum = errno;
+ return &ErrorGeneric;
+ }
+ regs->r[0] = ret;
+ break;
+ case 1: /* Iconv_Iconv */
+ if ((ret = (unsigned int)
+ iconv((iconv_t)regs->r[0],
+ (char**)regs->r[1],
+ (size_t*)regs->r[2],
+ (char**)regs->r[3],
+ (size_t*)regs->r[4])) == -1) {
+ ErrorGeneric.errnum = errno;
+ return &ErrorGeneric;
+ }
+ regs->r[0] = ret;
+ break;
+ case 2: /* Iconv_Close */
+ if ((ret = (unsigned int)
+ iconv_close((iconv_t)regs->r[0])) == -1) {
+ ErrorGeneric.errnum = errno;
+ return &ErrorGeneric;
+ }
+ regs->r[0] = ret;
+ break;
+ case 3: /* Iconv_Convert */
+ if ((ret = (unsigned int)
+ iconv_convert(regs)) == -1) {
+ ErrorGeneric.errnum = errno;
+ return &ErrorGeneric;
+ }
+ regs->r[0] = ret;
+ break;
+ case 4: /* Iconv_CreateMenu */
+ {
+ size_t dlen = regs->r[5];
+ regs->r[2] = iconv_createmenu(regs->r[0],
+ (char *)regs->r[1],
+ regs->r[2],
+ (const char *)regs->r[3],
+ (char *)regs->r[4],
+ &dlen);
+ regs->r[5] = dlen;
+ }
+ break;
+ case 5: /* Iconv_DecodeMenu */
+ regs->r[4] = iconv_decodemenu(regs->r[0],
+ (void *)regs->r[1],
+ (int *)regs->r[2],
+ (char *)regs->r[3], regs->r[4]);
+ break;
+ }
+
+ return NULL;
+}
+
+/* *command handler */
+_kernel_oserror *command_handler(const char *arg_string, int argc,
+ int cmd_no, void *pw)
+{
+ UNUSED(arg_string);
+ UNUSED(argc);
+ UNUSED(pw);
+
+ switch (cmd_no) {
+ case CMD_ReadAliases:
+ free_alias_data();
+ if (!create_alias_data(ALIASES_FILE)) {
+ strcpy(ErrorGeneric.errmess,
+ "Failed reading Aliases file.");
+ return &ErrorGeneric;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+size_t iconv_convert(_kernel_swi_regs *regs)
+{
+ char *inbuf, *outbuf;
+ size_t inbytesleft, outbytesleft;
+ size_t ret;
+
+ inbuf = (char *)regs->r[1];
+ inbytesleft = (size_t)regs->r[2];
+ outbuf = (char *)regs->r[3];
+ outbytesleft = (size_t)regs->r[4];
+
+ ret = iconv((iconv_t)regs->r[0], &inbuf, &inbytesleft,
+ &outbuf, &outbytesleft);
+
+ regs->r[1] = (int)inbuf;
+ regs->r[2] = (int)inbytesleft;
+ regs->r[3] = (int)outbuf;
+ regs->r[4] = (int)outbytesleft;
+
+ return ret;
+}
+
+int errno_to_iconv_error(int num)
+{
+ switch (num) {
+ case ENOMEM:
+ return ICONV_NOMEM;
+ case E2BIG:
+ return ICONV_2BIG;
+ case EILSEQ:
+ return ICONV_ILSEQ;
+ case EINVAL:
+ default:
+ return ICONV_INVAL:
+ }
+}
+