9fans.net/go@v0.0.7/cmd/devdraw/mklatinkbd.go (about)

     1  // +build ignore
     2  
     3  /*
     4   * Parse /lib/keyboard to create latin1.h table for kernel.
     5   * mklatinkbd -r prints an array of integers rather than a Rune string literal.
     6   */
     7  
     8  package main
     9  
    10  var rflag int
    11  var xflag int
    12  
    13  const MAXLD = 2 /* latin1.c assumes this is 2 */
    14  
    15  var head *C.char = "" + "/*\n" + " * This is automatically generated by %s from /lib/keyboard\n" + " * Edit /lib/keyboard instead.\n" + " */\n"
    16  
    17  /*
    18   * latin1.c assumes that strlen(ld) is at most 2.
    19   * It also assumes that latintab[i].ld can be a prefix of latintab[j].ld
    20   * only when j < i.  We ensure this by sorting the output by prefix length.
    21   * The so array is indexed by the character value.
    22   */
    23  
    24  type Trie struct {
    25  	n    int
    26  	seq  [MAXLD + 1 + 1]C.char
    27  	r    [256]rune
    28  	link [256]*Trie
    29  }
    30  
    31  var root *Trie
    32  
    33  func mktrie(seq []C.char) *Trie {
    34  	if root == nil {
    35  		root = malloc(sizeof(*root))
    36  		memset(root, 0, sizeof(*root))
    37  	}
    38  
    39  	assert(seq[0] != '\x00')
    40  
    41  	tp := &root
    42  	for q := (*uint8)(seq); *(q + 1) != '\x00'; q++ {
    43  		tp = &(*tp).link[*q]
    44  		if *tp == nil {
    45  			*tp = malloc(sizeof(**tp))
    46  			assert(*tp != nil)
    47  			memset(*tp, 0, sizeof(**tp))
    48  			strcpy((*tp).seq, seq)
    49  			(*tp).seq[q+1-(*uint8)(seq)] = '\x00'
    50  		}
    51  	}
    52  
    53  	assert(*tp != nil)
    54  	return *tp
    55  }
    56  
    57  /* add character sequence s meaning rune r */
    58  func insert(s []C.char, r rune) {
    59  	len := strlen(s)
    60  	lastc := uint8(s[len-1])
    61  
    62  	t := mktrie(s)
    63  	if t.r[lastc] != 0 {
    64  		fprint(2, "warning: table duplicate: %s is %C and %C\n", s, t.r[lastc], r)
    65  		return
    66  	}
    67  	t.r[lastc] = r
    68  	t.n++
    69  }
    70  
    71  func cprintchar(b *Biobuf, c int) {
    72  	/* print a byte c safe for a C string. */
    73  	switch c {
    74  	case '\'',
    75  		'"',
    76  		'\\':
    77  		Bprint(b, "\\%c", c)
    78  	case '\t':
    79  		Bprint(b, "\\t")
    80  	default:
    81  		if isascii(c) != 0 && isprint(c) != 0 {
    82  			Bprint(b, "%c", c)
    83  		} else {
    84  			Bprint(b, "\\x%.2x", c)
    85  		}
    86  	}
    87  }
    88  
    89  func cprints(b *Biobuf, p *C.char) {
    90  	for *p != '\x00' {
    91  		cprintchar(b, *p)
    92  		p++
    93  	}
    94  }
    95  
    96  func xprint(b *Biobuf, c int) {
    97  }
    98  
    99  func printtrie(b *Biobuf, t *Trie) {
   100  	var i int
   101  	for i = 0; i < 256; i++ {
   102  		if t.link[i] != 0 {
   103  			printtrie(b, t.link[i])
   104  		}
   105  	}
   106  	if t.n == 0 {
   107  		return
   108  	}
   109  
   110  	if xflag != 0 {
   111  		for i = 0; i < 256; i++ {
   112  			if t.r[i] == 0 {
   113  				continue
   114  			}
   115  			Bprint(b, "<Multi_key>")
   116  			for p := t.seq; *p != 0; p++ {
   117  				Bprint(b, " %k", *p)
   118  			}
   119  			Bprint(b, " %k : \"%C\" U%04X\n", i, t.r[i], t.r[i])
   120  		}
   121  		return
   122  	}
   123  
   124  	Bprint(b, "\t\"")
   125  	cprints(b, t.seq)
   126  	Bprint(b, "\", \"")
   127  	for i = 0; i < 256; i++ {
   128  		if t.r[i] != 0 {
   129  			cprintchar(b, i)
   130  		}
   131  	}
   132  	Bprint(b, "\",\t")
   133  	if rflag != 0 {
   134  		Bprint(b, "{")
   135  		for i = 0; i < 256; i++ {
   136  			if t.r[i] != 0 {
   137  				Bprint(b, " 0x%.4ux,", t.r[i])
   138  			}
   139  		}
   140  		Bprint(b, " }")
   141  	} else {
   142  		Bprint(b, "L\"")
   143  		for i = 0; i < 256; i++ {
   144  			if t.r[i] != 0 {
   145  				Bprint(b, "%C", t.r[i])
   146  			}
   147  		}
   148  		Bprint(b, "\"")
   149  	}
   150  	Bprint(b, ",\n")
   151  }
   152  
   153  func readfile(fname *C.char) {
   154  	b := Bopen(fname, OREAD)
   155  	if b == 0 {
   156  		fprint(2, "cannot open \"%s\": %r\n", fname)
   157  		exits("open")
   158  	}
   159  
   160  	lineno := 0
   161  	for {
   162  		line := Brdline(b, '\n')
   163  		if line == 0 {
   164  			break
   165  		}
   166  		lineno++
   167  		if line[0] == '#' {
   168  			continue
   169  		}
   170  
   171  		r := strtol(line, nil, 16)
   172  		p := strchr(line, ' ')
   173  		if r == 0 || (p != line+4 && p != line+5) || p[0] != ' ' || (p == line+4 && p[1] != ' ') {
   174  			fprint(2, "%s:%d: cannot parse line\n", fname, lineno)
   175  			continue
   176  		}
   177  
   178  		p = line + 6
   179  		/*	00AE  Or rO       ®	registered trade mark sign	*/
   180  		inseq := 1
   181  		seq := p
   182  		for ; uint8(*p) < Runeself; p++ {
   183  			if *p == '\x00' || isspace(*p) != 0 {
   184  				if inseq != 0 && p-seq >= 2 {
   185  					*p = '\x00'
   186  					inseq = 0
   187  					insert(seq, r)
   188  					*p = ' '
   189  				}
   190  				if *p == '\x00' {
   191  					break
   192  				}
   193  			} else {
   194  				if inseq == 0 {
   195  					seq = p
   196  					inseq = 1
   197  				}
   198  			}
   199  		}
   200  	}
   201  }
   202  
   203  func usage() {
   204  	fprint(2, "usage: mklatinkbd [-r] [/lib/keyboard]\n")
   205  	exits("usage")
   206  }
   207  
   208  func main(argc int, argv []*C.char) {
   209  	switch ARGBEGIN {
   210  	case 'r': /* print rune values */
   211  		rflag = 1
   212  	case 'x':
   213  		xflag = 1
   214  	default:
   215  		usage()
   216  	}
   217  
   218  	if argc > 1 {
   219  		usage()
   220  	}
   221  
   222  	fmtinstall('k', kfmt)
   223  	var tmp2 unknown
   224  	if argc == 1 {
   225  		tmp2 = argv[0]
   226  	} else {
   227  		tmp2 = "/dev/stdin"
   228  	}
   229  	readfile(tmp2)
   230  	var bout Biobuf
   231  
   232  	Binit(&bout, 1, OWRITE)
   233  	if xflag != 0 {
   234  		Bprint(&bout, "# Generated by mklatinkbd -x; do not edit.\n")
   235  		for i := 0x20; i < 0x10000; i++ {
   236  			Bprint(&bout, "<Multi_key> <X> <%x> <%x> <%x> <%x> : \"%C\" U%04X\n", (i>>12)&0xf, (i>>8)&0xf, (i>>4)&0xf, i&0xf, i, i)
   237  		}
   238  	}
   239  	if root != nil {
   240  		printtrie(&bout, root)
   241  	}
   242  	exits(0)
   243  }
   244  
   245  // X11 key names
   246  
   247  var xkey = [68]struct {
   248  	c int
   249  	s *C.char
   250  }{
   251  	' ', "space",
   252  	'!', "exclam",
   253  	'"', "quotedbl",
   254  	'#', "numbersign",
   255  	'$', "dollar",
   256  	'%', "percent",
   257  	'&', "ampersand",
   258  	'\'', "apostrophe",
   259  	'(', "parenleft",
   260  	')', "parenright",
   261  	'*', "asterisk",
   262  	'+', "plus",
   263  	',', "comma",
   264  	'-', "minus",
   265  	'.', "period",
   266  	'/', "slash",
   267  	':', "colon",
   268  	';', "semicolon",
   269  	'<', "less",
   270  	'=', "equal",
   271  	'>', "greater",
   272  	'?', "question",
   273  	'@', "at",
   274  	'[', "bracketleft",
   275  	'\\', "backslash",
   276  	',', "bracketright",
   277  	'^', "asciicircum",
   278  	'_', "underscore",
   279  	'`', "grave",
   280  	'{', "braceleft",
   281  	'|', "bar",
   282  	'}', "braceright",
   283  	'~', "asciitilde",
   284  	0, 0,
   285  }
   286  
   287  func kfmt(f *Fmt) int {
   288  	c := va_arg(f.args, int)
   289  	for i := 0; xkey[i].s != 0; i++ {
   290  		if xkey[i].c == c {
   291  			return fmtprint(f, "<%s>", xkey[i].s)
   292  		}
   293  	}
   294  	return fmtprint(f, "<%c>", c)
   295  }