diff options
Diffstat (limited to 'module')
-rw-r--r-- | module/Mk | 80 | ||||
-rw-r--r-- | module/errors.h | 11 | ||||
-rw-r--r-- | module/header.cmhg | 18 | ||||
-rw-r--r-- | module/menu.c | 618 | ||||
-rw-r--r-- | module/module.c | 192 | ||||
-rw-r--r-- | module/module.h | 24 | ||||
-rw-r--r-- | module/stubs.c | 102 |
7 files changed, 1045 insertions, 0 deletions
diff --git a/module/Mk b/module/Mk new file mode 100644 index 0000000..de88cbc --- /dev/null +++ b/module/Mk @@ -0,0 +1,80 @@ +# Old RISC OS makefile. This is of no real use now, but is retained +# so that the useful parts may be integrated into the cross-platform +# buildsystem at some later date + +TARGET = ^.!System.310.Modules.Iconv +VERSION = 008 +PVERSION = 0.0.8 +CC = cc +CFLAGS = -Wp -fnah -zM -fussy -ITCPIPLibs: +CFLAGSDEBUG = -DDEBUG -ITCPIPLibs: -Wnp -fn -fussy +LD = link +LDFLAGS = C:o.stubs TCPIPLibs:o.unixlibzm C:unicode.o.ucodelibm-no6937 +CMHG = cmhg -p +AR = libfile + +OBJECTS = eightbit.o header.o iconv.o alias.o aliases.o menu.o utils.o + +SOURCES = $(OBJECTS:.o=.c) +OBJS = $(OBJECTS:%.o=Release.%.o) +OBJSDEBUG = $(OBJECTS:%.o=Debug.%.o) + +all: setup $(TARGET) stubs + +debug: setup libiconv/a + +$(TARGET): $(OBJS) + $(LD) -RMF -o $@ $(LDFLAGS) $^ + @modsqz -f $@ + +stubs: Release.stubs.o + $(AR) -c -o ^.libiconv/a Release.o.stubs + @settype ^.libiconv/a fff + +libiconv/a: $(OBJSDEBUG) + $(AR) -c -o ^.libiconv/a Debug.o.eightbit Debug.o.iconv Debug.o.alias Debug.o.aliases Debug.o.menu Debug.o.utils ^.ucodelib.o.* + @settype ^.libiconv/a fff + +Release.header.o: + $(CMHG) cmhg.header -o $@ -d header.h + +Release.stubs.o: stubs.c + $(CC) -c -o $@ $(CFLAGS) $< + +Release.%.o: %.c + $(CC) -c -o $@ $(CFLAGS) $< + +Debug.header.o: + $(CMHG) cmhg.header -o $@ -d header.h + +Debug.%.o: %.c + $(CC) -c -o $@ $(CFLAGSDEBUG) $< + +setup: + -@cdir Release.o + -@cdir Debug.o + +clean: + -@wipe Release.o ~C~VFR + -@wipe Debug.o ~C~VFR + +distclean: clean + -@wipe ^.!System.310.Modules.Iconv ~C~VFR + -@wipe ^.libiconv/a ~C~VFR + +zip: all clean + -@dir ^ + -@wipe iconv$(VERSION)/zip ~C~VFR + -@zip -9r iconv$(VERSION)/zip !Boot !System libiconv/a ReadMe src doc + -@dir src + +pkg: all clean + -@dir ^ + -@wipe iconv$(VERSION)pkg ~C~VFR + -@copy !Boot.Resources.* pkg.Resources.* ~C~DF~L~N~P~QR~S~T~V + -@copy !System.* pkg.System.* ~C~DF~L~N~P~QR~S~T~V + -@copy Control pkg.RiscPkg.Control ~C~DF~L~N~P~QR~S~T~V + -sed -i -e s/VERSION/$(PVERSION)/ pkg/RiscPkg/Control + -@dir pkg + -@zip -9r ^.iconv$(VERSION)pkg * + -@dir ^.src diff --git a/module/errors.h b/module/errors.h new file mode 100644 index 0000000..a5995f5 --- /dev/null +++ b/module/errors.h @@ -0,0 +1,11 @@ +#ifndef _ICONV_ERRORS_H_ +#define _ICONV_ERRORS_H_ + +#define ERROR_BASE 0x81b900 + +#define ICONV_NOMEM (ERROR_BASE+0) +#define ICONV_INVAL (ERROR_BASE+1) +#define ICONV_2BIG (ERROR_BASE+2) +#define ICONV_ILSEQ (ERROR_BASE+3) + +#endif diff --git a/module/header.cmhg b/module/header.cmhg new file mode 100644 index 0000000..5f7fe5e --- /dev/null +++ b/module/header.cmhg @@ -0,0 +1,18 @@ +help-string: Iconv 0.08 + +title-string: Iconv + +initialisation-code: mod_init + +finalisation-code: mod_fini + +swi-chunk-base-number: 0x57540 + +swi-handler-code: swi_handler + +swi-decoding-table: Iconv, Open, Iconv, Close, Convert, CreateMenu, DecodeMenu + +command-keyword-table: command_handler + ReadAliases(min-args: 0, max-args: 0, + invalid-syntax: "Syntax: *ReadAliases", + help-text: "*ReadAliases rereads the encoding aliases file.\n") diff --git a/module/menu.c b/module/menu.c new file mode 100644 index 0000000..f42f505 --- /dev/null +++ b/module/menu.c @@ -0,0 +1,618 @@ +/* Encoding menu */ + +#include <ctype.h> +#ifdef MTEST +#include <stdio.h> +#endif +#include <stdlib.h> +#include <string.h> + +#include <unicode/charsets.h> +#include <unicode/encoding.h> + +#include "module.h" + +#define menu_HEADER_SIZE (28) +#define menu_ENTRY_SIZE (24) + +typedef struct _menu { + char head[menu_HEADER_SIZE]; /* We don't care about this */ + struct { + int menu_flags; + int *sub_menu; + int icon_flags; + struct { /* Only handle indirected text */ + char *text; + char *validation; + int size; + } indirected_text; + } entries[1]; +} wimp_menu; + +struct menu_desc { + char *title; + int n_entries; + const char *entries[1]; +}; + +#define menudesc(N) \ + struct { \ + char *title; \ + int n_entries; \ + char *entries[(N)]; \ + } + +/* Menu descriptions. + * A number of magic characters are permitted at the start of entry names: + * + * Character: Meaning: + * ^ Insert separator after this entry + * > Can open submenu, even if shaded + * {..} Has submenu, named ".." + * $ This entry is shaded + * + * Magic characters are examined in the order above. + * The submenu name is the title of the submenu. + * The first alphanumeric character is taken as the start of the entry name. + */ +static const char *val = ""; /* Validation string */ + +#define N_LATIN (30) +static const menudesc(N_LATIN) latin_menu = { + "Latin", N_LATIN, + { + "Western (ISO 8859-1: Latin-1)", + "Eastern (ISO 8859-2: Latin-2)", + "Southern (ISO 8859-3: Latin-3)", + "Nordic (ISO 8859-4: Latin-4)", + "Turkish (ISO 8859-9: Latin-5)", + "Nordic (ISO 8859-10: Latin-6)", + "Baltic rim (ISO 8859-13: Latin-7)", + "Celtic (ISO 8859-14: Latin-8)", + "^Western (ISO 8859-15: Latin-9)", + "Welsh (ISO-IR 182)", + "^Sami (ISO-IR 197)", + "Microsoft Latin-1 (CP1252)", + "Microsoft Latin-2 (CP1250)", + "Microsoft Baltic (CP1257)", + "^Microsoft Turkish (CP1254)", + "Apple Macintosh Roman", + "Apple Macintosh Croatian", + "Apple Macintosh Icelandic", + "Apple Macintosh Romanian", + "Apple Macintosh Turkish", + "^Apple Macintosh Central European", + "^Acorn Latin-1", + "DOS Latin-1 (CP850)", + "DOS Latin-2 (CP852)", + "DOS Baltic rim (CP775)", + "DOS Turkish (CP857)", + "DOS Portuguese (CP860)", + "DOS Icelandic (CP861)", + "DOS CanadaF (CP863)", + "DOS Nordic (CP865)", + } +}; + +#define N_ARABIC (4) +static const menudesc(N_ARABIC) arabic_menu = { + "Arabic", N_ARABIC, + { + "$ISO 8859-6", + "Microsoft Arabic (CP1256)", + "Apple Macintosh Arabic", + "DOS Arabic (CP864)", + } +}; + +#define N_CYRILLIC (10) +static const menudesc(N_CYRILLIC) cyrillic_menu = { + "Cyrillic", N_CYRILLIC, + { + "ISO 8859-5", + "KOI8-R", + "KOI8-RU", + "KOI8-T", + "^KOI8-U", + "^Microsoft Cyrillic (CP1251)", + "Apple Macintosh Cyrillic", + "^Apple Macintosh Ukrainian", + "DOS Cyrillic (CP855)", + "DOS Cyrillic Russian (CP866)", + } +}; + +#define N_GREEK (5) +static const menudesc(N_GREEK) greek_menu = { + "Greek", N_GREEK, + { + "ISO 8859-7", + "Microsoft Greek (CP1253)", + "Apple Macintosh Greek", + "DOS Greek (CP737)", + "DOS Greek2 (CP869)", + } +}; + +#define N_HEBREW (4) +static const menudesc(N_HEBREW) hebrew_menu = { + "Hebrew", N_HEBREW, + { + "ISO 8859-8", + "$Microsoft Hebrew (CP1255)", + "Apple Macintosh Hebrew", + "DOS Hebrew (CP862)", + } +}; + +#define N_CHINESE (3) +static const menudesc(N_CHINESE) chinese_menu = { + "Chinese", N_CHINESE, + { + "ISO 2022-CN", + "^GB 2312 (EUC-CN)", + "Big Five", + } +}; + +#define N_JAPANESE (3) +static const menudesc(N_JAPANESE) japanese_menu = { + "Japanese", N_JAPANESE, + { + "ISO 2022-JP", + "EUC-JP", + "Shift-JIS", + } +}; + +#define N_KOREAN (3) +static const menudesc(N_KOREAN) korean_menu = { + "Korean", N_KOREAN, + { + "ISO 2022-KR", + "EUC-KR", + "Johab", + } +}; + +#define N_THAI (3) +static const menudesc(N_THAI) thai_menu = { + "Thai", N_THAI, + { + "ISO 8859-11", + "Apple Macintosh Thai", + "DOS Thai (CP874)", + } +}; + +#define N_VIETNAMESE (1) +static const menudesc(N_VIETNAMESE) vietnamese_menu = { + "Vietnamese", N_VIETNAMESE, + { + "$Microsoft Vietnamese (CP1258)", + } +}; + +#define N_UNIVERSAL (4) +static const menudesc(N_UNIVERSAL) universal_menu = { + "Universal", N_UNIVERSAL, + { + "UTF-8 (ASCII-compatible)", + "UCS-2 / UTF-16 (16-bit)", + "^UCS-4 (31-bit)", + "ISO-2022", + } +}; + +#define N_ENC (11) +static const menudesc(N_ENC) enc_menu = { + "Encodings", N_ENC, + { + "^{Latin}Latin", + "{Arabic}Arabic", + "{Cyrillic}Cyrillic", + "{Greek}Greek", + "^{Hebrew}Hebrew", + "{Chinese}Chinese", + "{Japanese}Japanese", + "{Korean}Korean", + "{Thai}Thai", + "^>{Vietnamese}$Vietnamese", + "{Universal}Universal", + } +}; + +/* This struct is a lookup table between menu entries and charset numbers + * It is ordered as per the menus. */ +static const struct csmap { + short latin[N_LATIN]; + short arabic[N_ARABIC]; + short greek[N_GREEK]; + short hebrew[N_HEBREW]; + short cyrillic[N_CYRILLIC]; + short chinese[N_CHINESE]; + short japanese[N_JAPANESE]; + short korean[N_KOREAN]; + short thai[N_THAI]; + short vietnamese[N_VIETNAMESE]; + short universal[N_UNIVERSAL]; +} csmap = { + { csISOLatin1, csISOLatin2, csISOLatin3, csISOLatin4, csISOLatin5, + csISOLatin6, csISOLatin7, csISOLatin8, csISOLatin9, csWelsh, + csSami, csWindows1252, csWindows1250, csWindows1257, csWindows1254, + csMacintosh, 3019, 3022, 3023, 3025, csMacCentEuro, csAcornLatin1, + csPC850Multilingual, csPCp852, csPC775Baltic, csIBM857, csIBM860, + csIBM861, csIBM863, csIBM865 }, + { csISOLatinArabic, csWindows1256, 3018, csIBM864 }, + { csISOLatinGreek, csWindows1253, 3020, 3000, csIBM869 }, + { csISOLatinHebrew, csWindows1255, 3021, csPC862LatinHebrew }, + { csISOLatinCyrillic, csKOI8R, 3016, 3017, 2088, csWindows1251, + csMacCyrillic, csMacUkrainian, csIBM855, csIBM866 }, + { csISO2022CN, csGB2312, csBig5 }, + { csISO2022JP, csEUCPkdFmtJapanese, csShiftJIS }, + { csISO2022KR, csEUCKR, csJohab }, + { csISOLatinThai, 3024, 3004 }, + { csWindows1258 }, + { csUTF8, csUnicode11, csUCS4, csVenturaMath } +}; + +/* Sub menu lookup table - Must be sorted alphabetically */ +static const struct sub_menu { + char name[12]; + const struct menu_desc *desc; + const short *lut; +} sub_menus[] = { + { "Arabic", (const struct menu_desc *)&arabic_menu, + csmap.arabic }, + { "Chinese", (const struct menu_desc *)&chinese_menu, + csmap.chinese }, + { "Cyrillic", (const struct menu_desc *)&cyrillic_menu, + csmap.cyrillic }, + { "Greek", (const struct menu_desc *)&greek_menu, csmap.greek }, + { "Hebrew", (const struct menu_desc *)&hebrew_menu, + csmap.hebrew }, + { "Japanese", (const struct menu_desc *)&japanese_menu, + csmap.japanese }, + { "Korean", (const struct menu_desc *)&korean_menu, + csmap.korean }, + { "Latin", (const struct menu_desc *)&latin_menu, csmap.latin }, + { "Thai", (const struct menu_desc *)&thai_menu, csmap.thai }, + { "Universal", (const struct menu_desc *)&universal_menu, + csmap.universal }, + { "Vietnamese", (const struct menu_desc *)&vietnamese_menu, + csmap.vietnamese }, +}; +#define SUB_MENU_COUNT (sizeof(sub_menus) / sizeof(sub_menus[0])) + + + +#define MAX_SUBMENUS (16) /* Maximum number of submenus each menu can have */ + +#define MENU_COUNT_SIZE (0x00) +#define MENU_CREATE (0x01) +#define MENU_CLEAR_SELECTIONS (0x02) +/** + * Perform an operation on a menu + * + * \param d The description + * \param buf Location to write menu to + * \param parent Parent menu + * \param which Which parent entry this menu is linked from + * \param flags Flags word + * Bit: Meaning: + * 0 Create menu + * 1 Clear existing selections (charset != 0) + * \param charset Charset identifier of selected charset + * \param lut Selection lookup table + * \param data Location to write indirected data to + * \return Pointer to location after menu data + */ +static char *menu_op(const struct menu_desc *d, char *buf, + wimp_menu *parent, size_t which, size_t flags, + size_t charset, const short *lut, char **data) +{ + size_t e, top = 0; + struct { size_t e; const char *name; } submenus[MAX_SUBMENUS]; + char *bp = buf; + char *dp; + + if (data) + dp = *data; + + if (!buf && (flags & 0x02)) + return buf; + + if ((flags & MENU_CREATE)) { + /* copy menu title */ + strncpy(bp, d->title, 12); + bp += 12; + + /* colours */ + *bp++ = 7; *bp++ = 2; *bp++ = 7; *bp++ = 0; + + /* width, height, gap */ + *((int *)bp) = 200; bp += 4; + *((int *)bp) = 44; bp += 4; + *((int *)bp) = 0; bp += 4; + + memcpy(dp, val, strlen(val) + 1); + dp += strlen(val) + 1; + } else { + bp += menu_HEADER_SIZE; + dp += strlen(val) + 1; + } + + /* now the entries */ + for (e = 0; e != d->n_entries; e++) { + int menuf = 0, icon = (7 << 24) | 0x121; + const char *pos = 0; + + /* parse description string */ + for (pos = d->entries[e]; !isalnum(*pos); pos++) { + if (*pos == '^') + menuf |= 0x2; + else if (*pos == '>') + menuf |= 0x10; + else if (*pos == '{') { + if (top < MAX_SUBMENUS) { + submenus[top].e = e; + submenus[top++].name = pos+1; + } + while (*pos != '}') + pos++; + } + else if (*pos == '$') + icon |= (1<<22); + } + + if (e == d->n_entries - 1) + /* last item */ + menuf |= 0x80; + + if (charset != 0 && lut && lut[e] == charset) { + menuf |= 0x1; + if (parent) + parent->entries[which].menu_flags |= 0x1; + } + else + menuf &= ~0x1; + + if (flags & MENU_CLEAR_SELECTIONS) { + ((wimp_menu *)buf)->entries[e].menu_flags = menuf; + } + + if ((flags & MENU_CREATE)) { + *((int *)bp) = menuf; bp += 4; + *((int *)bp) = -1; bp += 4; + *((int *)bp) = icon; bp += 4; + *((int *)bp) = (int)(dp); bp += 4; + *((int *)bp) = (int)(*data); bp += 4; + *((int *)bp) = strlen(pos) + 1; bp += 4; + + memcpy(dp, pos, strlen(pos) + 1); + dp += strlen(pos) + 1; + } else { + bp += menu_ENTRY_SIZE; + dp += strlen(pos) + 1; + } + } + + /* fixup parent's pointer to this menu */ + if (parent && (flags & MENU_CREATE)) + parent->entries[which].sub_menu = (int *)buf; + + /* and recurse */ + for (e = 0; e < top; e++) { + struct sub_menu *s; + size_t len = (strchr(submenus[e].name, '}') - + submenus[e].name); + char child[len + 1]; + + strncpy(child, submenus[e].name, len); + child[len] = '\0'; + + s = bsearch(child, sub_menus, SUB_MENU_COUNT, + sizeof(sub_menus[0]), + (int (*)(const void *, const void *))strcmp); + if (s) + bp = menu_op(s->desc, bp, (wimp_menu *)buf, + submenus[e].e, flags, + charset, s->lut, &dp); + } + + if (data) + (*data) = dp; + + return bp; +} + +/** + * Iconv_CreateMenu SWI - Creates a menu structure of supported encodings + * + * \param flags Flags word - all reserved + * \param buf Pointer to buffer in which to store menu data, or NULL to + * read required buffer size. + * \param len Length of buffer, in bytes + * \param selected Pointer to name of selected encoding, or NULL if none + * \param data Pointer to buffer in which to store indirected data, or NULL + * to read required buffer size. + * \param dlen Pointer to length of data buffer, in bytes + * \return length of data written in buffer, or 0 if insufficient space + */ +size_t iconv_createmenu(size_t flags, char *buf, size_t len, + const char *selected, char *data, size_t *dlen) +{ + size_t reqlen, datalen; + char *bp = buf, *dp = NULL; + int sel = 0; + struct canon *c; + + UNUSED(flags); + + /* sanity check arguments */ + if ((!buf && data) || !dlen) + return 0; + + /* get required size */ + reqlen = (int)menu_op((const struct menu_desc *)&enc_menu, 0, + NULL, 0, MENU_COUNT_SIZE, 0, NULL, &dp); + + datalen = (size_t)dp; + + /* buffer length requested, so return it */ + if (!buf) { + *dlen = datalen; + return reqlen; + } + + /* insufficient room in buffer */ + if (reqlen > len) + return 0; + + /* Selected entry? */ + if (selected) { + sel = iconv_eightbit_number_from_name(selected) & ~(1<<30); + + if (!sel) { + c = alias_canonicalise(selected); + if (c) { + sel = encoding_number_from_name(c->name); + } + } + } + +#ifdef TEST + printf("selected: '%s' : %d\n", selected, sel); +#endif + + dp = data; + bp = menu_op((const struct menu_desc *)&enc_menu, buf, + NULL, 0, MENU_CREATE, sel, NULL, &dp); + + (*dlen) = datalen; + + return reqlen; +} + +/** + * Iconv_DecodeMenu SWI - Decodes a selection in a menu generated by + * Iconv_CreateMenu. + * + * \param flags Bitfield of flags - all reserved + * \param menu Menu definition + * \param selections Menu selections + * \param buf Pointer to output buffer, or NULL to read required length + * \param buflen Length of output buffer + * \return Required length of output buffer, or 0 if no selections + */ +size_t iconv_decodemenu(size_t flags, void *menu, int *selections, + char *buf, size_t buflen) +{ + const char *text, *t; + size_t len; + struct sub_menu *s; + + UNUSED(flags); + + if (!menu || !selections) + return 0; + + /* out of range */ + if (selections[0] == -1 || selections[0] >= enc_menu.n_entries) + return 0; + + /* Grab sub menu name */ + t = strchr(enc_menu.entries[selections[0]], '{') + 1; + len = (strchr(t, '}') - t); + + /* copy to temporary buffer */ + char child[len + 1]; + strncpy(child, t, len); + child[len] = '\0'; + + /* look for submenu */ + s = bsearch(child, sub_menus, SUB_MENU_COUNT, sizeof(sub_menus[0]), + (int (*)(const void *, const void *))strcmp); + if (!s) + return 0; + + if (selections[1] == -1 || selections[1] >= s->desc->n_entries) + return 0; + + /* lookup encoding name from number */ + text = mibenum_to_name(s->lut[selections[1]]); + + /* not found */ + if (!text) + return 0; + +#ifdef MTEST + printf("%p : '%s'\n", text, text); +#endif + + if (buf && buflen < strlen(text) + 1) + /* insufficient buffer space */ + return 0; + + + if (buf) { + strcpy(buf, text); + buf[strlen(text)] = '\0'; + } + + menu_op((const struct menu_desc *)&enc_menu, menu, NULL, 0, + MENU_CLEAR_SELECTIONS, s->lut[selections[1]], + NULL, NULL); + + return strlen(text) + 1; +} + + +#ifdef MTEST +int main(void) +{ + int len, slen, dlen; + char *buf, *dbuf, *selected; + int selection[3] = { 0, 5, -1}; + + if (!create_alias_data("Unicode:Files.Aliases")) + return 1; + + + len = iconv_createmenu(0, 0, 0, 0, 0, (size_t *)&dlen); + + buf = calloc(len, sizeof(char)); + if (!buf) + return 1; + + dbuf = calloc(dlen, sizeof(char)); + if (!dbuf) + return 1; + + printf("%p: %d\n", buf, iconv_createmenu(0, buf, len, "UTF-16", + dbuf, (size_t *)&dlen)); + + FILE *fp = fopen("$.dump", "w"); + fwrite(buf, len, sizeof(char), fp); + fclose(fp); + + fp = fopen("$.dump1", "w"); + fwrite(dbuf, dlen, sizeof(char), fp); + fclose(fp); + + slen = iconv_decodemenu(0, (wimp_menu*)buf, selection, 0, 0); + + selected = calloc(slen, sizeof(char)); + if (!selected) + return 1; + + printf("%p: %d\n", selected, iconv_decodemenu(0, (wimp_menu*)buf, + selection, selected, slen)); + + printf("'%s'\n", selected); + + free_alias_data(); + + return 0; +} +#endif 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: + } +} + diff --git a/module/module.h b/module/module.h new file mode 100644 index 0000000..09dcfeb --- /dev/null +++ b/module/module.h @@ -0,0 +1,24 @@ +#ifndef iconv_module_h_ +#define iconv_module_h_ + +#ifndef DEBUG +#define LOG(x) +#else +#define LOG(x) (printf(__FILE__ " %s %i: ", __func__, __LINE__), printf x, fputc('\n', stdout)) +#endif + +#define UNUSED(x) ((x) = (x)) + +/* In iconv library */ +extern int iconv_eightbit_number_from_name(const char *name); +extern short mibenum_from_name(const char *alias); +extern const char *mibenum_to_name(short mibenum); + +/* in menu.c */ +size_t iconv_createmenu(size_t flags, char *buf, size_t buflen, + const char *selected, char *data, size_t *dlen); +size_t iconv_decodemenu(size_t flags, void *menu, int *selections, + char *buf, size_t buflen); + +#endif + diff --git a/module/stubs.c b/module/stubs.c new file mode 100644 index 0000000..96dee4b --- /dev/null +++ b/module/stubs.c @@ -0,0 +1,102 @@ +/* Iconv stubs */ + +#include <errno.h> + +#include <sys/errno.h> + +#include "swis.h" + +#include "errors.h" /* for error numbers */ +#include "header.h" /* for SWI numbers */ +#include "iconv.h" + +iconv_t iconv_open(const char *tocode, const char *fromcode) +{ + iconv_t ret; + _kernel_oserror *error; + + error = _swix(Iconv_Open, _INR(0,1) | _OUT(0), tocode, fromcode, &ret); + if (error) { + switch (error->errnum) { + case ICONV_NOMEM: + errno = ENOMEM; + break; + case ICONV_INVAL: + errno = EINVAL; + break; + case ICONV_2BIG: + errno = E2BIG; + break; + case ICONV_ILSEQ: + errno = EILSEQ; + break; + default: + errno = EINVAL; /* munge BAD_SWI to EINVAL */ + break; + } + return (iconv_t)(-1); + } + + return ret; +} + +size_t iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, + size_t *outbytesleft) +{ + size_t ret; + _kernel_oserror *error; + + error = _swix(Iconv_Iconv, _INR(0,4) | _OUT(0), cd, inbuf, inbytesleft, outbuf, outbytesleft, &ret); + if (error) { + switch (error->errnum) { + case ICONV_NOMEM: + errno = ENOMEM; + break; + case ICONV_INVAL: + errno = EINVAL; + break; + case ICONV_2BIG: + errno = E2BIG; + break; + case ICONV_ILSEQ: + errno = EILSEQ; + break; + default: + errno = EINVAL; /* munge BAD_SWI to EINVAL */ + break; + } + return (size_t)(-1); + } + + return ret; +} + +int iconv_close(iconv_t cd) +{ + int ret; + _kernel_oserror *error; + + error = _swix(Iconv_Close, _IN(0) | _OUT(0), cd, &ret); + if (error) { + switch (error->errnum) { + case ICONV_NOMEM: + errno = ENOMEM; + break; + case ICONV_INVAL: + errno = EINVAL; + break; + case ICONV_2BIG: + errno = E2BIG; + break; + case ICONV_ILSEQ: + errno = EILSEQ; + break; + default: + errno = EINVAL; /* munge BAD_SWI to EINVAL */ + break; + } + return -1; + } + + return ret; +} |