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