]> jfr.im git - solanum.git/blame - ircd/match.c
Centralise banmask matching logic
[solanum.git] / ircd / match.c
CommitLineData
212380e3
AC
1/************************************************************************
2 * IRC - Internet Relay Chat, src/match.c
3 * Copyright (C) 1990 Jarkko Oikarinen
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 1, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
212380e3
AC
19 */
20#include "stdinc.h"
9b8e9eb3 21#include "defaults.h"
212380e3
AC
22#include "client.h"
23#include "ircd.h"
4562c604 24#include "match.h"
77d3d2db 25#include "s_assert.h"
212380e3
AC
26
27/*
28 * Compare if a given string (name) matches the given
29 * mask (which can contain wild cards: '*' - match any
30 * number of chars, '?' - match any single character.
31 *
32 * return 1, if match
33 * 0, if no match
34 *
35 * Originally by Douglas A Lewis (dalewis@acsu.buffalo.edu)
36 * Rewritten by Timothy Vogelsang (netski), net@astrolink.org
37 */
38
39/** Check a string against a mask.
40 * This test checks using traditional IRC wildcards only: '*' means
41 * match zero or more characters of any type; '?' means match exactly
42 * one character of any type.
43 *
44 * @param[in] mask Wildcard-containing mask.
45 * @param[in] name String to check against \a mask.
46 * @return Zero if \a mask matches \a name, non-zero if no match.
47 */
48int match(const char *mask, const char *name)
49{
50 const char *m = mask, *n = name;
51 const char *m_tmp = mask, *n_tmp = name;
52 int star_p;
53
54 s_assert(mask != NULL);
55 s_assert(name != NULL);
56
57 for (;;)
58 {
59 switch (*m)
60 {
61 case '\0':
62 if (!*n)
63 return 1;
64 backtrack:
65 if (m_tmp == mask)
66 return 0;
67 m = m_tmp;
68 n = ++n_tmp;
69 break;
70 case '*':
71 case '?':
72 for (star_p = 0;; m++)
73 {
74 if (*m == '*')
75 star_p = 1;
76 else if (*m == '?')
77 {
78 if (!*n++)
79 goto backtrack;
80 }
81 else
82 break;
83 }
84 if (star_p)
85 {
86 if (!*m)
87 return 1;
88 else
89 {
90 m_tmp = m;
7e6b5384 91 for (n_tmp = n; *n && irctolower(*n) != irctolower(*m); n++);
212380e3
AC
92 }
93 }
94 /* and fall through */
95 default:
96 if (!*n)
97 return (*m != '\0' ? 0 : 1);
7e6b5384 98 if (irctolower(*m) != irctolower(*n))
212380e3
AC
99 goto backtrack;
100 m++;
101 n++;
102 break;
103 }
104 }
105}
106
df251055
JT
107/** Check a mask against a mask.
108 * This test checks using traditional IRC wildcards only: '*' means
109 * match zero or more characters of any type; '?' means match exactly
110 * one character of any type.
111 * The difference between mask_match() and match() is that in mask_match()
112 * a '?' in mask does not match a '*' in name.
113 *
114 * @param[in] mask Existing wildcard-containing mask.
115 * @param[in] name New wildcard-containing mask.
116 * @return 1 if \a name is equal to or more specific than \a mask, 0 otherwise.
117 */
118int mask_match(const char *mask, const char *name)
119{
120 const char *m = mask, *n = name;
121 const char *m_tmp = mask, *n_tmp = name;
122 int star_p;
123
124 s_assert(mask != NULL);
125 s_assert(name != NULL);
126
127 for (;;)
128 {
129 switch (*m)
130 {
131 case '\0':
132 if (!*n)
133 return 1;
134 backtrack:
135 if (m_tmp == mask)
136 return 0;
137 m = m_tmp;
138 n = ++n_tmp;
139 break;
140 case '*':
141 case '?':
142 for (star_p = 0;; m++)
143 {
144 if (*m == '*')
145 star_p = 1;
146 else if (*m == '?')
147 {
148 /* changed for mask_match() */
149 if (*n == '*' || !*n)
150 goto backtrack;
151 n++;
152 }
153 else
154 break;
155 }
156 if (star_p)
157 {
158 if (!*m)
159 return 1;
160 else
161 {
162 m_tmp = m;
7e6b5384 163 for (n_tmp = n; *n && irctolower(*n) != irctolower(*m); n++);
df251055
JT
164 }
165 }
166 /* and fall through */
167 default:
168 if (!*n)
169 return (*m != '\0' ? 0 : 1);
7e6b5384 170 if (irctolower(*m) != irctolower(*n))
df251055
JT
171 goto backtrack;
172 m++;
173 n++;
174 break;
175 }
176 }
177}
178
179
7eecdd68
JT
180#define MATCH_MAX_CALLS 512 /* ACK! This dies when it's less that this
181 and we have long lines to parse */
212380e3 182/** Check a string against a mask.
7eecdd68
JT
183 * This test checks using extended wildcards: '*' means match zero
184 * or more characters of any type; '?' means match exactly one
185 * character of any type; '#' means match exactly one character that
186 * is a number; '@' means match exactly one character that is a
187 * letter; '\s' means match a space.
212380e3 188 *
55abcbb2 189 * This function supports escaping, so that a wildcard may be matched
212380e3
AC
190 * exactly.
191 *
192 * @param[in] mask Wildcard-containing mask.
193 * @param[in] name String to check against \a mask.
194 * @return Zero if \a mask matches \a name, non-zero if no match.
195 */
7eecdd68
JT
196int
197match_esc(const char *mask, const char *name)
212380e3 198{
7eecdd68
JT
199 const unsigned char *m = (const unsigned char *)mask;
200 const unsigned char *n = (const unsigned char *)name;
201 const unsigned char *ma = (const unsigned char *)mask;
202 const unsigned char *na = (const unsigned char *)name;
203 int wild = 0;
204 int calls = 0;
205 int quote = 0;
206 int match1 = 0;
212380e3
AC
207
208 s_assert(mask != NULL);
209 s_assert(name != NULL);
210
7eecdd68
JT
211 if(!mask || !name)
212 return 0;
213
214 /* if the mask is "*", it matches everything */
215 if((*m == '*') && (*(m + 1) == '\0'))
216 return 1;
217
218 while(calls++ < MATCH_MAX_CALLS)
212380e3 219 {
7eecdd68
JT
220 if(quote)
221 quote++;
222 if(quote == 3)
223 quote = 0;
224 if(*m == '\\' && !quote)
212380e3 225 {
7eecdd68
JT
226 m++;
227 quote = 1;
228 continue;
229 }
230 if(!quote && *m == '*')
231 {
232 /*
233 * XXX - shouldn't need to spin here, the mask should have been
234 * collapsed before match is called
235 */
236 while(*m == '*')
237 m++;
238
239 wild = 1;
240 ma = m;
241 na = n;
242
243 if(*m == '\\')
244 {
245 m++;
246 /* This means it is an invalid mask -A1kmm. */
247 if(!*m)
248 return 0;
249 quote++;
250 continue;
251 }
252 }
253
254 if(!*m)
255 {
256 if(!*n)
257 return 1;
258 if(quote)
259 return 0;
5ef68b13
JT
260 for(m--; (m > (const unsigned char *)mask) && (*m == '?'); m--)
261 ;
7eecdd68
JT
262
263 if(*m == '*' && (m > (const unsigned char *)mask))
264 return 1;
265 if(!wild)
266 return 0;
267 m = ma;
268 n = ++na;
269 }
270 else if(!*n)
271 {
272 /*
273 * XXX - shouldn't need to spin here, the mask should have been
274 * collapsed before match is called
275 */
276 if(quote)
277 return 0;
278 while(*m == '*')
279 m++;
280 return (*m == 0);
281 }
282
283 if(quote)
7e6b5384 284 match1 = *m == 's' ? *n == ' ' : irctolower(*m) == irctolower(*n);
7eecdd68
JT
285 else if(*m == '?')
286 match1 = 1;
287 else if(*m == '@')
288 match1 = IsLetter(*n);
289 else if(*m == '#')
290 match1 = IsDigit(*n);
291 else
7e6b5384 292 match1 = irctolower(*m) == irctolower(*n);
7eecdd68
JT
293 if(match1)
294 {
295 if(*m)
296 m++;
297 if(*n)
298 n++;
299 }
300 else
301 {
302 if(!wild)
303 return 0;
304 m = ma;
305 n = ++na;
212380e3
AC
306 }
307 }
7eecdd68 308 return 0;
212380e3
AC
309}
310
4b11f391 311int comp_with_mask(void *addr, void *dest, unsigned int mask)
212380e3
AC
312{
313 if (memcmp(addr, dest, mask / 8) == 0)
314 {
315 int n = mask / 8;
d8f0b5d7 316 unsigned char m = (0xFF << (8 - (mask % 8)));
4b11f391 317 if (mask % 8 == 0 || (((unsigned char *) addr)[n] & m) == (((unsigned char *) dest)[n] & m))
212380e3
AC
318 {
319 return (1);
320 }
321 }
322 return (0);
323}
324
4b11f391 325int comp_with_mask_sock(struct sockaddr *addr, struct sockaddr *dest, unsigned int mask)
212380e3
AC
326{
327 void *iaddr = NULL;
328 void *idest = NULL;
329
330 if (addr->sa_family == AF_INET)
331 {
29c92cf9
JB
332 iaddr = &((struct sockaddr_in *)(void *)addr)->sin_addr;
333 idest = &((struct sockaddr_in *)(void *)dest)->sin_addr;
212380e3 334 }
212380e3
AC
335 else
336 {
29c92cf9
JB
337 iaddr = &((struct sockaddr_in6 *)(void *)addr)->sin6_addr;
338 idest = &((struct sockaddr_in6 *)(void *)dest)->sin6_addr;
212380e3
AC
339
340 }
212380e3
AC
341
342 return (comp_with_mask(iaddr, idest, mask));
343}
344
345/*
346 * match_ips()
347 *
348 * Input - cidr ip mask, address
349 */
350int match_ips(const char *s1, const char *s2)
351{
e7046ee5 352 struct rb_sockaddr_storage ipaddr, maskaddr;
212380e3
AC
353 char mask[BUFSIZE];
354 char address[HOSTLEN + 1];
355 char *len;
356 void *ipptr, *maskptr;
357 int cidrlen, aftype;
358
4d5a902f
AJ
359 rb_strlcpy(mask, s1, sizeof(mask));
360 rb_strlcpy(address, s2, sizeof(address));
212380e3
AC
361
362 len = strrchr(mask, '/');
363 if (len == NULL)
364 return 0;
365
366 *len++ = '\0';
367
368 cidrlen = atoi(len);
441da2f2 369 if (cidrlen <= 0)
212380e3
AC
370 return 0;
371
212380e3
AC
372 if (strchr(mask, ':') && strchr(address, ':'))
373 {
441da2f2
JT
374 if (cidrlen > 128)
375 return 0;
376
212380e3
AC
377 aftype = AF_INET6;
378 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
379 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
380 }
de293496 381 else if (!strchr(mask, ':') && !strchr(address, ':'))
212380e3 382 {
441da2f2
JT
383 if (cidrlen > 32)
384 return 0;
385
212380e3
AC
386 aftype = AF_INET;
387 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
388 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
389 }
390 else
391 return 0;
392
83e5941c
JT
393 if (rb_inet_pton(aftype, address, ipptr) <= 0)
394 return 0;
395 if (rb_inet_pton(aftype, mask, maskptr) <= 0)
396 return 0;
212380e3
AC
397 if (comp_with_mask(ipptr, maskptr, cidrlen))
398 return 1;
399 else
400 return 0;
401}
402
403/* match_cidr()
404 *
405 * Input - mask, address
406 * Ouput - 1 = Matched 0 = Did not match
407 */
408
409int match_cidr(const char *s1, const char *s2)
410{
e7046ee5 411 struct rb_sockaddr_storage ipaddr, maskaddr;
212380e3
AC
412 char mask[BUFSIZE];
413 char address[NICKLEN + USERLEN + HOSTLEN + 6];
414 char *ipmask;
415 char *ip;
416 char *len;
417 void *ipptr, *maskptr;
418 int cidrlen, aftype;
419
4d5a902f
AJ
420 rb_strlcpy(mask, s1, sizeof(mask));
421 rb_strlcpy(address, s2, sizeof(address));
212380e3
AC
422
423 ipmask = strrchr(mask, '@');
424 if (ipmask == NULL)
425 return 0;
426
427 *ipmask++ = '\0';
428
429 ip = strrchr(address, '@');
430 if (ip == NULL)
431 return 0;
432 *ip++ = '\0';
433
434
435 len = strrchr(ipmask, '/');
436 if (len == NULL)
437 return 0;
438
439 *len++ = '\0';
440
441 cidrlen = atoi(len);
4dbd5e07 442 if (cidrlen <= 0)
212380e3
AC
443 return 0;
444
212380e3
AC
445 if (strchr(ip, ':') && strchr(ipmask, ':'))
446 {
4dbd5e07
JT
447 if (cidrlen > 128)
448 return 0;
449
212380e3
AC
450 aftype = AF_INET6;
451 ipptr = &((struct sockaddr_in6 *)&ipaddr)->sin6_addr;
452 maskptr = &((struct sockaddr_in6 *)&maskaddr)->sin6_addr;
453 }
de293496 454 else if (!strchr(ip, ':') && !strchr(ipmask, ':'))
212380e3 455 {
4dbd5e07
JT
456 if (cidrlen > 32)
457 return 0;
458
212380e3
AC
459 aftype = AF_INET;
460 ipptr = &((struct sockaddr_in *)&ipaddr)->sin_addr;
461 maskptr = &((struct sockaddr_in *)&maskaddr)->sin_addr;
462 }
463 else
464 return 0;
465
83e5941c
JT
466 if (rb_inet_pton(aftype, ip, ipptr) <= 0)
467 return 0;
468 if (rb_inet_pton(aftype, ipmask, maskptr) <= 0)
469 return 0;
212380e3
AC
470 if (comp_with_mask(ipptr, maskptr, cidrlen) && match(mask, address))
471 return 1;
472 else
473 return 0;
474}
475
476/* collapse()
477 *
478 * collapses a string containing multiple *'s.
479 */
480char *collapse(char *pattern)
481{
482 char *p = pattern, *po = pattern;
483 char c;
484 int f = 0;
485
486 if (p == NULL)
487 return NULL;
488
489 while ((c = *p++))
490 {
491 if (c == '*')
492 {
493 if (!(f & 1))
494 *po++ = '*';
495 f |= 1;
496 }
497 else
498 {
499 *po++ = c;
500 f &= ~1;
501 }
502 }
503 *po++ = 0;
504
505 return pattern;
506}
507
508/* collapse_esc()
509 *
510 * The collapse() function with support for escaping characters
511 */
512char *collapse_esc(char *pattern)
513{
514 char *p = pattern, *po = pattern;
515 char c;
516 int f = 0;
517
518 if (p == NULL)
519 return NULL;
520
521 while ((c = *p++))
522 {
523 if (!(f & 2) && c == '*')
524 {
525 if (!(f & 1))
526 *po++ = '*';
527 f |= 1;
528 }
529 else if (!(f & 2) && c == '\\')
530 {
531 *po++ = '\\';
532 f |= 2;
533 }
534 else
535 {
536 *po++ = c;
537 f &= ~3;
538 }
539 }
540 *po++ = 0;
541 return pattern;
542}
543
544/*
545 * irccmp - case insensitive comparison of two 0 terminated strings.
546 *
547 * returns 0, if s1 equal to s2
548 * <0, if s1 lexicographically less than s2
549 * >0, if s1 lexicographically greater than s2
550 */
551int irccmp(const char *s1, const char *s2)
552{
553 const unsigned char *str1 = (const unsigned char *)s1;
554 const unsigned char *str2 = (const unsigned char *)s2;
555 int res;
556
557 s_assert(s1 != NULL);
558 s_assert(s2 != NULL);
559
7e6b5384 560 while ((res = irctoupper(*str1) - irctoupper(*str2)) == 0)
212380e3
AC
561 {
562 if (*str1 == '\0')
563 return 0;
564 str1++;
565 str2++;
566 }
567 return (res);
568}
569
570int ircncmp(const char *s1, const char *s2, int n)
571{
572 const unsigned char *str1 = (const unsigned char *)s1;
573 const unsigned char *str2 = (const unsigned char *)s2;
574 int res;
575 s_assert(s1 != NULL);
576 s_assert(s2 != NULL);
577
7e6b5384 578 while ((res = irctoupper(*str1) - irctoupper(*str2)) == 0)
212380e3
AC
579 {
580 str1++;
581 str2++;
582 n--;
583 if (n == 0 || (*str1 == '\0' && *str2 == '\0'))
584 return 0;
585 }
586 return (res);
587}
588
a7d4a0ab
EK
589void matchset_for_client(struct Client *who, struct matchset *m)
590{
591 unsigned hostn = 0;
592 unsigned ipn = 0;
593
594 struct sockaddr_in ip4;
595
596 sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->host);
597 sprintf(m->ip[ipn++], "%s!%s@%s", who->name, who->username, who->sockhost);
598 if (who->localClient->mangledhost != NULL)
599 {
600 /* if host mangling mode enabled, also check their real host */
601 if (!strcmp(who->host, who->localClient->mangledhost))
602 {
603 sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->orighost);
604 }
605 /* if host mangling mode not enabled and no other spoof,
606 * also check the mangled form of their host */
607 else if (!IsDynSpoof(who))
608 {
609 sprintf(m->host[hostn++], "%s!%s@%s", who->name, who->username, who->localClient->mangledhost);
610 }
611 }
612 if (GET_SS_FAMILY(&who->localClient->ip) == AF_INET6 &&
613 rb_ipv4_from_ipv6((const struct sockaddr_in6 *)&who->localClient->ip, &ip4))
614 {
615 int n = sprintf(m->ip[ipn++], "%s!%s@", who->name, who->username);
616 rb_inet_ntop_sock((struct sockaddr *)&ip4,
617 m->ip[ipn] + n, sizeof m->ip[ipn] - n);
618 }
619
620 for (int i = hostn; i < ARRAY_SIZE(m->host); i++)
621 {
622 m->host[i][0] = '\0';
623 }
624 for (int i = ipn; i < ARRAY_SIZE(m->ip); i++)
625 {
626 m->ip[i][0] = '\0';
627 }
628}
629
630bool client_matches_mask(struct Client *who, const char *mask)
631{
632 static struct matchset ms;
633 matchset_for_client(who, &ms);
634 return matches_mask(&ms, mask);
635}
636
637bool matches_mask(const struct matchset *m, const char *mask)
638{
639 for (int i = 0; i < ARRAY_SIZE(m->host); i++)
640 {
641 if (m->host[i][0] == '\0')
642 break;
643 if (match(mask, m->host[i]))
644 return true;
645 }
646 for (int i = 0; i < ARRAY_SIZE(m->ip); i++)
647 {
648 if (m->ip[i][0] == '\0')
649 break;
650 if (match(mask, m->ip[i]))
651 return true;
652 if (match_cidr(mask, m->ip[i]))
653 return true;
654 }
655 return false;
656}
657
7e6b5384 658const unsigned char irctolower_tab[] = {
212380e3
AC
659 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
660 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
661 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
662 0x1e, 0x1f,
663 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
664 '*', '+', ',', '-', '.', '/',
665 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
666 ':', ';', '<', '=', '>', '?',
667 '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
668 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
669 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
670 '_',
671 '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
672 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
673 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~',
674 0x7f,
675 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
676 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
677 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
678 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
679 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
680 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
681 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
682 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
683 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
684 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
685 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
686 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
687 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
688 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
689 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
690 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
691};
692
7e6b5384 693const unsigned char irctoupper_tab[] = {
212380e3
AC
694 0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa,
695 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13, 0x14,
696 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
697 0x1e, 0x1f,
698 ' ', '!', '"', '#', '$', '%', '&', 0x27, '(', ')',
699 '*', '+', ',', '-', '.', '/',
700 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
701 ':', ';', '<', '=', '>', '?',
702 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
703 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
704 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
705 0x5f,
706 '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
707 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
708 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^',
709 0x7f,
710 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
711 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
712 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99,
713 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
714 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,
715 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
716 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9,
717 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
718 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9,
719 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
720 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9,
721 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
722 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
723 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
724 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9,
725 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
726};
727
728/*
729 * CharAttrs table
730 *
731 * NOTE: RFC 1459 sez: anything but a ^G, comma, or space is allowed
732 * for channel names
733 */
f3b84221 734unsigned int CharAttrs[] = {
212380e3
AC
735/* 0 */ CNTRL_C,
736/* 1 */ CNTRL_C | CHAN_C | NONEOS_C,
737/* 2 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
738/* 3 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
739/* 4 */ CNTRL_C | CHAN_C | NONEOS_C,
740/* 5 */ CNTRL_C | CHAN_C | NONEOS_C,
741/* 6 */ CNTRL_C | CHAN_C | NONEOS_C,
742/* 7 BEL */ CNTRL_C | NONEOS_C,
743/* 8 \b */ CNTRL_C | CHAN_C | NONEOS_C,
744/* 9 \t */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
745/* 10 \n */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
746/* 11 \v */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
747/* 12 \f */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C,
748/* 13 \r */ CNTRL_C | SPACE_C | CHAN_C | NONEOS_C | EOL_C,
749/* 14 */ CNTRL_C | CHAN_C | NONEOS_C,
750/* 15 */ CNTRL_C | CHAN_C | NONEOS_C,
751/* 16 */ CNTRL_C | CHAN_C | NONEOS_C,
752/* 17 */ CNTRL_C | CHAN_C | NONEOS_C,
753/* 18 */ CNTRL_C | CHAN_C | NONEOS_C,
754/* 19 */ CNTRL_C | CHAN_C | NONEOS_C,
755/* 20 */ CNTRL_C | CHAN_C | NONEOS_C,
756/* 21 */ CNTRL_C | CHAN_C | NONEOS_C,
757/* 22 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
758/* 23 */ CNTRL_C | CHAN_C | NONEOS_C,
759/* 24 */ CNTRL_C | CHAN_C | NONEOS_C,
760/* 25 */ CNTRL_C | CHAN_C | NONEOS_C,
761/* 26 */ CNTRL_C | CHAN_C | NONEOS_C,
762/* 27 */ CNTRL_C | CHAN_C | NONEOS_C,
763/* 28 */ CNTRL_C | CHAN_C | NONEOS_C,
b19d3c51 764/* 29 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
212380e3
AC
765/* 30 */ CNTRL_C | CHAN_C | NONEOS_C,
766/* 31 */ CNTRL_C | CHAN_C | FCHAN_C | NONEOS_C,
767/* SP */ PRINT_C | SPACE_C,
768/* ! */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C,
769/* " */ PRINT_C | CHAN_C | NONEOS_C,
770/* # */ PRINT_C | MWILD_C | CHANPFX_C | CHAN_C | NONEOS_C,
f2edb2be 771/* $ */ PRINT_C | CHAN_C | NONEOS_C,
212380e3
AC
772/* % */ PRINT_C | CHAN_C | NONEOS_C,
773/* & */ PRINT_C | CHANPFX_C | CHAN_C | NONEOS_C,
774/* ' */ PRINT_C | CHAN_C | NONEOS_C,
775/* ( */ PRINT_C | CHAN_C | NONEOS_C,
776/* ) */ PRINT_C | CHAN_C | NONEOS_C,
e5d9ca18 777/* * */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
212380e3
AC
778/* + */ PRINT_C | CHAN_C | NONEOS_C,
779/* , */ PRINT_C | NONEOS_C,
780/* - */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
781/* . */ PRINT_C | KWILD_C | CHAN_C | NONEOS_C | USER_C | HOST_C | SERV_C,
9a180ae3 782/* / */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
212380e3
AC
783/* 0 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
784/* 1 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
785/* 2 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
786/* 3 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
787/* 4 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
788/* 5 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
789/* 6 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
790/* 7 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
791/* 8 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
792/* 9 */ PRINT_C | DIGIT_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
793/* : */ PRINT_C | CHAN_C | NONEOS_C | HOST_C,
794/* ; */ PRINT_C | CHAN_C | NONEOS_C,
795/* < */ PRINT_C | CHAN_C | NONEOS_C,
796/* = */ PRINT_C | CHAN_C | NONEOS_C,
797/* > */ PRINT_C | CHAN_C | NONEOS_C,
798/* ? */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
799/* @ */ PRINT_C | KWILD_C | MWILD_C | CHAN_C | NONEOS_C,
800/* A */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
801/* B */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
802/* C */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
803/* D */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
804/* E */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
805/* F */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
806/* G */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
807/* H */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
808/* I */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
809/* J */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
810/* K */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
811/* L */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
812/* M */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
813/* N */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
814/* O */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
815/* P */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
816/* Q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
817/* R */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
818/* S */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
819/* T */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
820/* U */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
821/* V */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
822/* W */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
823/* X */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
824/* Y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
825/* Z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
826/* [ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
827/* \ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
828/* ] */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
829/* ^ */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
830/* _ */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
831/* ` */ PRINT_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
832/* a */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
833/* b */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
834/* c */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
835/* d */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
836/* e */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
837/* f */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
838/* g */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
839/* h */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
840/* i */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
841/* j */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
842/* k */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
843/* l */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
844/* m */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
845/* n */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
846/* o */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
847/* p */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
848/* q */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
849/* r */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
850/* s */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
851/* t */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
852/* u */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
853/* v */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
854/* w */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
855/* x */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
856/* y */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
857/* z */ PRINT_C | ALPHA_C | LET_C | NICK_C | CHAN_C | NONEOS_C | USER_C | HOST_C,
858/* { */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
859/* | */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
860/* } */ PRINT_C | ALPHA_C | NICK_C | CHAN_C | NONEOS_C | USER_C,
861/* ~ */ PRINT_C | ALPHA_C | CHAN_C | NONEOS_C | USER_C,
862/* del */ CHAN_C | NONEOS_C,
863/* 0x80 */ CHAN_C | NONEOS_C,
864/* 0x81 */ CHAN_C | NONEOS_C,
865/* 0x82 */ CHAN_C | NONEOS_C,
866/* 0x83 */ CHAN_C | NONEOS_C,
867/* 0x84 */ CHAN_C | NONEOS_C,
868/* 0x85 */ CHAN_C | NONEOS_C,
869/* 0x86 */ CHAN_C | NONEOS_C,
870/* 0x87 */ CHAN_C | NONEOS_C,
871/* 0x88 */ CHAN_C | NONEOS_C,
872/* 0x89 */ CHAN_C | NONEOS_C,
873/* 0x8A */ CHAN_C | NONEOS_C,
874/* 0x8B */ CHAN_C | NONEOS_C,
875/* 0x8C */ CHAN_C | NONEOS_C,
876/* 0x8D */ CHAN_C | NONEOS_C,
877/* 0x8E */ CHAN_C | NONEOS_C,
878/* 0x8F */ CHAN_C | NONEOS_C,
879/* 0x90 */ CHAN_C | NONEOS_C,
880/* 0x91 */ CHAN_C | NONEOS_C,
881/* 0x92 */ CHAN_C | NONEOS_C,
882/* 0x93 */ CHAN_C | NONEOS_C,
883/* 0x94 */ CHAN_C | NONEOS_C,
884/* 0x95 */ CHAN_C | NONEOS_C,
885/* 0x96 */ CHAN_C | NONEOS_C,
886/* 0x97 */ CHAN_C | NONEOS_C,
887/* 0x98 */ CHAN_C | NONEOS_C,
888/* 0x99 */ CHAN_C | NONEOS_C,
889/* 0x9A */ CHAN_C | NONEOS_C,
890/* 0x9B */ CHAN_C | NONEOS_C,
891/* 0x9C */ CHAN_C | NONEOS_C,
892/* 0x9D */ CHAN_C | NONEOS_C,
893/* 0x9E */ CHAN_C | NONEOS_C,
894/* 0x9F */ CHAN_C | NONEOS_C,
895/* 0xA0 */ CHAN_C | FCHAN_C | NONEOS_C,
896/* 0xA1 */ CHAN_C | NONEOS_C,
897/* 0xA2 */ CHAN_C | NONEOS_C,
898/* 0xA3 */ CHAN_C | NONEOS_C,
899/* 0xA4 */ CHAN_C | NONEOS_C,
900/* 0xA5 */ CHAN_C | NONEOS_C,
901/* 0xA6 */ CHAN_C | NONEOS_C,
902/* 0xA7 */ CHAN_C | NONEOS_C,
903/* 0xA8 */ CHAN_C | NONEOS_C,
904/* 0xA9 */ CHAN_C | NONEOS_C,
905/* 0xAA */ CHAN_C | NONEOS_C,
906/* 0xAB */ CHAN_C | NONEOS_C,
907/* 0xAC */ CHAN_C | NONEOS_C,
908/* 0xAD */ CHAN_C | NONEOS_C,
909/* 0xAE */ CHAN_C | NONEOS_C,
910/* 0xAF */ CHAN_C | NONEOS_C,
911/* 0xB0 */ CHAN_C | NONEOS_C,
912/* 0xB1 */ CHAN_C | NONEOS_C,
913/* 0xB2 */ CHAN_C | NONEOS_C,
914/* 0xB3 */ CHAN_C | NONEOS_C,
915/* 0xB4 */ CHAN_C | NONEOS_C,
916/* 0xB5 */ CHAN_C | NONEOS_C,
917/* 0xB6 */ CHAN_C | NONEOS_C,
918/* 0xB7 */ CHAN_C | NONEOS_C,
919/* 0xB8 */ CHAN_C | NONEOS_C,
920/* 0xB9 */ CHAN_C | NONEOS_C,
921/* 0xBA */ CHAN_C | NONEOS_C,
922/* 0xBB */ CHAN_C | NONEOS_C,
923/* 0xBC */ CHAN_C | NONEOS_C,
924/* 0xBD */ CHAN_C | NONEOS_C,
925/* 0xBE */ CHAN_C | NONEOS_C,
926/* 0xBF */ CHAN_C | NONEOS_C,
927/* 0xC0 */ CHAN_C | NONEOS_C,
928/* 0xC1 */ CHAN_C | NONEOS_C,
929/* 0xC2 */ CHAN_C | NONEOS_C,
930/* 0xC3 */ CHAN_C | NONEOS_C,
931/* 0xC4 */ CHAN_C | NONEOS_C,
932/* 0xC5 */ CHAN_C | NONEOS_C,
933/* 0xC6 */ CHAN_C | NONEOS_C,
934/* 0xC7 */ CHAN_C | NONEOS_C,
935/* 0xC8 */ CHAN_C | NONEOS_C,
936/* 0xC9 */ CHAN_C | NONEOS_C,
937/* 0xCA */ CHAN_C | NONEOS_C,
938/* 0xCB */ CHAN_C | NONEOS_C,
939/* 0xCC */ CHAN_C | NONEOS_C,
940/* 0xCD */ CHAN_C | NONEOS_C,
941/* 0xCE */ CHAN_C | NONEOS_C,
942/* 0xCF */ CHAN_C | NONEOS_C,
943/* 0xD0 */ CHAN_C | NONEOS_C,
944/* 0xD1 */ CHAN_C | NONEOS_C,
945/* 0xD2 */ CHAN_C | NONEOS_C,
946/* 0xD3 */ CHAN_C | NONEOS_C,
947/* 0xD4 */ CHAN_C | NONEOS_C,
948/* 0xD5 */ CHAN_C | NONEOS_C,
949/* 0xD6 */ CHAN_C | NONEOS_C,
950/* 0xD7 */ CHAN_C | NONEOS_C,
951/* 0xD8 */ CHAN_C | NONEOS_C,
952/* 0xD9 */ CHAN_C | NONEOS_C,
953/* 0xDA */ CHAN_C | NONEOS_C,
954/* 0xDB */ CHAN_C | NONEOS_C,
955/* 0xDC */ CHAN_C | NONEOS_C,
956/* 0xDD */ CHAN_C | NONEOS_C,
957/* 0xDE */ CHAN_C | NONEOS_C,
958/* 0xDF */ CHAN_C | NONEOS_C,
959/* 0xE0 */ CHAN_C | NONEOS_C,
960/* 0xE1 */ CHAN_C | NONEOS_C,
961/* 0xE2 */ CHAN_C | NONEOS_C,
962/* 0xE3 */ CHAN_C | NONEOS_C,
963/* 0xE4 */ CHAN_C | NONEOS_C,
964/* 0xE5 */ CHAN_C | NONEOS_C,
965/* 0xE6 */ CHAN_C | NONEOS_C,
966/* 0xE7 */ CHAN_C | NONEOS_C,
967/* 0xE8 */ CHAN_C | NONEOS_C,
968/* 0xE9 */ CHAN_C | NONEOS_C,
969/* 0xEA */ CHAN_C | NONEOS_C,
970/* 0xEB */ CHAN_C | NONEOS_C,
971/* 0xEC */ CHAN_C | NONEOS_C,
972/* 0xED */ CHAN_C | NONEOS_C,
973/* 0xEE */ CHAN_C | NONEOS_C,
974/* 0xEF */ CHAN_C | NONEOS_C,
975/* 0xF0 */ CHAN_C | NONEOS_C,
976/* 0xF1 */ CHAN_C | NONEOS_C,
977/* 0xF2 */ CHAN_C | NONEOS_C,
978/* 0xF3 */ CHAN_C | NONEOS_C,
979/* 0xF4 */ CHAN_C | NONEOS_C,
980/* 0xF5 */ CHAN_C | NONEOS_C,
981/* 0xF6 */ CHAN_C | NONEOS_C,
982/* 0xF7 */ CHAN_C | NONEOS_C,
983/* 0xF8 */ CHAN_C | NONEOS_C,
984/* 0xF9 */ CHAN_C | NONEOS_C,
985/* 0xFA */ CHAN_C | NONEOS_C,
986/* 0xFB */ CHAN_C | NONEOS_C,
987/* 0xFC */ CHAN_C | NONEOS_C,
988/* 0xFD */ CHAN_C | NONEOS_C,
989/* 0xFE */ CHAN_C | NONEOS_C,
990/* 0xFF */ CHAN_C | NONEOS_C
991};