Merge remote-tracking branch 'origin/front' into front

This commit is contained in:
xfnw 2022-07-18 22:31:02 -04:00
commit 917ae0345f
29 changed files with 86682 additions and 3270 deletions

83100
lib/hanzi.zidian Normal file

File diff suppressed because it is too large Load diff

12
lib/ktrans/README Normal file
View file

@ -0,0 +1,12 @@
#
# The following are a set of tools to obtain and process dictionaries from the SKK project in order to use them with ktrans(1).
#
# grabskkdicts pulls the skk kana-kanji conversion dictionaries from the skk-dev/dict repo.
# skk2ktrans takes an skk dictionary and converts it into a kanji jisho suitable to be used with ktrans(1).
#
# You can fetch and convert all the dictionaries by running this file.
#
grabskkdicts
for(d in skkdicts/SKK-JISYO.*)
<$d skk2ktrans >$d.jisho

2
lib/ktrans/grabskkdicts Executable file
View file

@ -0,0 +1,2 @@
#!/bin/rc
git/clone https://github.com/skk-dev/dict skkdicts

2
lib/ktrans/skk2ktrans Executable file
View file

@ -0,0 +1,2 @@
#!/bin/rc
tcs -sf jis | awk '$1 !~ /;;/ {gsub("(^\/|\/$)", "", $2); gsub(" ", " "); gsub("\/", " ", $2);} {print}'

View file

@ -956,3 +956,7 @@ I really don't understand the approach being taken here.
I want to understand what the goal here is. I want to understand what the goal here is.
It won't happen. It won't happen.
That is either a funny joke, or it shows you don't understand Unix. That is either a funny joke, or it shows you don't understand Unix.
The smallest diffs are the best.
I don't understand what the proposal is.
The man page says "don't do that".
That seems disgustingly verbose to me.

View file

@ -22,16 +22,18 @@ if(~ $#p9part 0){
exit '' exit ''
} }
echo if(test -f /386/mbr){
echo 'If you use the Windows NT/2000/XP master boot record' echo
echo 'or a master boot record from a Unix clone (e.g., LILO or' echo 'If you use the Windows NT/2000/XP master boot record'
echo 'FreeBSD bootmgr), it is probably safe to continue using' echo 'or a master boot record from a Unix clone (e.g., LILO or'
echo 'that boot record rather than install the Plan 9 boot record.' echo 'FreeBSD bootmgr), it is probably safe to continue using'
echo echo 'that boot record rather than install the Plan 9 boot record.'
prompt 'Install the Plan 9 master boot record' yes no echo
switch($rd) { prompt 'Install the Plan 9 master boot record' yes no
case yes switch($rd) {
case yes
disk/mbr -m /386/mbr /dev/$disk/data disk/mbr -m /386/mbr /dev/$disk/data
}
} }
prompt 'Mark the Plan 9 partition active' yes no prompt 'Mark the Plan 9 partition active' yes no

View file

@ -30,16 +30,26 @@ case go
9fat=$rd 9fat=$rd
export 9fat export 9fat
if(~ $#bootfile 1){
bootfile=`{basename $bootfile} bootfile=`{basename $bootfile}
}
if(! ~ $#bootfile 1 || ! test -f /$cputype/$bootfile) {
bootfile=()
}
if(! test -f /tmp/plan9.ini) { if(! test -f /tmp/plan9.ini) {
@{ @{
if(~ $#bootfile 1)
echo 'bootfile='^$bootfile echo 'bootfile='^$bootfile
if(~ $#fs 1)
echo 'bootargs=local!'^$fs' '$"fsflags echo 'bootargs=local!'^$fs' '$"fsflags
if(~ $#nvram 1) if(~ $#nvram 1)
echo 'nvram='^$nvram echo 'nvram='^$nvram
if(~ $#mouseport 1)
echo 'mouseport='^$mouseport echo 'mouseport='^$mouseport
if(~ $#monitor 1)
echo 'monitor='^$monitor echo 'monitor='^$monitor
if(~ $#vgasize 1)
echo 'vgasize='^$vgasize echo 'vgasize='^$vgasize
cd '#ec' cd '#ec'
for(i in *){ for(i in *){
@ -72,32 +82,50 @@ case go
# always make backup of old bootsector # always make backup of old bootsector
logprog dd -bs 512 -count 1 -if $9fat -of /tmp/pbs.bak logprog dd -bs 512 -count 1 -if $9fat -of /tmp/pbs.bak
if (! test -f /386/pbs) {
if(~ $need9fatformat yes){ if(~ $need9fatformat yes){
log Initializing Plan 9 FAT partition. log Initializing Plan 9 FAT partition.
logprog disk/format -r 2 -d -b /n/newfs/386/pbs -l PLAN9 $9fat logprog disk/format -r 2 -d -l PLAN9 $9fat
}
}
if not {
if(~ $need9fatformat yes){
log Initializing Plan 9 FAT partition.
logprog disk/format -r 2 -d -b /386/pbs -l PLAN9 $9fat
} }
if not { if not {
log Updating bootsector. log Updating bootsector.
logprog disk/format -b /n/newfs/386/pbs $9fat logprog disk/format -b /386/pbs $9fat
}
} }
logprog mount -c /srv/dos /n/9fat $9fat logprog mount -c /srv/dos /n/9fat $9fat
logprog rm -f /n/9fat/^(9bootfat plan9.ini $bootfile) if(test -f /386/9bootfat) {
logprog rm -f /n/9fat/9bootfat
logprog cp /386/9bootfat /n/9fat/9bootfat
logprog cp /n/newfs/386/9bootfat /n/9fat/9bootfat
# make file continous on disk # make file continous on disk
logprog chmod +al /n/9fat/9bootfat logprog chmod +al /n/9fat/9bootfat
}
# copy config # copy config
logprog rm -f /n/9fat/plan9.ini
logprog cp /tmp/plan9.ini /n/9fat/plan9.ini logprog cp /tmp/plan9.ini /n/9fat/plan9.ini
# copy kernel # copy kernel
logprog cp /n/newfs/$cputype/$bootfile /n/9fat/ if(~ $#bootfile 1){
logprog rm -f /n/9fat/$bootfile
logprog cp /$cputype/$bootfile /n/9fat/$bootfile
}
# copy efi bootloader # copy efi bootloader
for(i in /386/*.efi){
if(test -f $i) {
logprog mkdir -p /n/9fat/efi/boot logprog mkdir -p /n/9fat/efi/boot
logprog cp /386/^(bootia32.efi bootx64.efi) /n/9fat/efi/boot logprog cp $i /n/9fat/efi/boot/
}
}
# copy in backups # copy in backups
if(test -f /tmp/oldplan9.ini) if(test -f /tmp/oldplan9.ini)

View file

@ -5260,3 +5260,5 @@ MY NAME IS BEING USED IN A PHISHING ATTACK. DO NOT RESPOND TO MAIL OFFERING MON
Xterm.js Xterm.js
GPU.js GPU.js
Joys of Porting a Kernel to WebAssembly Joys of Porting a Kernel to WebAssembly
Never change anything. You can only make it worse. -- Ted Unangst
Use a client written in Go? -- Skip Tavakkolian

98
sys/man/3/i2c Normal file
View file

@ -0,0 +1,98 @@
.TH I2C 3
.SH NAME
i2c \- I²C Bus Interface
.SH SYNOPSIS
.nf
.B bind -a #J /dev
.PP
.nf
.BI /dev/ bus /i2c. n .ctl
.BI /dev/ bus /i2c. n .data
.SH DESCRIPTION
The I²C (Inter-Integrated Circuit) bus is a serial bus standard
invented by Philips.
It is used to connect chips over short-distances like on a motherboard
or between boards.
The bus requires only a single data signal
.IR SDA ,
a clock signal
.I SDC
and ground.
Devices on the bus have 7-bit or 10-bit addresses, which is
determined by the device (see the datasheet).
Every device monitors the bus and waits for the master to initiate
a transaction.
Each transaction starts with the master sending the target device address
with a direction bit and the device acknowledges each byte
received if its address matched.
Depending on the device, more bytes must be transmitted after the
.IR device-address .
For example, encoding a register number at a memory offset.
We refer to these bytes as the
.IR sub-address .
After the address phase, the data phase begins where
zero or more data bytes are either transmitted or received
depending on the transaction direction.
.PP
This driver supports multiple buses (controllers) to be registered
by platform specific code in the kernel.
Each bus is represented as a directory with a platform specific name.
.PP
Because all received bytes are acknowledged by target devices,
it is possible for the master to enumerate all existing addresses
on a bus, which is done when accessing the
.I bus
directory.
.PP
Platform specific code can also register individual devices,
supplying a meaningful device configuration.
It can also be necessary to manually register devices if
the device has been disabled by an enable signal or
otherwise inhibited during enumeration.
.PP
Each device appears as a control (
.BI i2c. n .ctl
)
and a data file (
.BI i2c. n .data
) in the
.I bus
directory
where
.I n
is the device-address in hexadecimal.
.PP
The data file is used to initiate transactions to the device.
The initial
.I sub-address
bytes sent are derived from the file position according to the device
configuration, and the length of the data phase is controlled by
the requested read or write size.
The requested size might be truncated by the driver if
the request exceeds the logical file-size.
.PP
The control-file provides access to the device configuration.
When read,
it reproduces this configuration in text form.
The following text lines are accepted when written to the control-file:
.TF "subaddress n"
.TP
.BI "subaddress " n
Sets the length
.IR n ,
in bytes, of the sub-address for the device
that is derived from the file-position of the data-file.
This can be set to zero if no sub-address bytes should
be generated by the driver.
By default, the sub-address length is 1.
.TP
.BI "size " n
Changes the logical size of the data-file to
.IR n .
Making sure the file-position is not exceeding this size.
.SH SOURCE
.B /sys/src/9/port/devi2c.c
.SH HISTORY
The file-interface has been inspired by infernos devi2c,
but with the addition of supporting multiple buses
and device enumeration.

View file

@ -682,33 +682,43 @@ Otherwise a free port number starting at 5000 is chosen.
The connect fails if the combination of local and remote address/port pairs The connect fails if the combination of local and remote address/port pairs
are already assigned to another port. are already assigned to another port.
.TP .TP
.BI announce\ X .BI announce\ [ip-address ! ]port
.I X Set the local IP address and port number and accept calls there. If
is a decimal port number or ip-address is left out, accept calls on any address. If port is 0, a
.LR * . port is automatically choosen that is not yet announced.
Set the local port If the address is
number to
.I X
and accept calls to
.IR X .
If
.I X
is
.LR * , .LR * ,
accept accept calls on any address.
calls for any port that no process has explicitly announced. If port is
The local IP address cannot be set. .LR * ,
accept calls on any port.
If port is
.LR * ,
and the address is left out, accept calls on any address and port.
.B Announce .B Announce
fails if the connection is already announced or connected. fails if the connection is already announced.
.TP .TP
.BI bind\ X .BI bind\ [ip-address ! ]port
.I X Set the local IP address and port number like for a server connection
is a decimal port number or similar to the
.LR * . .B announce
Set the local port number to command.
.IR X . If ip-address is left out, an address is automatically selected. If
This exists to support emulation port is 0, a port is automatically choosen that is not yet announced.
of BSD sockets by the APE libraries (see This command has no actual effect, beyond remembering the parameters
and possibly selecting an unused port.
The commands
.B announce
and
.B connect
reset both the local address and the port according to their own
parameters.
This command also does
.B not
reserve the IP address and port, another connection can use them, even
while they are registered in a connection by this command.
This exists to support emulation of BSD sockets by the APE libraries
(see
.IR pcc (1)) .IR pcc (1))
and is not otherwise used. and is not otherwise used.
.\" this is gone .\" this is gone

View file

@ -13,6 +13,7 @@ dev
tls tls
cap cap
fs fs
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen swcursor draw screen swcursor
mouse mouse mouse mouse
@ -22,10 +23,11 @@ dev
usb usb
link link
loopbackmedium
ethermedium
archbcm archbcm
usbdwc usbdwc
ethermedium
loopbackmedium
netdevmedium
ip ip
tcp tcp

View file

@ -13,6 +13,7 @@ dev
tls tls
cap cap
fs fs
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen swcursor draw screen swcursor
mouse mouse mouse mouse
@ -22,10 +23,11 @@ dev
usb usb
link link
loopbackmedium
ethermedium
archbcm2 archbcm2
usbdwc usbdwc
ethermedium
loopbackmedium
netdevmedium
ip ip
tcp tcp

View file

@ -13,6 +13,7 @@ dev
tls tls
cap cap
fs fs
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen swcursor draw screen swcursor
mouse mouse mouse mouse
@ -23,10 +24,11 @@ dev
dtracy dtracy
link link
loopbackmedium
ethermedium
archbcm3 archbcm3
usbdwc usbdwc
ethermedium
loopbackmedium
netdevmedium
ip ip
tcp tcp

View file

@ -14,6 +14,7 @@ dev
cap cap
fs fs
ether netif ether netif
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen swcursor draw screen swcursor
mouse mouse mouse mouse
@ -31,6 +32,7 @@ link
ethergenet ethermii ethergenet ethermii
ethermedium ethermedium
loopbackmedium loopbackmedium
netdevmedium
ip ip
tcp tcp

View file

@ -13,6 +13,7 @@ dev
cap cap
fs fs
ether netif ether netif
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen swcursor draw screen swcursor
mouse screen swcursor mouse screen swcursor
@ -26,8 +27,10 @@ link
etherimx ethermii etherimx ethermii
ethermedium ethermedium
loopbackmedium loopbackmedium
netdevmedium
i2cimx devi2c i2cimx devi2c
pciimx pci pciimx pci
ip ip
tcp tcp
udp udp

View file

@ -20,7 +20,7 @@ dev
dtracy dtracy
ether netif ether netif
bridge netif log bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen vga vgax vgasoft draw screen vga vgax vgasoft
@ -81,9 +81,9 @@ link
ethervirtio pci ethervirtio pci
ethervirtio10 pci ethervirtio10 pci
ethermedium ethermedium
pcmciamodem
netdevmedium
loopbackmedium loopbackmedium
netdevmedium
pcmciamodem
usbuhci pci usbuhci pci
usbohci pci usbohci pci
usbehci usbehcipc usbehci usbehcipc

View file

@ -19,8 +19,8 @@ dev
fs fs
ether netif ether netif
bridge netif log bridge log
ip arp chandial ip ipv6 ipaux iproute netlog ethermedium nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
draw screen vga vgax vgasoft draw screen vga vgax vgasoft
mouse mouse mouse mouse
@ -79,9 +79,9 @@ link
ethervirtio pci ethervirtio pci
ethervirtio10 pci ethervirtio10 pci
ethermedium ethermedium
# pcmciamodem
netdevmedium
loopbackmedium loopbackmedium
netdevmedium
# pcmciamodem
usbuhci pci usbuhci pci
usbohci pci usbohci pci
usbehci pci usbehcipc usbehci pci usbehcipc

View file

@ -12,6 +12,7 @@ dev
pipe pipe
dup dup
ether netif ether netif
bridge log
ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno ip arp chandial ip ipv6 ipaux iproute netlog nullmedium pktmedium inferno
tls tls
cap cap

View file

@ -39,6 +39,30 @@ _sock_inport(struct sockaddr *a)
return 0; return 0;
} }
int
_sock_inisany(int af, void *addr)
{
int alen;
void *any;
/* an IPv4 address that is auto-initialized to all zeros */
static struct in_addr inaddr_any;
switch(af){
case AF_INET:
alen = sizeof inaddr_any.s_addr;
any = &inaddr_any;
break;
case AF_INET6:
alen = sizeof in6addr_any;
any = &in6addr_any;
break;
default:
return 0;
}
return 0 == memcmp(addr, any, alen);
}
int int
_sock_inaddr(int af, char *ip, char *port, void *a, int *alen) _sock_inaddr(int af, char *ip, char *port, void *a, int *alen)
{ {
@ -97,3 +121,23 @@ _sock_ingetaddr(Rock *r, void *a, int *alen, char *file)
close(fd); close(fd);
} }
} }
char *
_sock_inaddr2string(Rock *r, char *dest, int dlen)
{
int af = r->domain;
void *addr = _sock_inip(&r->addr);
int port = _sock_inport(&r->addr);
char *d = dest;
char *dend = dest+dlen;
if(!_sock_inisany(af, addr)){
inet_ntop(af, addr, d, dlen-1);
d = memchr(d, 0, dlen-1);
*(d++) = '!';
}
snprintf(d, dend-d, "%d", port);
return dest;
}

View file

@ -24,7 +24,7 @@
int int
bind(int fd, void *a, int alen) bind(int fd, void *a, int alen)
{ {
int n, len, cfd, port; int n, len, cfd;
struct sockaddr *sa; struct sockaddr *sa;
Rock *r; Rock *r;
char msg[128]; char msg[128];
@ -55,20 +55,25 @@ bind(int fd, void *a, int alen)
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
port = _sock_inport(&r->addr);
if(port > 0) strcpy(msg, "bind ");
snprintf(msg, sizeof msg, "bind %d", port); _sock_inaddr2string(r, msg + 5, sizeof msg - 5);
else
strcpy(msg, "bind *");
n = write(cfd, msg, strlen(msg)); n = write(cfd, msg, strlen(msg));
if(n < 0){ if(n < 0){
errno = EOPNOTSUPP; /* Improve error reporting!!! */ _syserrno();
if(errno == EPLAN9)
errno = EOPNOTSUPP;
close(cfd); close(cfd);
return -1; return -1;
} }
close(cfd); close(cfd);
if(port <= 0)
if(_sock_inport(&r->addr) == 0)
_sock_ingetaddr(r, &r->addr, 0, "local"); _sock_ingetaddr(r, &r->addr, 0, "local");
return 0; return 0;
} }

View file

@ -121,7 +121,7 @@ listen(fd, backlog)
int backlog; int backlog;
{ {
Rock *r; Rock *r;
int n, cfd, port; int n, cfd;
char msg[128]; char msg[128];
struct sockaddr_un *lunix; struct sockaddr_un *lunix;
@ -139,20 +139,13 @@ listen(fd, backlog)
errno = EBADF; errno = EBADF;
return -1; return -1;
} }
port = _sock_inport(&r->addr); strcpy(msg, "announce ");
if(port >= 0) { _sock_inaddr2string(r, msg + 9, sizeof msg - 9);
if(write(cfd, "bind 0", 6) < 0) {
errno = EGREG;
close(cfd);
return -1;
}
snprintf(msg, sizeof msg, "announce %d", port);
}
else
strcpy(msg, "announce *");
n = write(cfd, msg, strlen(msg)); n = write(cfd, msg, strlen(msg));
if(n < 0){ if(n < 0){
errno = EOPNOTSUPP; /* Improve error reporting!!! */ _syserrno();
if(errno == EPLAN9)
errno = EOPNOTSUPP;
close(cfd); close(cfd);
return -1; return -1;
} }

View file

@ -43,5 +43,7 @@ extern int _sock_data(int, char*, int, int, int, Rock**);
extern int _sock_ipattr(char*); extern int _sock_ipattr(char*);
extern void* _sock_inip(struct sockaddr*); extern void* _sock_inip(struct sockaddr*);
extern int _sock_inport(struct sockaddr*); extern int _sock_inport(struct sockaddr*);
extern int _sock_inisany(int af, void *addr);
extern int _sock_inaddr(int, char*, char*, void*, int*); extern int _sock_inaddr(int, char*, char*, void*, int*);
extern void _sock_ingetaddr(Rock*, void*, int*, char*); extern void _sock_ingetaddr(Rock*, void*, int*, char*);
extern char* _sock_inaddr2string(Rock *r, char *dest, int dlen);

224
sys/src/cmd/ktrans/hash.c Normal file
View file

@ -0,0 +1,224 @@
#include <u.h>
#include <libc.h>
#include "hash.h"
typedef struct Hnode Hnode;
struct Hnode {
int filled;
int next;
void *key;
};
enum{
Tagsize = sizeof(Hnode),
};
uvlong
shash(char *s)
{
uvlong hash;
hash = 7;
for(; *s; s++)
hash = hash*31 + *s;
return hash;
}
Hmap*
hmapalloc(int nbuckets, int size)
{
void *store;
Hmap *h;
int nsz;
nsz = Tagsize + size;
store = mallocz(sizeof(*h) + (nbuckets * nsz), 1);
if(store == nil)
return nil;
h = store;
h->nbs = nbuckets;
h->nsz = nsz;
h->len = h->cap = nbuckets;
h->nodes = store;
h->nodes += sizeof(*h);
return store;
}
int
hmaprepl(Hmap **store, char *key, void *new, void *old, int freekeys)
{
Hnode *n;
uchar *v;
uchar *oldv;
Hmap *h;
int next;
vlong diff;
h = *store;
oldv = nil;
v = h->nodes + (shash(key)%h->nbs) * h->nsz;
for(;;){
n = (Hnode*)v;
next = n->next;
if(n->filled == 0)
goto replace;
if(strcmp(n->key, key) == 0){
if(freekeys)
free(n->key);
oldv = v + Tagsize;
goto replace;
}
if(next == 0)
break;
v = h->nodes + next*h->nsz;
}
if(h->cap == h->len){
/* figure out way back from a relocation */
diff = v - h->nodes;
h->cap *= 2;
*store = realloc(*store, sizeof(*h) + h->cap*h->nsz);
h = *store;
h->nodes = (uchar*)*store + sizeof(*h);
memset(h->nodes + h->len*h->nsz, 0, h->nsz);
v = h->nodes + diff;
n = (Hnode*)v;
}
n->next = h->len;
h->len++;
assert(h->len <= h->cap);
v = h->nodes + n->next*h->nsz;
n = (Hnode*)v;
replace:
memmove(v + Tagsize, new, h->nsz - Tagsize);
n->filled++;
n->key = key;
n->next = next;
if(old != nil && oldv != nil){
memmove(old, oldv, h->nsz - Tagsize);
return 1;
}
return 0;
}
int
hmapupd(Hmap **h, char *key, void *new)
{
char *prev;
prev = hmapkey(*h, key);
if(prev == nil)
prev = key;
return hmaprepl(h, prev, new, nil, 0);
}
void*
_hmapget(Hmap *h, char *key)
{
Hnode *n;
uchar *v;
v = h->nodes + (shash(key)%h->nbs)*h->nsz;
for(;;){
n = (Hnode*)v;
if(n->filled != 0 && strcmp(n->key, key) == 0)
return v;
if(n->next == 0)
break;
v = h->nodes + n->next*h->nsz;
}
return nil;
}
int
hmapget(Hmap *h, char *key, void *dst)
{
uchar *v;
v = _hmapget(h, key);
if(v == nil)
return -1;
if(dst != nil)
memmove(dst, v + Tagsize, h->nsz - Tagsize);
return 0;
}
int
hmapdel(Hmap *h, char *key, void *dst, int freekey)
{
uchar *v;
Hnode *n;
v = _hmapget(h, key);
if(v == nil)
return -1;
n = (Hnode*)v;
n->filled = 0;
if(freekey)
free(n->key);
if(dst != nil)
memmove(dst, v + Tagsize, h->nsz - Tagsize);
return 0;
}
char*
hmapkey(Hmap *h, char *key)
{
uchar *v;
Hnode *n;
v = _hmapget(h, key);
if(v == nil)
return nil;
n = (Hnode*)v;
return n->key;
}
Hmap*
hmaprehash(Hmap *old, int buckets)
{
int i;
uchar *v;
Hnode *n;
Hmap *new;
if(buckets == 0)
buckets = old->len;
new = hmapalloc(buckets, old->nsz - Tagsize);
for(i=0 ; i < old->len; i++){
v = old->nodes + i*old->nsz;
n = (Hnode*)v;
hmaprepl(&new, n->key, v + Tagsize, nil, 0);
}
free(old);
return new;
}
void
hmapreset(Hmap *h, int freekeys)
{
Hnode *n;
uchar *v;
int i;
for(i=0; i < h->len; i++){
v = h->nodes + i*h->nsz;
n = (Hnode*)v;
if(n->filled == 0)
continue;
if(freekeys)
free(n->key);
n->filled = 0;
}
h->len = 0;
}

23
sys/src/cmd/ktrans/hash.h Normal file
View file

@ -0,0 +1,23 @@
typedef union Hkey Hkey;
union Hkey {
void *p;
int v;
};
typedef struct Hmap Hmap;
struct Hmap {
int nbs;
int nsz;
int len;
int cap;
uchar *nodes;
};
Hmap* hmapalloc(int nbuckets, int size);
int hmapget(Hmap *h, char *key, void *dst);
int hmaprepl(Hmap **h, char *key, void *new, void *old, int freekeys);
int hmapupd(Hmap **h, char *key, void *new);
int hmapdel(Hmap *h, char *key, void *dst, int freekey);
char* hmapkey(Hmap *h, char *key);
void hmapreset(Hmap *h, int freekeys);

View file

@ -1,211 +0,0 @@
/*
* open jisho file, and set the size of this jisho etc
*
* Kenji Okamoto August 4, 2000
* Osaka Prefecture Univ.
* okamoto@granite.cias.osakafu-u.ac.jp
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "jisho.h"
Dictionary *openQDIC(char *);
void freeQDIC(Dictionary*);
KouhoList *getKouhoHash(Dictionary*, char *);
KouhoList *getKouhoFile(DicList*, char *);
void selectKouho(KouhoList **, KouhoList*);
int hashVal(char *);
void addHash(Hash **, DicList*);
/*
* Open QuickDIC (hashed personal dictionary)
* open skk styled ktrans dictionary file, and make its hash table
* based on individual header kana strings
*
* KouhoList
* |---------|
* Hash |---->kouho---->kouhotop
* |-------| |
* dic---->dhash---->dicindex---->kanahead
* |--------| |--------|
* Dictionary DicList
*
*/
Dictionary *
openQDIC(char *dicname)
{
Biobuf *f;
void *Bbuf;
Dictionary *dic;
DicList *dicitem; /* for a future extension */
char buf[1024], *startstr, *endstr;
int i;
SET(dicitem); /* yes, I know I'm wrong, but... */
dic = (Dictionary*)malloc(sizeof(Dictionary));
/* make room for pointer array (size=HASHSIZE) of hash table */
for(i=0; i< HASHSIZE; i++) dic->dhash[i] = 0;
dic->dlist = 0; /* for a future extension (more than one dics ^_^ */
if ((f = Bopen(dicname, OREAD)) == 0)
return dic;
/* make hash table by the dic's header word */
while(Bbuf = Brdline(f, '\n')) {
strncpy(buf, (char *)Bbuf, Blinelen(f));
if (buf[0] == ';') /* comment line */
continue;
else {
/* get header word from jisho */
startstr = buf;
if(!(endstr = utfutf(startstr, "\t"))) break;
*endstr = '\0';
/* dicitem includes each header word from the jisho */
dicitem = (DicList*)malloc(sizeof(DicList)+(endstr-startstr+1));
dicitem->nextitem = 0; /* for a future extension */
strcpy(dicitem->kanahead, startstr);
dicitem->kouho = getKouhoFile(dicitem, endstr); /* read kouho from jisho */
addHash(dic->dhash, dicitem);
}
continue;
}
dic->dlist = dicitem;
Bterm(f);
return dic;
}
/*
* free dynamically allocated memory
*/
void
freeQDIC(Dictionary *dic)
{
Hash *hash1, *hash2;
DicList *dlist, *dlist2;
int l;
for (dlist = dic->dlist;
dlist != 0;
dlist2 = dlist, dlist = dlist->nextitem, free((void *)dlist2));
for (l = 0; l < HASHSIZE; l++) {
for (hash1 = dic->dhash[l]; hash1; hash1 = hash2) {
if (hash1->next !=0) {
hash2 = hash1->next;
free((void *)hash1);
}else
break;
}
}
free((void *)dic);
}
int
hashVal(char *s)
{
uint h;
h = 0x811c9dc5;
while(*s != 0)
h = (h^(uchar)*s++) * 0x1000193;
return h % HASHSIZE;
}
void
addHash(Hash **hash, DicList *ditem)
{
Hash *h;
int v;
v = hashVal(ditem->kanahead);
h = (Hash*)malloc(sizeof(Hash));
h->dicindex = ditem;
h->length = strlen(ditem->kanahead);
h->next = hash[v];
hash[v] = h;
}
/*
* read Kouho list from the jisho file defined by Biobuf descriptor f
*
* revised for Plan 9 by K.Okamoto
*/
KouhoList *
getKouhoFile(DicList *dicitem, char * endstr)
{
char *kouhostart, *kouhoend;
KouhoList *kouhoitem, *currntkouhoitem=0, *prevkouhoitem;
prevkouhoitem = 0;
kouhostart = endstr + 1;
while((kouhoend = utfutf(kouhostart, " ")) ||
(kouhoend = utfutf(kouhostart, "\n"))) {
*kouhoend = '\0';
kouhoitem = (KouhoList*)malloc(sizeof(KouhoList)+(kouhoend-kouhostart+1));
kouhoitem->nextkouho = 0;
kouhoitem->prevkouho = prevkouhoitem;
kouhoitem->dicitem = dicitem;
strcpy(kouhoitem->kouhotop, kouhostart);
if (prevkouhoitem)
prevkouhoitem->nextkouho = kouhoitem;
else
currntkouhoitem = kouhoitem;
prevkouhoitem = kouhoitem;
kouhostart = kouhoend + 1;
}
return currntkouhoitem;
}
/*
* get matched kouho from the hash table of header word of the dict
* if found, returns pointer to the first candidate in the hash table.
* if not found, returns 0.
*
* from getCand() in skklib.c by Akinori Ito et al.,(aito@ei5sun.yz.yamagata-u.ac.jp)
*/
KouhoList *
getKouhoHash(Dictionary *dic, char *s)
{
int l, v;
Hash *h;
l = strlen(s);
v = hashVal(s);
for (h = dic->dhash[v]; h != 0; h = h->next) {
if (h->length != l ||
strcmp(h->dicindex->kanahead, s)) continue;
return h->dicindex->kouho; /* return matched kouho */
}
return 0;
}
/*
* from skklib.c by Akinori Ito et al.,(aito@ei5sun.yz.yamagata-u.ac.jp)
* just modified to read easier for current purpose
*/
void
selectKouho(KouhoList **first, KouhoList *current)
{
/* take off currentkouho from the kouholist table */
if (current->prevkouho) {
current->prevkouho->nextkouho = current->nextkouho;
if (current->nextkouho)
current->nextkouho->prevkouho = current->prevkouho;
current->prevkouho = 0;
}
/* take place of firstkouho by currentkouho */
if (*first != current) {
(*first)->prevkouho = current;
current->nextkouho = *first;
*first = current;
}
}

View file

@ -1,41 +0,0 @@
/*
* Kenji Okamoto August 4, 2000
* Osaka Prefecture Univ.
* okamoto@granite.cias.osakafu-u.ac.jp
*/
#define HASHSIZE 257
/*
* Structure for Dictionary's header word (in Hiragana)
*/
typedef struct DicList DicList;
struct DicList {
struct KouhoList *kouho;
struct DicList *nextitem; /* for a future extension */
char kanahead[1];
};
/*
* Structure for Kouho of each index word in the dictionary
*/
typedef struct KouhoList KouhoList;
struct KouhoList {
struct KouhoList *nextkouho;
struct KouhoList *prevkouho;
struct DicList *dicitem;
char kouhotop[1]; /* top of the kouhos */
} ;
typedef struct Hash Hash;
struct Hash {
DicList *dicindex; /* pointer to a KouhoList and kanahead etc */
short length;
struct Hash *next;
};
typedef struct Dictionary Dictionary;
struct Dictionary {
DicList *dlist; /* for a future extension, having more than one dictionaries */
Hash *dhash[HASHSIZE];
};

File diff suppressed because it is too large Load diff

View file

@ -6,16 +6,26 @@
* okamoto@granite.cias.osakafu-u.ac.jp * okamoto@granite.cias.osakafu-u.ac.jp
*/ */
/*
* A glossary on some of the Japanese vocabulary used:
* kana: syllabic letting, either hiragana() or katakana()
* kanji(): borrowed characters, in
* Okurigana(): kana tail to kanji, in
* Joshi(): particle, in
* Jisho(): dictionary
* kouho(): candidate
*/
#include <u.h> #include <u.h>
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#include "hash.h"
#include "ktrans.h" #include "ktrans.h"
#include "jisho.h"
#define LSIZE 256 #define LSIZE 256
Rune lbuf[LSIZE]; /* hiragana buffer for key input written by send() */ Rune lbuf[LSIZE]; /* hiragana buffer for key input written by send() */
Map *table = hira; /* default language conversion table */ Hmap *table;
uchar okurigana[LSIZE]; /* buffer for okurigana */ uchar okurigana[LSIZE]; /* buffer for okurigana */
char okuri = 0; /* buffer/flag for capital input char */ char okuri = 0; /* buffer/flag for capital input char */
int in, out; int in, out;
@ -23,16 +33,10 @@ int llen, olen, joshi = 0;
int natural = 1; /* not Japanese but English mode */ int natural = 1; /* not Japanese but English mode */
int changelang(int); int changelang(int);
int dotrans(Dictionary*); int dotrans(Hmap*);
int nrune(char *); int nrune(char *);
void send(uchar *, int); void send(uchar *, int);
Map *match(uchar *p, int *nc, Map *table); Hmap* opendict(Hmap *, char *);
extern Dictionary *openQDIC(char *);
extern KouhoList *getKouhoHash(Dictionary*, char *);
extern KouhoList *getKouhoFile(DicList*, char *);
extern void freeQDIC(Dictionary*);
extern void selectKouho(KouhoList **, KouhoList*);
void void
kbdopen(void) kbdopen(void)
@ -89,6 +93,49 @@ kbdopen(void)
exits(nil); exits(nil);
} }
Map signalmore = {
"_", nil, 1,
};
Hmap*
initmap(Map *m, int n)
{
int i, j;
char buf[16];
char *s;
Map prev;
Hmap *h;
h = hmapalloc(n, sizeof(Map));
for(i = 0; i < n; i++){
if(m[i].roma == nil || m[i].roma[0] == '\0')
continue;
//We mark all partial strings so we know when
//we have partial match when ingesting.
j = 2;
for(s = m[i].roma; *s && j <= sizeof buf; s++){
snprint(buf, j, "%s", m[i].roma);
prev = m[i];
if(hmapget(h, buf, &prev) == 0){
if(prev.leadstomore == 1 && s[1] == '\0'){
//confict; partial & valid input
prev = m[i];
prev.leadstomore = 1;
}
}
if(s[1] == '\0'){
hmaprepl(&h, strdup(buf), &prev, nil, 1);
} else {
hmaprepl(&h, strdup(buf), &signalmore, nil, 1);
}
j++;
}
}
return h;
}
void void
usage(void) usage(void)
{ {
@ -101,11 +148,11 @@ main(int argc, char *argv[])
{ {
uchar *bp, *ep, buf[128]; uchar *bp, *ep, buf[128];
Map *mp; Map lkup, last;
int nchar, wantmore; int wantmore;
int n, c; int n, c;
char *dictname; char *jishoname, *zidianname;
Dictionary *jisho; Hmap *jisho, *zidian;
ARGBEGIN{ ARGBEGIN{
default: usage(); default: usage();
@ -113,9 +160,20 @@ main(int argc, char *argv[])
if(argc != 0) if(argc != 0)
usage(); usage();
if((dictname = getenv("jisho")) == nil) if((jishoname = getenv("jisho")) == nil)
dictname = "/lib/kanji.jisho"; jishoname = "/lib/kanji.jisho";
jisho = openQDIC(dictname); jisho = opendict(nil, jishoname);
if((zidianname = getenv("zidian")) == nil)
zidianname = "/lib/hanzi.zidian";
zidian = opendict(nil, zidianname);
hira = table = initmap(mhira, nelem(mhira));
kata = initmap(mkata, nelem(mkata));
greek = initmap(mgreek, nelem(mgreek));
cyril = initmap(mcyril, nelem(mcyril));
hangul = initmap(mhangul, nelem(mhangul));
last = (Map){nil, nil, -1};
kbdopen(); kbdopen();
if(fork()) if(fork())
@ -147,8 +205,8 @@ main(int argc, char *argv[])
wantmore = 0; wantmore = 0;
if (*bp=='') { /* ^x read ktrans-jisho once more */ if (*bp=='') { /* ^x read ktrans-jisho once more */
freeQDIC(jisho); jisho = opendict(jisho, jishoname);
jisho = openQDIC(dictname); zidian = opendict(zidian, zidianname);
llen = 0; llen = 0;
olen = okuri = joshi = 0; olen = okuri = joshi = 0;
wantmore=0; wantmore=0;
@ -156,6 +214,9 @@ main(int argc, char *argv[])
continue; continue;
} }
if (*bp=='') { /* ^\ (start translation command) */ if (*bp=='') { /* ^\ (start translation command) */
if (table == hanzi)
c = dotrans(zidian);
else
c = dotrans(jisho); c = dotrans(jisho);
if (c) if (c)
*bp = c; /* pointer to translated rune */ *bp = c; /* pointer to translated rune */
@ -167,11 +228,13 @@ main(int argc, char *argv[])
bp++; bp++;
llen = 0; llen = 0;
olen = okuri = joshi = 0; olen = okuri = joshi = 0;
last.kana = nil;
continue; continue;
} }
if (changelang(*bp)) { /* change language mode OK */ if (changelang(*bp)) { /* change language mode OK */
bp++; bp++;
olen = okuri = joshi = 0; olen = okuri = joshi = 0;
last.kana = nil;
continue; continue;
} }
if (natural || *bp<=' ' || *bp>='{') { /* English mode but not ascii */ if (natural || *bp<=' ' || *bp>='{') { /* English mode but not ascii */
@ -179,6 +242,7 @@ main(int argc, char *argv[])
int rlen = chartorune(&r, (char *)bp); int rlen = chartorune(&r, (char *)bp);
send(bp, rlen); /* write bp to /dev/cons */ send(bp, rlen); /* write bp to /dev/cons */
bp += rlen; bp += rlen;
last.kana = nil;
continue; continue;
} }
if (table == hira && (*bp >= 'A' && *bp <= 'Z') && (*(bp+1) < 'A' if (table == hira && (*bp >= 'A' && *bp <= 'Z') && (*(bp+1) < 'A'
@ -192,25 +256,31 @@ main(int argc, char *argv[])
joshi = 1; joshi = 1;
olen = 0; olen = 0;
} }
mp = match(bp, &nchar, table); if(hmapget(table, (char*)bp, &lkup) < 0){
if (mp == 0) { if(last.kana != nil){
if (nchar>0) { /* match, longer possible */ send((uchar*)last.kana, strlen(last.kana));
wantmore++; bp += strlen(last.roma);
} else
send(bp++, 1);
last.kana = nil;
break; break;
} }
send(bp++, 1); /* alphabet in kana mode */ /* concatinations; only advance a single character */
} else { if(lkup.kana != nil && strstr("ッっ", lkup.kana))
send((uchar*)mp->kana, strlen(mp->kana)); lkup.roma = "_";
bp += nchar; /* partial match */
} if(lkup.kana == nil || lkup.leadstomore == 1){
} if(lkup.kana != nil)
} last = lkup;
}
int wantmore = 1;
min(int a, int b) break;
{ }
return a<b? a: b; last.kana = nil;
send((uchar*)lkup.kana, strlen(lkup.kana));
bp += strlen(lkup.roma);
}
}
} }
/* /*
@ -232,7 +302,9 @@ send(uchar *p, int n)
llen -= 64; llen -= 64;
} }
if (table!=hira || natural) if(table != hira && table != hanzi)
return;
if(natural && table != hanzi)
return; return;
ep = p+n; ep = p+n;
@ -253,49 +325,13 @@ send(uchar *p, int n)
} }
} }
/*
* Romaji to Hiragana/Katakana conversion
* romaji shoud be input as small letter
* returns the matched address in table, hira, kata, etc.
* nc: number of character (return value)
*/
Map *
match(uchar *p, int *nc, Map *table)
{
register Map *longp = 0, *kp;
static char last;
int longest = 0;
*nc = -1;
for (kp=table; kp->roma; kp++) {
if (*p == *kp->roma) {
int lr = strlen(kp->roma);
int len = min(lr, strlen((char *)p));
if (strncmp(kp->roma, (char *)p, len)==0) {
if (len<lr) {
*nc = 1;
return 0;
}
if (len>longest) {
longest = len;
longp = kp;
}
}
}
}
if (longp) {
last = longp->roma[longest-1];
*nc = longp->advance;
}
return longp;
}
int int
changelang(int c) changelang(int c)
{ {
switch(c){ switch(c){
case '': /* ^t (English mode) */ case '': /* ^t (English mode) */
natural = 1; natural = 1;
table = hira;
llen = 0; llen = 0;
return 1; return 1;
break; break;
@ -334,23 +370,80 @@ changelang(int c)
llen = 0; llen = 0;
return 1; return 1;
break; break;
case '': /* ^c (Chinese mode) */
natural = 1;
table = hanzi;
llen = 0;
return 1;
break;
} }
return 0; return 0;
} }
Hmap*
opendict(Hmap *h, char *name)
{
Biobuf *b;
char *p;
char *dot, *rest;
char *kouho[16];
int i;
b = Bopen(name, OREAD);
if(b == nil)
return nil;
if(h == nil)
h = hmapalloc(8192, sizeof(kouho));
else
hmapreset(h, 1);
while(p = Brdstr(b, '\n', 1)){
if(p[0] == '\0' || p[0] == ';'){
Err:
free(p);
continue;
}
dot = utfrune(p, '\t');
if(dot == nil)
goto Err;
*dot = '\0';
rest = dot+1;
if(*rest == '\0')
goto Err;
memset(kouho, 0, sizeof kouho);
i = 0;
while(i < nelem(kouho)-1 && (dot = utfrune(rest, ' '))){
*dot = '\0';
kouho[i++] = rest;
rest = dot+1;
}
if(i < nelem(kouho)-1)
kouho[i] = rest;
/* key is the base pointer; overwrites clean up for us */
hmaprepl(&h, p, kouho, nil, 1);
}
Bterm(b);
return h;
}
/* /*
* write translated kanji runes to stdout and return last character * write translated kanji runes to stdout and return last character
* if it's not ctl-\. if the last is ctl-\, proceed with * if it's not ctl-\. if the last is ctl-\, proceed with
* translation of the next kouho * translation of the next kouho
*/ */
int int
dotrans(Dictionary *dic) dotrans(Hmap *dic)
{ {
Rune *res, r[1]; Rune *res, r[1];
char v[1024], *p, tbuf[64], hirabuf[64]; char v[1024], *p, tbuf[64], hirabuf[64];
int j, lastlen, nokouho = 0; int j, lastlen, nokouho = 0;
char ch; char ch;
KouhoList *fstkouho, *currentkouho; int i;
char *kouho[16];
if (llen==0) if (llen==0)
return 0; /* don't use kanji transform function */ return 0; /* don't use kanji transform function */
@ -375,15 +468,13 @@ dotrans(Dictionary *dic)
if (okuri && joshi != 1) /* verb mode */ if (okuri && joshi != 1) /* verb mode */
hirabuf[strlen(hirabuf) - 1] = '\0'; hirabuf[strlen(hirabuf) - 1] = '\0';
if(!(fstkouho = getKouhoHash(dic, v))) { /* not found */ if(hmapget(dic, v, kouho) < 0){
llen = olen = okuri = joshi = 0; llen = olen = okuri = joshi = 0;
okurigana[0] = 0; okurigana[0] = 0;
return 0; return 0;
} }
for(i = 0; i < nelem(kouho) && kouho[i] != nil; i++) {
currentkouho = fstkouho; p = kouho[i];
for(;;) {
p = currentkouho->kouhotop; /* p to the head of kanji kouho array */
lastlen = nrune(tbuf); /* number of rune chars */ lastlen = nrune(tbuf); /* number of rune chars */
if (okuri && joshi != 1) /* verb mode */ if (okuri && joshi != 1) /* verb mode */
@ -407,10 +498,9 @@ dotrans(Dictionary *dic)
exits(nil); exits(nil);
if (ch == '') { /* if next input is ^\, once again */ if (ch == '') { /* if next input is ^\, once again */
if(currentkouho->nextkouho != 0) { /* have next kouho */ if(i+1 < nelem(kouho) && kouho[i+1] != nil) { /* have next kouho */
nokouho = 0; nokouho = 0;
strcpy(tbuf, p); strcpy(tbuf, p);
currentkouho = currentkouho->nextkouho;
if (okuri && joshi != 1) /* verb mode */ if (okuri && joshi != 1) /* verb mode */
for (j=0; j<nrune(tbuf); j++) for (j=0; j<nrune(tbuf); j++)
@ -442,8 +532,12 @@ dotrans(Dictionary *dic)
break; break;
} }
} else { } else {
if(!nokouho) /* learn the previous use of the kouho */ if(!nokouho && i != 0){ /* learn the previous use of the kouho */
selectKouho(&(fstkouho->dicitem->kouho), currentkouho); p = kouho[0];
kouho[0] = kouho[i];
kouho[i] = p;
hmapupd(&dic, v, kouho);
}
olen = okuri = joshi = 0; olen = okuri = joshi = 0;
okurigana[0] = 0; okurigana[0] = 0;

View file

@ -2,9 +2,9 @@
BIN=/$objtype/bin BIN=/$objtype/bin
TARG=ktrans TARG=ktrans
HFILES=jisho.h ktrans.h HFILES=ktrans.h
OFILES=\ OFILES=\
hash.$O\
main.$O\ main.$O\
jisho.$O
</sys/src/cmd/mkone </sys/src/cmd/mkone