2013-11-15 11:25:10 -05:00
|
|
|
/* See LICENSE file for copyright and license details. */
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <locale.h>
|
|
|
|
#include <wchar.h>
|
|
|
|
#include "text.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(void)
|
|
|
|
{
|
2014-04-09 08:12:34 -04:00
|
|
|
eprintf("usage: %s [-d] set1 [set2]\n", argv0);
|
2013-11-15 11:25:10 -05:00
|
|
|
}
|
|
|
|
|
2014-01-25 17:07:13 -05:00
|
|
|
static void
|
2013-11-15 11:25:10 -05:00
|
|
|
handleescapes(char *s)
|
|
|
|
{
|
|
|
|
switch(*s) {
|
|
|
|
case 'n':
|
|
|
|
*s = '\n';
|
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
*s = '\t';
|
|
|
|
break;
|
|
|
|
case '\\':
|
|
|
|
*s = '\\';
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
*s = '\r';
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
*s = '\f';
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
*s = '\a';
|
|
|
|
break;
|
|
|
|
case 'b':
|
|
|
|
*s = '\b';
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
*s = '\v';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-12 14:50:51 -04:00
|
|
|
static int
|
|
|
|
xmbtowc(wchar_t *unicodep, const char *s)
|
|
|
|
{
|
|
|
|
int rv;
|
|
|
|
|
|
|
|
rv = mbtowc(unicodep, s, 4);
|
|
|
|
if (rv < 0)
|
|
|
|
eprintf("mbtowc:");
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2014-01-25 17:07:13 -05:00
|
|
|
static void
|
2013-11-15 11:25:10 -05:00
|
|
|
parsemapping(const char *set1, const char *set2, wchar_t *mappings)
|
|
|
|
{
|
2014-04-09 08:03:02 -04:00
|
|
|
char *s1, *s2;
|
2013-11-15 11:25:10 -05:00
|
|
|
wchar_t runeleft;
|
|
|
|
wchar_t runeright;
|
|
|
|
int leftbytes;
|
|
|
|
int rightbytes;
|
|
|
|
|
2014-04-09 08:03:02 -04:00
|
|
|
s1 = (char *)set1;
|
|
|
|
if(set2)
|
|
|
|
s2 = (char *)set2;
|
|
|
|
else
|
|
|
|
s2 = (char *)set1;
|
2013-11-15 11:25:10 -05:00
|
|
|
|
2014-04-09 08:03:02 -04:00
|
|
|
while(*s1) {
|
|
|
|
if(*s1 == '\\')
|
|
|
|
handleescapes(++s1);
|
2014-04-12 14:50:51 -04:00
|
|
|
leftbytes = xmbtowc(&runeleft, s1);
|
2014-04-09 08:03:02 -04:00
|
|
|
s1 += leftbytes;
|
|
|
|
if(*s2 == '\\')
|
|
|
|
handleescapes(++s2);
|
|
|
|
if(*s2 != '\0') {
|
2014-04-12 14:50:51 -04:00
|
|
|
rightbytes = xmbtowc(&runeright, s2);
|
2014-04-09 08:03:02 -04:00
|
|
|
s2 += rightbytes;
|
|
|
|
}
|
2013-11-15 11:25:10 -05:00
|
|
|
mappings[runeleft] = runeright;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-25 17:07:13 -05:00
|
|
|
static void
|
2013-11-15 11:25:10 -05:00
|
|
|
maptonull(const wchar_t *mappings, char *in)
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
wchar_t runeleft;
|
|
|
|
int leftbytes = 0;
|
|
|
|
|
|
|
|
s = in;
|
|
|
|
while(*s) {
|
2014-04-12 14:50:51 -04:00
|
|
|
leftbytes = xmbtowc(&runeleft, s);
|
2013-11-15 11:25:10 -05:00
|
|
|
if(!mappings[runeleft])
|
|
|
|
putwchar(runeleft);
|
|
|
|
s += leftbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-25 17:07:13 -05:00
|
|
|
static void
|
2013-11-15 11:25:10 -05:00
|
|
|
maptoset(const wchar_t *mappings, char *in)
|
|
|
|
{
|
|
|
|
const char *s;
|
|
|
|
wchar_t runeleft;
|
|
|
|
int leftbytes = 0;
|
|
|
|
|
|
|
|
s = in;
|
|
|
|
while(*s) {
|
2014-04-12 14:50:51 -04:00
|
|
|
leftbytes = xmbtowc(&runeleft, s);
|
2013-11-15 11:25:10 -05:00
|
|
|
if(!mappings[runeleft])
|
|
|
|
putwchar(runeleft);
|
|
|
|
else
|
|
|
|
putwchar(mappings[runeleft]);
|
|
|
|
s += leftbytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
wchar_t *mappings;
|
|
|
|
char *buf = NULL;
|
|
|
|
size_t size = 0;
|
|
|
|
void (*mapfunc)(const wchar_t*, char*);
|
2014-04-09 08:12:34 -04:00
|
|
|
int dflag = 0;
|
2013-11-15 11:25:10 -05:00
|
|
|
|
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
|
2014-04-12 15:32:39 -04:00
|
|
|
mappings = mmap(NULL, 0x110000 * sizeof(wchar_t),
|
|
|
|
PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0);
|
2014-01-20 06:25:57 -05:00
|
|
|
if (mappings == MAP_FAILED)
|
|
|
|
eprintf("mmap:");
|
2013-11-15 11:25:10 -05:00
|
|
|
|
|
|
|
ARGBEGIN {
|
2014-04-09 08:12:34 -04:00
|
|
|
case 'd':
|
|
|
|
dflag = 1;
|
|
|
|
break;
|
2013-11-15 11:25:10 -05:00
|
|
|
default:
|
|
|
|
usage();
|
|
|
|
} ARGEND;
|
|
|
|
|
|
|
|
if(argc == 0)
|
|
|
|
usage();
|
|
|
|
|
2014-04-12 06:56:56 -04:00
|
|
|
if(dflag || argc == 1) {
|
|
|
|
if(argc != 1)
|
2014-04-09 08:12:34 -04:00
|
|
|
usage();
|
2013-11-15 11:25:10 -05:00
|
|
|
parsemapping(argv[0], NULL, mappings);
|
|
|
|
mapfunc = maptonull;
|
2014-04-09 08:12:34 -04:00
|
|
|
} else {
|
|
|
|
if(argc != 2)
|
|
|
|
usage();
|
|
|
|
parsemapping(argv[0], argv[1], mappings);
|
|
|
|
mapfunc = maptoset;
|
2013-11-15 11:25:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
while(afgets(&buf, &size, stdin))
|
|
|
|
mapfunc(mappings, buf);
|
|
|
|
free(buf);
|
|
|
|
if(ferror(stdin))
|
|
|
|
eprintf("<stdin>: read error:");
|
|
|
|
|
2014-01-20 06:25:57 -05:00
|
|
|
munmap(mappings, 0x110000 * sizeof(wchar_t));
|
|
|
|
|
2013-11-15 11:25:10 -05:00
|
|
|
return EXIT_SUCCESS;
|
|
|
|
}
|