recodeg.c0100644000076600007660000000664007657142534011346 0ustar ivanivan/* The recode table creator for multiply translations Copyright (C) 1999 Lev Levitin Systemizing document and system-known charset names. Enhancements. Copyright (C) 2000-2003 Ivan Zakharyaschev */ /*#define FDEBUG*/ #include #include #include #include "recodeg.h" #include #include struct Chain * recodeg_rules(void) { static struct Chain * global_rules = NULL; return global_rules ? : (global_rules = chain_createEmpty()); } /* We do not need this function -- will pass the selected rules as an argument in the place where the pipe is created. */ #if 0 #ifdef FDEBUG #include #endif MultipleConverter *recodeg_pipe(void) { #ifdef FDEBUG MultipleConverter * result; fprintf(stderr, __FUNCTION__ " start\n"); result = multiple_conv_open(rules()->first); fprintf(stderr, __FUNCTION__ ": unused %d\n", ((SingleConverter *)result->first->value)->inbuf); return result; #else return multiple_conv_open(recodeg_rules()->first); #endif } #endif /* 0 */ #include int recodeg_addrule(const char *from, const char *to) { return addRecodeRule(recodeg_rules(), from, to); } void recodeg_dellast(void) { dellastRecodeRule(recodeg_rules()); } void recodeg_delall(void) { delallRecodeRules(recodeg_rules()); } char * recodeg_info(void) { return infoOnRecodeRules(recodeg_rules()); } int recodeg_used(void) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif return ! chain_isEmpty(recodeg_rules()); } static int auto_recode = 1;; int recodeg_auto(void) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif return auto_recode; } void recodeg_setauto(int flag) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif auto_recode = flag; } #ifdef RECODEG_PINE #include "headers.h" void recodeg_autosolve(BODY *body) { char *charset = rfc2231_get_param(body->parameter, "charset", NULL, NULL); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif recodeg_delall(); if(!charset) return; if( strucmp(charset, "us-ascii") && ps_global->VAR_CHAR_SET && strucmp(charset, ps_global->VAR_CHAR_SET)) { recodeg_addrule(charset, ps_global->VAR_CHAR_SET); } fs_give((void **)&charset); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ " ret\n"); #endif } #endif char * recodeg_validcharset(char * const in_charset) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (recodeg_used()) { const char * const our_charset = ((const struct RecodeRule *)chain_last(recodeg_rules()))->to; fs_give((void **) &in_charset); return my_fs_dup(our_charset); } else return in_charset; } const char * recodeg_validcharset_static(const char * const in_charset) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (recodeg_used()) { const char * const our_charset = ((const struct RecodeRule *)chain_last(recodeg_rules()))->to; return our_charset; } else return in_charset; } /* Utility functions not related to recoding directly; */ char * my_fs_dup(const char * const S) { const size_t l = strlen(S); char * const copy = fs_get( (l+1) * sizeof(char) ); copy[l] = '\0'; strncpy(copy, S, l); return copy; } char * my_fs_move(const char * const S) { char * const copy = my_fs_dup(S); free((char*)S); return copy; } recodeg.h0100644000076600007660000000216407657142534011350 0ustar ivanivan/* Recode Global interface: interface to information about recoding for the whole process. Copyright (C) 2001-2003 Ivan Zakharyaschev It is similar to the interface defined by Lev. The recode table creator for multiply translations Copyright (C) 1999 Lev Levitin */ #ifndef _RECODEG_H #define _RECODEG_H /* Utility functions not related to recoding directly; */ char * my_fs_dup(const char * S); char * my_fs_move(const char * S); #include struct Chain * recodeg_rules(void); int recodeg_addrule(const char *from, const char *to); void recodeg_dellast(void); void recodeg_delall(void); int recodeg_used(void); int recodeg_auto(void); void recodeg_setauto(int flag); char * recodeg_info(void); char * recodeg_validcharset(char *in_charset); const char * recodeg_validcharset_static(const char *in_charset); #ifdef RECODEG_PINE /* This was added for PINE */ #include "headers.h" void gf_recode(FILTER_S *, int); int cmd_recode PROTO((struct pine *)); void recodeg_autosolve(BODY *body); #define MC_RECODE 1000 #define MC_FMTSAVE 1001 #endif #endif my_util/0042755000076600007660000000000010200441725011231 5ustar ivanivanmy_util/Makefile0100644000076600007660000000070707400222671012675 0ustar ivanivanCPPFLAGS += -D_GNU_SOURCE #CPPFLAGS += -DDEBUG CFLAGS += -Wall objs = lists.o chains.o buffers.o lib = libmy_util.a $(lib): $(objs) clean:: -$(RM) $(objs) %.a: $(AR) rc $@ $^ clean:: -$(RM) $(lib) ###################################### # Various types of Cleaning clean_cores:: -$(RM) *core clean_after_emacs:: -$(RM) *'~' -$(RM) '#'*'#' distclean:: clean clean_after_emacs clean_cores # End of Cleaning section ######################## my_util/LICENSE0100644000076600007660000000076407377703677012274 0ustar ivanivan(Public domain) The permission to use, compile, modify, copy and ditribute this code in any form is given to anyone. Anyone can put his own distribution terms on a code derived from this. I advise you to keep all the copyright notices and contributors' names in your derived work based on this code. No one is allowed to use the names of the copyright holders and contributors for purposes different from stating that they are the copyright holders and contributors without their permission. my_util/buffers.c0100644000076600007660000000706607656453273013063 0ustar ivanivan#include "buffers.h" /* Do not care about the maximum length of buffers: */ #define BUFFER_MAXLEN 0 /* A buffer grows by this number of bytes each time */ #define BUFFER_GROWSTEP 57 #include #include struct CharBuffer * buffer_createEmpty(void) { static const struct CharBuffer INITIAL = { (char*)NULL, (char*)NULL, (char*)NULL, (size_t)0 }; struct CharBuffer * const result = malloc(sizeof(struct CharBuffer)); #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (result) memcpy(result, &INITIAL, sizeof(struct CharBuffer)); return result; } struct CharBuffer * buffer_createMinimal(void) { struct CharBuffer * result = buffer_createEmpty(); #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (result) if (! buffer_grow(result)) { free(result); result = NULL; } #ifdef DEBUG fprintf(stderr, __FUNCTION__ "ret unused %d\n", result->unused); #endif return result; } void buffer_destroy(struct CharBuffer * const buf) { if (buf->bulk) free(buf->bulk); free(buf); } #undef MIN #define MIN(a,b) ( ( (a) < (b) ) ? (a) : (b) ) size_t buffer_grow(struct CharBuffer * const buf) { size_t len = buf->after_used - buf->bulk + buf->unused; size_t step = BUFFER_GROWSTEP; size_t gap = buf->used - buf->bulk; #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (gap) { memmove(buf->bulk, buf->used, buffer_used_len(buf)); buf->used = buf->bulk; buf->after_used -= gap; buf->unused += gap; step -= gap; } if (! step) return BUFFER_GROWSTEP; if ( ! BUFFER_MAXLEN || ( len < BUFFER_MAXLEN ) ) { /* the buffer grows until it's BUFFER_MAXLEN bytes long */ char * new; step = (! BUFFER_MAXLEN) ? step : MIN(step, BUFFER_MAXLEN - len); len += step; new = realloc(buf->bulk, len * sizeof(char)); if (new) { buf->after_used = new + (buf->after_used - buf->bulk); buf->used = buf->bulk = new; buf->unused += step; #ifdef DEBUG fprintf(stderr, __FUNCTION__ " ret %d\n", step); #endif return step; } else return 0; } } short int buffer_putc(struct CharBuffer * const buf, const char c) { return (buffer_puts(buf, &c, 1) != (size_t)0); } size_t buffer_puts(struct CharBuffer * const buf, const char * s, size_t s_len) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": unused %d, used_len %d\n", buf->unused, buffer_used_len(buf)); #endif while ( (buf->unused < s_len) && buffer_grow(buf) ); strncpy(buf->after_used, s, buf->unused); buf->unused -= (s_len = MIN(buf->unused,s_len)); buf->after_used += s_len; #ifdef DEBUG fprintf(stderr, __FUNCTION__ " returning: unused %d, used_len %d\n", buf->unused, buffer_used_len(buf)); #endif return s_len; } short int buffer_isEmpty(const struct CharBuffer * const buf) { return buf->used == buf->after_used; } #include int buffer_getc(struct CharBuffer * const buf) { if ( buffer_isEmpty(buf) ) return EOF; else return *(buf->used++); } size_t buffer_copyContents(const char ** const s, const struct CharBuffer * const buf) { const size_t l = buffer_used_len(buf); char * const dest = calloc(l, sizeof(char)); memcpy(dest, buf->used, l); *s = dest; return l; } #include void buffer_dump(const struct CharBuffer * const buf, FILE * f) { if (! buffer_isEmpty(buf) ) fwrite(buf->used, sizeof(char), buffer_used_len(buf) , f); } size_t buffer_used_len(const struct CharBuffer * const buf) { return buf->after_used - buf->used; } my_util/buffers.h0100644000076600007660000000143607656443664013066 0ustar ivanivan#ifndef _BUFFERS_H #define _BUFFERS_H #include struct CharBuffer { char * bulk, * used, * after_used; size_t unused; }; struct CharBuffer * buffer_createEmpty(void); struct CharBuffer * buffer_createMinimal(void); void buffer_destroy(struct CharBuffer * buf); short int buffer_isEmpty(const struct CharBuffer * buf); size_t buffer_used_len(const struct CharBuffer * const buf); size_t buffer_grow(struct CharBuffer * buf); short int buffer_putc(struct CharBuffer * buf, char c); size_t buffer_puts(struct CharBuffer * buf, const char * s, size_t s_len); int buffer_getc(struct CharBuffer * buf); size_t buffer_copyContents(const char ** dest, const struct CharBuffer * buf); #include void buffer_dump(const struct CharBuffer * const buf, FILE * f); #endif my_util/lists.c0100644000076600007660000000265707377702751012564 0ustar ivanivan/* lists.c * Implementation of common basic actions on linked lists. * Version 0.1, November 2001 * * Copyright 2001 Ivan Zakharyaschev * * This code is in public domain: look LICENSE for more info. */ #include "lists.h" #include short int list_isEmptyList(const struct ListNode * const head) { return head == NULL; } void * list_find(const struct ListNode * head, const void * const key, int (*cmp)(const void * key, const void * elem) ) { for (; head != NULL; head = head->next) if (cmp(key, head->value) == 0) break; return head ? head->value : NULL; } struct ListNode * list_add(struct ListNode * const head, void * const elem) { struct ListNode * new = malloc(sizeof(struct ListNode)); new->value = elem; new->next = head; return new; } #ifdef DEBUG #include #endif void list_walkThrough(const struct ListNode * head, void (*action)(void * params, void * elem), void * const params ) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif for (; head != NULL; head = head->next) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": performing action.\n"); #endif action(params, head->value); } } void list_destroy(struct ListNode * head, void (* const destroyElem)(void * elem) ) { while (head) { struct ListNode * next = head->next; destroyElem(head->value); free(head); head = next; } } my_util/lists.h0100644000076600007660000000145707377703147012566 0ustar ivanivan/* lists.c * The interface of common basic actions on linked lists. * Version 0.1, November 2001 * * Copyright 2001 Ivan Zakharyaschev * * This code is in public domain: look LICENSE for more info. */ #ifndef _LISTS_H_ #define _LISTS_H_ struct ListNode { void * value; struct ListNode * next; }; short int list_isEmptyList(const struct ListNode * head); void * list_find(const struct ListNode * head, const void * key, int (*cmp)(const void * key, const void * elem) ); struct ListNode * list_add(struct ListNode * head, void * elem); void list_walkThrough(const struct ListNode * head, void (*action)(void * params, void * elem), void * params ); void list_destroy(struct ListNode * head, void (*destroyElem)(void * elem) ); #endif my_util/chains.c010064400007660000766 4157 10200441725 12524 0ustar ivanivan/* chains.c * Basic actions on chains (list that can be appended) */ #include "chains.h" #include struct Chain * chain_createEmpty(void) { struct Chain * result; result = malloc(sizeof(struct Chain)); result->last = result->first = NULL; return result; } short int chain_isEmpty(const struct Chain * const x) { return x->first == NULL; } /* report if chain is empty: */ short int chain_verifyNotEmpty(const struct Chain *, const char *); void chain_destroy(struct Chain * const x, void (* const destroyElem)(void * elem)) { list_destroy(x->first, destroyElem); free(x); } struct Chain * chain_append(struct Chain * const x, void * const a) { struct ListNode * newNode = malloc(sizeof(struct ListNode)); newNode->value = a; newNode->next = NULL; if ( chain_isEmpty(x) ) x->last = x->first = newNode; else x->last = x->last->next = newNode; return x; } void * chain_first(const struct Chain * const x) { return chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ? x->first->value : NULL; } void * chain_last(const struct Chain * const x) { return chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ? x->last->value : NULL; } void chain_clear(struct Chain * const x, void (* const destroyElem)(void * elem)) { list_destroy(x->first, destroyElem); x->last = x->first = NULL; } void * chain_dellast(struct Chain * const x) { if ( chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ) { void * result; struct ListNode *node, *prev = NULL; for (node = x->first; node != x->last; node = node->next) prev = node; result = node->value; free(node); x->last = prev; if (prev) prev->next = NULL; else x->first = NULL; return result; } else return NULL; } /* The deifinitions of auxiliary functions: */ #include short int chain_verifyNotEmpty(const struct Chain * const x, const char * const callerName) { const short int ok = ( ! chain_isEmpty(x) ); if ( ! ok ) { fprintf(stderr, "Invalid call to %s -- the chain is empty! Returning NULL.\n", callerName); } return ok; } my_util/chains.h0100644000076600007660000000106307656525723012670 0ustar ivanivan#ifndef _CHAINS_H #define _CHAINS_H #include "lists.h" struct Chain { struct ListNode * first, * last; }; struct Chain * chain_createEmpty(void); void chain_destroy(struct Chain * x, void (*destroyElem)(void * elem)); short int chain_isEmpty(const struct Chain * x); void chain_clear(struct Chain * const x, void (* const destroyElem)(void * elem)); struct Chain * chain_append(struct Chain * x, void * a); void * chain_first(const struct Chain * x); void * chain_last(const struct Chain * x); void * chain_dellast(struct Chain * const x); #endif my_util/.emacs-backups/0042755000076600007660000000000010200441725014025 5ustar ivanivanmy_util/.emacs-backups/chains.c~0100644000076600007660000000372407400205672015644 0ustar ivanivan/* chains.c * Basic actions on chains (list that can be appended) */ #include "chains.h" #include struct Chain * chain_createEmpty(void) { struct Chain * result; result = malloc(sizeof(struct Chain)); result->last = result->first = NULL; return result; } short int chain_isEmpty(const struct Chain * const x) { return x->first == NULL; } short int chain_verifyNotEmpty(const struct Chain * const x, const char * const callerName) { const short int ok = chain_isEmpty(x); if ( ! ok ) { fprintf(stderr, "Invalid call to %s -- the chain is empty! Returning NULL.\n", callerName); } return ok; } void chain_destroy(struct Chain * const x, void (* const destroyElem)(void * elem)) { list_destroy(x->first, destroyElem); free(x); } struct Chain * chain_append(struct Chain * const x, void * const a) { struct ListNode * newNode = malloc(sizeof(struct ListNode)); newNode->value = a; newNode->next = NULL; if ( chain_isEmpty(x) ) x->last = x->first = newNode; else x->last = x->last->next = newNode; return x; } #include void * chain_first(const struct Chain * const x) { return chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ? x->first->value : NULL; } void * chain_last(const struct Chain * const x) { return chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ? x->last->value : NULL; } void chain_clear(struct Chain * const x, void (* const destroyElem)(void * elem)) { list_destroy(x->first, destroyElem); x->last = x->first = NULL; } void * chain_dellast(struct Chain * const x) { if ( chain_verifyNotEmpty(x, __PRETTY_FUNCTION__) ) { void * result; struct ListNode *node, *prev = NULL; for (node = x->first; node != x->last; node = node->next) prev = node; result = node->value; free(node); x->last = prev; if (prev) prev->next = NULL; else x->first = NULL; return result; } else return NULL; } pure_recode/0042755000076600007660000000000007657135046012065 5ustar ivanivanpure_recode/Makefile0100644000076600007660000000265507400251514013511 0ustar ivanivanmy_util_dir = ../my_util CPPFLAGS += -I$(my_util_dir) CPPFLAGS += -D_GNU_SOURCE #CPPFLAGS += -DDEBUG CFLAGS += -Wall #LOADLIBES += sources = multipleconv.c singleconv.c docconv.c test.c objs = multipleconv.o singleconv.o docconv.o recoderules.o my_util = $(my_util_dir)/libmy_util.a tests = test libs = pure_recode.a all:: $(libs) $(tests) #################################### # Automatic dependencies: clean:: -$(RM) *.d %.d: %.c set -e; $(CC) -M $(CPPFLAGS) $< \ | sed 's/\($*\)\.o[ :]*/\1.o $@ : /g' > $@; \ [ -s $@ ] || rm -f $@ ifeq ($(subst clean,,$(MAKECMDGOALS)),$(MAKECMDGOALS)) include $(sources:.c=.d) endif # End automatic deps ###################################### ################################### # Lib %.a: $(objs) $(AR) rc $@ $^ clean:: -$(RM) $(libs) # end Lib #################################### ###################################### # Tests: $(tests): $(objs) $(my_util) clean_tests:: -$(RM) $(tests) clean:: clean_tests # End Tests ###################################### clean:: -$(RM) *.o ###################################### # Various types of Cleaning clean_cores:: -$(RM) *core clean_after_emacs:: -$(RM) *'~' -$(RM) '#'*'#' distclean:: clean clean_after_emacs clean_cores # End of Cleaning section ######################## ########################################## # Other libs $(my_util): .FORCE (cd "$$(dirname $(my_util))"; $(MAKE) "$$(basename $(my_util))"; ) .FORCE: pure_recode/docconv.c0100644000076600007660000000446307400017731013650 0ustar ivanivan/* Systemizing document and system-known charset names. 2000 Ivan Zakharyaschev */ #include "docconv.h" /************************** Here comes a piece of code that resembles "iconv" and is based on iconv, but is intended for use with different codename arguments. It could be a separate library. Ivan Z. */ #include #include #include #include #ifndef SYSTEM_CHARSET_FOR #define GET_SYSTEM_CHARSET_FOR(name) amateur_get_sys_charset(name) #define FREE_SYSTEM_CHARSET(chrst) amateur_free_sys_charset(chrst) #endif char * amateur_get_sys_charset(const char * doc_charset); void amateur_free_sys_charset(char * sys_charset); docconv_t docconv_open(const char * const from, const char * const to) { docconv_t result = malloc(sizeof(struct docconv)); result->to = GET_SYSTEM_CHARSET_FOR(to); result->from = GET_SYSTEM_CHARSET_FOR(from); result->ihandle = iconv_open(result->from, result->to); if ( result->ihandle == (iconv_t) -1 ) { FREE_SYSTEM_CHARSET(result->from); FREE_SYSTEM_CHARSET(result->to); return (docconv_t) -1; } return result; } int docconv_close(const docconv_t handle) { int result; if ( !handle || (handle == (docconv_t)-1) ) return -1; FREE_SYSTEM_CHARSET(handle->from); FREE_SYSTEM_CHARSET(handle->to); result = iconv_close(handle->ihandle); free(handle); return result; } /* Should be replaced by a more general tool for translating from document encoding names to character set names known by the system. Ivan Z. */ char * amateur_get_sys_charset(const char * doc_charset) { char *sys_charset = strdup(doc_charset), *result = sys_charset; /* Perhaps it doesn't belong here; maybe this should be done before adding a rule. */ /* cut "x-" in front of charset name */ if(!strncasecmp(result,"x-",2)) result += 2; /* translate windows- to cp, paratype- to pt */ if (!strncasecmp(result,"windows-",8)) { result += 6; result[0] = 'c'; result[1] = 'p'; } else if (!strncasecmp(result,"paratype-",9)) { result += 7; result[0] = 'p'; result[1] = 't'; } result = strdup(result); free(sys_charset); return result; } void amateur_free_sys_charset(char * sys_charset) { free(sys_charset); } /* docconv finishes here *****************************************/ pure_recode/docconv.h0100644000076600007660000000036307400022356013647 0ustar ivanivan#ifndef _DOCCONV_H #define _DOCCONV_H #include typedef struct docconv { char *from, *to; iconv_t ihandle; } * docconv_t; docconv_t docconv_open(const char * from, const char * to); int docconv_close(docconv_t handle); #endif pure_recode/pure_recode.h0100644000076600007660000000236407656525301014526 0ustar ivanivan#ifndef _PURE_RECODE_H #define _PURE_RECODE_H #include #include struct RecodeRule { const char *from, *to; } * createRecodeRule(const char * to, const char * from); void destroyRecodeRule(struct RecodeRule * rule); /* Contructing chains of rules: */ int addRecodeRule(struct Chain * const rules, const char *from, const char *to); void dellastRecodeRule(struct Chain * const rules); void delallRecodeRules(struct Chain * const rules); void destroyRecodeRules(struct Chain * const rules); char * infoOnRecodeRules(const struct Chain * const rules); /* Multiple converters: */ typedef struct Chain MultipleConverter; #include MultipleConverter * multiple_conv_open(const struct ListNode * rules); void multiple_conv_close(MultipleConverter * mc, struct CharBuffer * outbuf); void multiple_conv_feeds(const MultipleConverter * const mc, const char * s, size_t s_len, struct CharBuffer * const outbuf); void multiple_conv_feedc(const MultipleConverter * mc, char c, struct CharBuffer * outbuf); void multiple_conv_reset(MultipleConverter * mc, struct CharBuffer * outbuf); /* Higher level: */ char * multiple_conv_str(const struct Chain * const rules, const char * const s); #endif pure_recode/recoderules.c0100644000076600007660000000462107656526065014547 0ustar ivanivan#include "pure_recode.h" #include #include struct RecodeRule * createRecodeRule(const char * const to, const char * const from) { struct RecodeRule * result = malloc(sizeof(struct RecodeRule)); result->to = strdup(to); result->from = strdup(from); return result; } void destroyRecodeRule(struct RecodeRule * const rule) { free((char*)rule->to); free((char*)rule->from); free(rule); } /* Contructing chains of rules: */ #include "docconv.h" int addRecodeRule(struct Chain * const rules, const char *from, const char *to) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif { docconv_t tmp; if ( ( from == NULL ) || ( to == NULL ) || ( (tmp = docconv_open(to, from)) == (docconv_t) -1 ) ) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ ": bad\n"); #endif return 1; } docconv_close(tmp); } { struct RecodeRule *rule = createRecodeRule(to, from); if(rule == NULL) return 1; chain_append(rules, rule); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ ": good\n"); #endif return 0; } } void dellastRecodeRule(struct Chain * const rules) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if (! chain_isEmpty(rules) ) destroyRecodeRule(chain_dellast(rules)); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ " ret\n"); #endif } void delallRecodeRules(struct Chain * const rules) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif chain_clear(rules, (void(*)(void*))destroyRecodeRule); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ ": ret\n"); #endif } void destroyRecodeRules(struct Chain * const rules) { #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif chain_destroy(rules, (void(*)(void*))destroyRecodeRule); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ ": ret\n"); #endif } char * infoOnRecodeRules(const struct Chain * const rules) { void dumpRule(char ** const info, const struct RecodeRule * const rule) { if (*info) asprintf(info, "%s,%s->%s", *info, rule->from, rule->to); else asprintf(info, "%s->%s", rule->from, rule->to); } char * result = NULL; #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif if ( chain_isEmpty(rules) ) result = strdup(""); else list_walkThrough(rules->first, (void (*)(void * param, void * elem))&dumpRule, &result); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ " ret\n"); #endif return result; } pure_recode/test.c0100644000076600007660000000132607400205563013171 0ustar ivanivan#include #include "pure_recode.h" #include #include int main(int argc, char ** argv) { struct Chain * rules = chain_createEmpty(); MultipleConverter * mc; --argc; while (argc) { chain_append(rules, createRecodeRule(argv[2], argv[1])); argv += 2; argc -= 2; } mc = multiple_conv_open(rules->first); { int c; struct CharBuffer * buf = buffer_createEmpty(); while ( (c = getchar()) != EOF ) { multiple_conv_feedc(mc, c, buf); while (! buffer_isEmpty(buf)) putchar(buffer_getc(buf)); } fflush(NULL); buffer_destroy(buf); } multiple_conv_close(mc); chain_destroy(rules, (void (*)(void * elem))&destroyRecodeRule); return 0; } pure_recode/multipleconv.c0100644000076600007660000000671007656444571014756 0ustar ivanivan/***************************************** * Multiple */ #include "pure_recode.h" #include "singleconv.h" #include #include void multiple_conv_feedc(const MultipleConverter * const mc, const char c, struct CharBuffer * const outbuf) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif multiple_conv_feeds(mc, &c, 1, outbuf); #ifdef DEBUG fprintf(stderr, __FUNCTION__ " ret\n"); #endif } void multiple_conv_feeds(const MultipleConverter * const mc, const char * s, const size_t s_len, struct CharBuffer * const outbuf) { #define NEXT_BUF(next,outbuf) (\ next \ ? ((SingleConverter *)next->value)->inbuf \ : outbuf \ ) struct ListNode * node = NULL, * next = mc->first; #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif buffer_puts(NEXT_BUF(next,outbuf), s, s_len); #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": first puts done\n"); #endif while (next) { next = (node = next)->next; #ifdef DEBUG fprintf(stderr, __FUNCTION__ " inbuf: unused %d, used_len %d\n", ((SingleConverter *)node->value)->inbuf->unused, buffer_used_len(((SingleConverter *)node->value)->inbuf)); #endif single_conva_force((SingleConverter *)node->value, NEXT_BUF(next,outbuf)); } #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": return.\n"); #endif } #include MultipleConverter * multiple_conv_open(const struct ListNode * const rules) { void appendConverter(struct Chain * const chain, const struct RecodeRule * const rule) { SingleConverter * sc = single_conv_open(rule->to, rule->from); if (sc != NULL) chain_append(chain, sc); } MultipleConverter * result = chain_createEmpty(); list_walkThrough(rules, (void (*)(void * param, void * elem))&appendConverter, result); return result; } void multiple_conv_close_internal(MultipleConverter * mc) { void closeConverter(const void * const p, SingleConverter * const sc) { single_conv_close(sc); } list_walkThrough(mc->first, (void (*)(void * param, void * elem))&closeConverter , NULL); } void multiple_conv_close(MultipleConverter * mc, struct CharBuffer * const outbuf) { multiple_conv_reset(mc, outbuf); multiple_conv_close_internal(mc); } void multiple_conv_reset(MultipleConverter * mc, struct CharBuffer * const outbuf) { struct ListNode * node = NULL, * next = mc->first; #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif while (next) { next = (node = next)->next; #ifdef DEBUG fprintf(stderr, __FUNCTION__ " inbuf: unused %d, used_len %d\n", ((SingleConverter *)node->value)->inbuf->unused, buffer_used_len(((SingleConverter *)node->value)->inbuf)); #endif single_conva_reset((SingleConverter *)node->value, NEXT_BUF(next,outbuf)); } #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": return.\n"); #endif } /* Higher level: */ #include #include char * multiple_conv_str(const struct Chain * const rules, const char * const s) { char * result = NULL; MultipleConverter * const pipe = multiple_conv_open(rules->first); struct CharBuffer * const buf = buffer_createEmpty(); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif multiple_conv_feeds(pipe, s, strlen(s), buf); multiple_conv_close(pipe, buf); buffer_putc(buf, '\0'); buffer_copyContents((const char**)&result, buf); buffer_destroy(buf); #ifdef FDEBUG fprintf(stderr, __FUNCTION__ " ret\n"); #endif return result; } pure_recode/singleconv.c0100644000076600007660000000711207656444423014375 0ustar ivanivan#include #include #include #include #include #define ASCII_ERRS "?" size_t iconva(const iconv_t icd, char ** const inbuf, size_t * const inleft, struct CharBuffer * const outbuf) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif do { size_t result; if ( ! outbuf->unused ) buffer_grow(outbuf); #ifdef DEBUG if (inbuf) fprintf(stderr, __FUNCTION__ ": about iconv, left %d\n", *inleft); else fprintf(stderr, __FUNCTION__ ": about iconv, RESET\n"); #endif result = iconv(icd, inbuf, inleft, &outbuf->after_used, &outbuf->unused); #ifdef DEBUG if (inbuf) fprintf(stderr, __FUNCTION__ ": iconv == %d, left %d\n", result, *inleft); else fprintf(stderr, __FUNCTION__ ": iconv == %d, RESET\n", result); #endif if ( ( result != (size_t) -1 ) || ( errno != E2BIG) || ! buffer_grow(outbuf) ) return result; } while (1); } size_t iconva_reset(const iconv_t icd, struct CharBuffer * const outbuf) { return iconva(icd, NULL, NULL, outbuf); } /****************************************** * Single converter */ #include "singleconv.h" #include "docconv.h" size_t single_conva(const SingleConverter * const sc, struct CharBuffer * const outbuf) { size_t in_left = buffer_used_len(sc->inbuf); #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": about iconv, left %d\n", in_left); #endif return iconva(sc->icd, &sc->inbuf->used, &in_left, outbuf); } void single_conv_putErr(const SingleConverter * const sc, struct CharBuffer * const outbuf) { iconva_reset(sc->icd, outbuf); if (sc->errs) buffer_puts(outbuf, sc->errs, sc->errlen); } void single_conva_reset(const SingleConverter * const sc, struct CharBuffer * const outbuf) { iconva_reset(sc->icd, outbuf); } void single_conva_force(const SingleConverter * const sc, struct CharBuffer * const outbuf) { #ifdef DEBUG fprintf(stderr, __FUNCTION__ "\n"); #endif while ( ! buffer_isEmpty(sc->inbuf) && ( single_conva(sc, outbuf) == (size_t) -1 ) && ( errno == EILSEQ ) ) { single_conv_putErr(sc, outbuf); buffer_getc(sc->inbuf); } #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": returning.\n"); #endif } SingleConverter * single_conv_open(const char * const to, const char * const from) { SingleConverter * result = malloc(sizeof(SingleConverter)); result->dcd = docconv_open(to, from); if (result->dcd == (docconv_t) -1) { free(result); return NULL; } result->icd = result->dcd->ihandle; result->inbuf = buffer_createMinimal(); #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": unused %d.\n", result->inbuf->unused); #endif { docconv_t dcd = docconv_open(to, "us-ascii"); if (dcd == (docconv_t) -1) { result->errs = ""; result->errlen = 0; } else { char * ascii_errs = ASCII_ERRS; size_t ascii_errs_len = strlen(ASCII_ERRS); struct CharBuffer * buf = buffer_createMinimal(); iconva(result->dcd->ihandle, &ascii_errs, &ascii_errs_len, buf); iconva_reset(result->dcd->ihandle, buf); docconv_close(dcd); result->errlen = buffer_copyContents(&result->errs, buf); buffer_destroy(buf); } } #ifdef DEBUG fprintf(stderr, __FUNCTION__ ": ret unused %d.\n", result->inbuf->unused); #endif return result; } void single_conv_close(SingleConverter * const sc) { buffer_destroy(sc->inbuf); docconv_close(sc->dcd); if (sc->errs) free((char*)sc->errs); } /* End of single converter definitions ****************************************/ pure_recode/singleconv.h0100644000076600007660000000107507400233212014357 0ustar ivanivan#include #include #include "docconv.h" typedef struct { struct CharBuffer * inbuf; iconv_t icd; docconv_t dcd; const char * errs; size_t errlen; } SingleConverter; SingleConverter * single_conv_open(const char * to, const char * from); void single_conv_close(SingleConverter * sc); size_t single_conva(const SingleConverter * sc, struct CharBuffer * outbuf); void single_conva_force(const SingleConverter * sc, struct CharBuffer * outbuf); void single_conva_reset(const SingleConverter * sc, struct CharBuffer * outbuf);