Annotation of coherent/b/kernel/FWB/words.c, revision 1.1.1.1

1.1       root        1: /*-----------------------------------------------------------------------------
                      2:        Talking BIOS device driver for the AT&T PC6300.
                      3:        Copyright (C) Karl Dahlke 1987
                      4:        This software may be freely used and distributed
                      5:        for any non-profit purpose.
                      6:  *-----------------------------------------------------------------------------
                      7:  */
                      8: 
                      9: /* words.c: look up words in replacement table */
                     10: 
                     11: #include "speech.h"
                     12: 
                     13: #define isvowel(c) vowels[(c) - 'a']
                     14: 
                     15: /* several English suffixes are recognized.
                     16:  * If present, the suffix may be removed, revealing the root word.
                     17:  * We then look up the root word in the replacement table,
                     18:  * and reapply the suffix.
                     19:  * Thus you only need correct the pronunciation of the singular or present
                     20:  * tense form of the word, and all regular conjugates are also corrected.
                     21:  * The first array defines 10 suffixes.
                     22:  * Additional arrays determine whether the final e or y is dropped,
                     23:  * whether the final consonent is doubled, the length of the suffix, etc. */
                     24: static char sufshorten[] = {0,1,2,2,3,4,2,1,3,2,2};
                     25: static char suftab[] = "s   es  ies ing ing ing d   ed  ed  ied ";
                     26: static char sufdrop[] = "  y  e   y";
                     27: static char sufadd[] = {1,2,3,3,4,3,1,3,2,3};
                     28: static char sufdouble[] = {0,0,0,0,1,0,0,1,0,0};
                     29: 
                     30: static char vowels[26] = {1,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0};
                     31: static short wdlen; /* length of word being spoken */
                     32: 
                     33: /* word replacement table */
                     34: static char *wdreptbl;
                     35: short sdwdrepreq = 5000; /* patchable */
                     36: static short wdreplen, wdrepmax;
                     37: 
                     38: /* macro definition table */
                     39: static char *mactbl;
                     40: short sdmacreq = 5000; /* patchable */
                     41: static short maclen, macmax;
                     42: 
                     43: 
                     44: /* allocate word replacement table and macro definition table */
                     45: sdtblload()
                     46: {
                     47: static char defreptbl[8];
                     48: static char defmactbl[8];
                     49: 
                     50: if(wdreptbl = kalloc(sdwdrepreq)) {
                     51: wdrepmax = sdwdrepreq; /* able to allocate requested amount */
                     52: } else {
                     53: wdreptbl = defreptbl;
                     54: wdrepmax = 8;
                     55: }
                     56: wdreplen = 0;
                     57: *wdreptbl = 0;
                     58: 
                     59: if(mactbl = kalloc(sdmacreq)) {
                     60: macmax = sdmacreq; /* able to allocate requested amount */
                     61: } else {
                     62: mactbl = defmactbl;
                     63: macmax = 8;
                     64: }
                     65: maclen = 0;
                     66: *mactbl = 0;
                     67: } /* sdtblload */
                     68: 
                     69: /* speak the current word in the active control structure */
                     70: sdtextw()
                     71: {
                     72: if(sdc->rdflag && !sdc->onesymb)
                     73: drainset(sdc);
                     74: sdtext(sdw);
                     75: } /* sdtextw */
                     76: 
                     77: /* speak current character */
                     78: curchar(sayit, asword)
                     79: {
                     80: register char c;
                     81: register i;
                     82: char *t;
                     83: static char ctrlstr[] = "controal x";
                     84: /* phonetic alphabet, words for letters to avoid ambiguity.
                     85:  * important when you need to know exactly which letter  (e.g. m or n)
                     86:  * such as variables for equations or programs
                     87:  * words taken from the NATO standard, established in the 1960's
                     88:  * 10 bytes per entry.  */
                     89: static char wfl[] = "\
                     90: al fa~~~~~brohvo~~~~charlie~~~\
                     91: delta~~~~~eko~~~~~~~foxtrot~~~\
                     92: gawlf~~~~~hoatel~~~~india~~~~~\
                     93: juleyet~~~killo~~~~~liema~~~~~\
                     94: mike~~~~~~noavember~oscar~~~~~\
                     95: popa~~~~~~kebeck~~~~roamio~~~~\
                     96: seeara~~~~tango~~~~~uniform~~~\
                     97: victor~~~~wiskey~~~~x ray~~~~~\
                     98: yangkey~~~zoolu~~~~~\
                     99: ";
                    100: 
                    101: sdw[0] = 0;
                    102: cursor_set();
                    103: c = getc();
                    104: 
                    105: if(c == '\07') {
                    106: if(!sdsession && sdnoises) { sdsound(3); return; }
                    107: t = "bell";
                    108: goto copywd;
                    109: }
                    110: if(c == '\r') {
                    111: if(!sdsession && sdnoises) { sdcrsnd(); return; }
                    112: if(sdc->rdflag) return;
                    113: t = "line";
                    114: goto copywd;
                    115: }
                    116: if(c == '\12') {
                    117: t = "feed";
                    118: goto copywd;
                    119: }
                    120: 
                    121: if(c && c < 27) {
                    122: ctrlstr[9] = c|0x40;
                    123: t = ctrlstr;
                    124: 
                    125: copywd:
                    126: i = strlen(t);
                    127: memcpy(sdw, t, ++i);
                    128: if(sayit) sdtextw();
                    129: return;
                    130: }
                    131: 
                    132: i = c;
                    133: if(c) i -= 26;
                    134: if(c >= '0') {
                    135: if(c <= '9') goto onelet;
                    136: i -= 10;
                    137: }
                    138: if(c >= 'A') {
                    139: if(c <= 'Z') goto onelet;
                    140: i -= 26;
                    141: }
                    142: if(c >= 'a') {
                    143: if(c <= 'z') goto onelet;
                    144: i -= 26;
                    145: }
                    146: 
                    147: t = sdc->punctab + 10*i;
                    148: goto copywd10;
                    149: 
                    150: onelet:
                    151: sdw[0] = c | 0x20;
                    152: sdw[1] = 0;
                    153: if(asword && c > '9') {
                    154: t = wfl + 10*(sdw[0] - 'a');
                    155: copywd10:
                    156: for(i=0; i<10; ++i)
                    157: if((sdw[i] = t[i]) == '~') break;
                    158: sdw[i] = 0;
                    159: }
                    160: if(sayit) sdtextw();
                    161: } /* curchar */
                    162: 
                    163: /* read text until EOF or newline or end of symbol */
                    164: reading()
                    165: {
                    166: short i;
                    167: char c, past_eof, waspunct;
                    168: 
                    169: cursor_copy();
                    170: past_eof = waspunct = 0;
                    171: 
                    172: /* skip whitespace */
                    173: while(getc() == ' ')
                    174: if(incptr()) { stopread(); return; }
                    175: 
                    176: c = getc();
                    177: if(isdigit(c)) {
                    178: for(i=0; i<WORDLEN; ++i) {
                    179: sdw[i] = c;
                    180: if(incptr()) { past_eof = 1; break; }
                    181: c = getc();
                    182: if(!isdigit(c)) break;
                    183: }
                    184: if(i < WORDLEN) ++i;
                    185: sdw[i] = 0;
                    186: goto spkbuf;
                    187: } /* end number */
                    188: 
                    189: c |= 0x20;
                    190: if(isalnum(c)) {
                    191: for(i=0; i<WORDLEN; ++i) {
                    192: sdw[i] = c;
                    193: if(incptr()) { past_eof = 1; break; }
                    194: c = getc() | 0x20;
                    195: if(!islower(c)) break;
                    196: }
                    197: if(i < WORDLEN) ++i;
                    198: sdw[i] = 0;
                    199: 
                    200: wdlen = i;
                    201: wdexpand();
                    202: 
                    203: spkbuf:
                    204: sdtextw();
                    205: endword:
                    206: if(past_eof ||
                    207: sdc->onesymb && (waspunct || !isalnum(getc())) ||
                    208: sdc->oneline && waspunct == 2) {
                    209: stopread();
                    210: decptr();
                    211: }
                    212: cursor_set();
                    213: return;
                    214: } /* end word */
                    215: 
                    216: /* it's a symbol */
                    217: waspunct = 1;
                    218: curchar(0, 0);
                    219: if(getc() == '\r') waspunct = 2;
                    220: 
                    221: if(sdw[0]) { /* string to be spoken */
                    222: /* check for an entire line of the symbol */
                    223: c = getc();
                    224: i = 1;
                    225: while(!(past_eof = incptr()) && getc() == c) ++i;
                    226: if(i > 4) { /* too  many, just give count */
                    227: static char repeat[] = "length xxxxx";
                    228: int n = i;
                    229: for(i=4; i>=0; --i) { repeat[i+7] = n%10 + '0'; n /= 10; }
                    230: for(i=0; i<4; ++i) if(repeat[i+7] != '0') break;
                    231: memcpy(repeat+7, repeat+7+i, 5);
                    232: 
                    233: /* curchar() was called in setup mode, 
                    234:  * just tack this repeat modifyier on the end of sdw[] */
                    235: n = strlen(sdw);
                    236: sdw[n++] = ' ';
                    237: memcpy(sdw+n, repeat, 14);
                    238: goto spkbuf;
                    239: }
                    240: 
                    241: cursor_copy();
                    242: sdtextw();
                    243: }
                    244: 
                    245: past_eof = incptr();
                    246: goto endword;
                    247: } /* reading */
                    248: 
                    249: /* find word in lookup table, or check for acronym */
                    250: static wdexpand()
                    251: {
                    252: short foundit;
                    253: short root;
                    254: 
                    255: if(lookup()) return; /* word replaced */
                    256: 
                    257: if(root = mkroot()) {
                    258: wdlen -= sufshorten[root];
                    259: foundit = lookup();
                    260: reconst(root);
                    261: if(foundit) return;
                    262: }
                    263: 
                    264: acron();
                    265: } /* wdexpand */
                    266: 
                    267: /* extract the root word */
                    268: static mkroot()
                    269: {
                    270: char l0, l1, l2, l3, l4; /* letters */
                    271: short l;
                    272: 
                    273: l = wdlen - 5;
                    274: if(l < 0) return 0; /* word too short to safely "rootinize" */
                    275: l4 = sdw[l+4];
                    276: l3 = sdw[l+3];
                    277: l2 = sdw[l+2];
                    278: l1 = sdw[l+1];
                    279: l0 = sdw[l+0];
                    280: if(l4 == 's') { /* possible plural */
                    281: if(l3 == 's' || l3 == 'i' || l3 == 'a' || l3 == 'u') return 0;
                    282: if(l3 == 'e') {
                    283: if(l2 == 'i') {
                    284: sdw[l+2] = 'y';
                    285: sdw[l+3] = 0;
                    286: return 3;
                    287: }
                    288: if(l2 == 's' || l2 == 'h' || l2 == 'z') {
                    289: sdw[l+3] = 0;
                    290: return 2;
                    291: }
                    292: }
                    293: /* normal plural */
                    294: sdw[l+4] = 0;
                    295: return 1;
                    296: } /* end final s */
                    297: 
                    298: if(l == 0) return 0; /* too short */
                    299: 
                    300: if(l4 == 'g') { /* possible present progressive */
                    301: if(l3 != 'n' || l2 != 'i') return 0;
                    302: if(!isvowel(l1)) {
                    303: if(l1 == l0) { sdw[l+1] = 0; return 5; }
                    304: if(isvowel(l0) &&  l0 < 'w' && !isvowel(sdw[l-1])) {
                    305: sdw[l+2] = 'e';
                    306: sdw[l+3] = 0;
                    307: return 6;
                    308: }
                    309: }
                    310: sdw[l+2] = 0;
                    311: return 4;
                    312: } /* end ing */
                    313: 
                    314: if(l4 == 'd') { /* possible past tense */
                    315: if(l3 != 'e') return 0;
                    316: if(l2 == 'i') {
                    317: sdw[l+2] = 'y';
                    318: sdw[l+3] = 0;
                    319: return 10;
                    320: }
                    321: if(!isvowel(l2)) {
                    322: if(l2 == l1) { sdw[l+2] = 0; return 8; }
                    323: if(isvowel(l1) && l1 < 'w' && !isvowel(l0)) {
                    324: sdw[l+4] = 0;
                    325: return 7;
                    326: }
                    327: }
                    328: sdw[l+3] = 0;
                    329: return 9;
                    330: } /* end final ed */
                    331: 
                    332: return 0;
                    333: } /* mkroot */
                    334: 
                    335: /* reconstruct word based on root and removed suffixes */
                    336: static reconst(root)
                    337: {
                    338: register char *t;
                    339: register i;
                    340: char c;
                    341: 
                    342: if(root--) {
                    343: t = sdw + wdlen-1;
                    344: wdlen += sufadd[root];
                    345: if(sufdouble[root]) c = *t, *++t = c;
                    346: if(sufdrop[root] == *t) --t, --wdlen;
                    347: for(i=4*root; i<4*root+4; ++i)
                    348: *++t = suftab[i];
                    349: sdw[wdlen] = 0;
                    350: } /* a real root */
                    351: } /* reconst */
                    352: 
                    353: static char *sublookup(w, length)
                    354: char *w;
                    355: short length;
                    356: {
                    357: register char *t;
                    358: register short n;
                    359: short i;
                    360: 
                    361: /* loop over words in the table */
                    362: for(t = wdreptbl; n = *t; t += n+2 + t[n+1]) {
                    363: /* check length and first letter */
                    364: if(n != length) continue;
                    365: if(t[1] != *w) continue;
                    366: /* run strncmp */
                    367: for(i=1; i<n; ++i)
                    368: if(t[i+1] != sdw[i]) break;
                    369: if(i < n) continue;
                    370: return t; /* match */
                    371: }
                    372: return 0; /* no match */
                    373: } /* sublookup */
                    374: 
                    375: /* lookup in macro table, similar to sublookup */
                    376: char *submlookup(mset, key)
                    377: char mset, key; /* active macro set and key */
                    378: {
                    379: register char *t;
                    380: register short n;
                    381: 
                    382: /* loop over defined macros */
                    383: for(t=mactbl; n = *t; t += n) {
                    384: if(t[1] != mset) continue;
                    385: if(t[2] != key) continue;
                    386: return t;
                    387: } /* end loop */
                    388: 
                    389: return 0; /* macro not defined */
                    390: } /* submlookup */
                    391: 
                    392: /* look up word in pronounciation table */
                    393: static lookup()
                    394: {
                    395: char *t;
                    396: 
                    397: if(!(t = sublookup(sdw, wdlen))) return 0;
                    398: 
                    399: t += wdlen+1;
                    400: wdlen = *t++;
                    401: memcpy(sdw, t, wdlen);
                    402: sdw[wdlen] = 0;
                    403: return 1;
                    404: } /* lookup */
                    405: 
                    406: /* if it is an acronym, insert blanks to pronounce letters */
                    407: static acron()
                    408: {
                    409: register i, j;
                    410: /* legal english three letter initial consonent clusters */
                    411: static char iclu[] = "chrchlphrphlsclschscrshlshrshwsphsplsprstrthrthw~";
                    412: 
                    413: /* any vowels in the first four letters? */
                    414: for(j=0,i=0; i<4; ++i) {
                    415: if(sdw[i] == 0) break;
                    416: j += isvowel(sdw[i]);
                    417: }
                    418: if(j == 0 || j ==  4 || j == wdlen)
                    419: goto insert;
                    420: 
                    421: if(j != 1 || wdlen < 4 || !isvowel(sdw[3])) return;
                    422: 
                    423: for(i=0; iclu[i] != '~'; i+=3) {
                    424: if(iclu[i] != sdw[0]) continue;
                    425: if(iclu[i+1] != sdw[1]) continue;
                    426: if(iclu[i+2] != sdw[2]) continue;
                    427: return;
                    428: }
                    429: 
                    430: insert:
                    431: /* doesn't look very english, insert blanks */
                    432: i = wdlen-1;
                    433: wdlen = j = i + i + 1;
                    434: while(i >= 0) {
                    435: sdw[j--] = ' ';
                    436: sdw[j--] = sdw[i--];
                    437: }
                    438: sdw[wdlen] = 0;
                    439: } /* acron */
                    440: 
                    441: stopread()
                    442: {
                    443: sdc->rdflag = sdc->onesymb = 0;
                    444: } /* stopread */
                    445: 
                    446: /* add a word to the pronunciation table */
                    447: addword(s)
                    448: char *s;
                    449: {
                    450: char c;
                    451: char *t;
                    452: short i;
                    453: 
                    454: i = stringcheck(s, 0);
                    455: c = s[0];
                    456: if(isdigit(c) || i == 3) return 3;
                    457: if(!c) return 0; /* blank line */
                    458: 
                    459: if(islower(c)) {
                    460: /* word replacement */
                    461: 
                    462: /* first remove the old definition */
                    463: for(i=0; s[i] && s[i] != ' '; ++i)  ;
                    464: c = i;
                    465: if(t = sublookup(s, c)) {
                    466: i = c + t[c+1] + 2;
                    467: wdreplen -= i;
                    468: memcpy(t, t+i, wdreplen - (t-wdreptbl) + 1);
                    469: }
                    470: 
                    471: if(s[c]) {
                    472: i = strlen(s);
                    473: if(wdreplen + i >= wdrepmax-1)
                    474: return 4; /* not enough room */
                    475: t = wdreptbl + wdreplen;
                    476: memcpy(t+1, s, i);
                    477: t[++i] = 0;
                    478: wdreplen += i;
                    479: *t = c;
                    480: t[c+1] = i-c-2;
                    481: }
                    482: return 0;
                    483: } /* end word replacement */
                    484: 
                    485: /* punctuation replacement */
                    486: if(c > 'a') c -= 26;
                    487: if(c > 'A') c -= 26;
                    488: if(c > '0') c -= 10;
                    489: c -= ' ';
                    490: c += 6;
                    491: 
                    492: for(++s; *s; ++s)
                    493: if(*s != ' ') break;
                    494: if(!*s) return 3;
                    495: 
                    496: t = sdc->punctab + 10*c;
                    497: for(i=0; i<10; ++i) {
                    498: if(!s[i]) break;
                    499: t[i] = s[i];
                    500: }
                    501: if(s[i]) return 4;
                    502: 
                    503: while(i < 10)
                    504: t[i++] = '~';
                    505: 
                    506: return 0;
                    507: } /* addword */
                    508: 
                    509: static stringcheck(s, macro)
                    510: char *s;
                    511: {
                    512: short i, j;
                    513: char c, wasblank, macless;
                    514: 
                    515: wasblank = 1;
                    516: macless = 0;
                    517: for(i=j=0; c = s[i]; ++i) {
                    518: if(!macless) {
                    519: if(isupper(c)) c |= 0x20;
                    520: if(c == '\t') c = ' ';
                    521: }
                    522: s[j++] = c;
                    523: if(macless) continue;
                    524: if(macro && c == '<') { macless = 1; continue; }
                    525: if(c == ' ') {
                    526: if(wasblank) --j;
                    527: wasblank = 1;
                    528: continue;
                    529: }
                    530: wasblank = 0;
                    531: if(c & 0x80 || c < ' ') return 3;
                    532: if(c == '.' && j == 2 && s[0] == '#') continue; /* ok */
                    533: if(j != 1 && !isalnum(c)) return 3;
                    534: }
                    535: if(wasblank && j && !macro) --j;
                    536: s[j] = 0;
                    537: 
                    538: return (macro && !macless) ? 3 : 0;
                    539: } /* stringcheck */
                    540: 
                    541: keybind(s, macro)
                    542: char *s;
                    543: {
                    544: char c;
                    545: char *t;
                    546: struct SDCMD *cmdp;
                    547: char altkey, ctrlkey, shiftkey;
                    548: short i, keynum;
                    549: static alpha_alt[] = {
                    550: 0,30,48,46,32,18,33,34,35,23,36,37,38,50,49,24,25,16,19,31,20,22,47,17,45,21,44};
                    551: static char pad_cmd[] = {
                    552: 83,0,82,79,80,81,75,0,77,71,72,73};
                    553: 
                    554: i = stringcheck(s, macro);
                    555: if(i == 3) return 3;
                    556: c = *s++;
                    557: if(!c) return 0; /* blank line */
                    558: 
                    559: keynum = 0;
                    560: altkey = 0;
                    561: ctrlkey = 0;
                    562: shiftkey = 0;
                    563: 
                    564: switch(c) {
                    565: case '@': /* alt key */
                    566: altkey = 1;
                    567: if(*s == 'f' && isdigit(s[1])) { ++s; goto fnkey; }
                    568: goto letter;
                    569: 
                    570: case '+':
                    571: shiftkey = 1;
                    572: if(*s++ != 'f') return 3;
                    573: /* fall through to function key */
                    574: 
                    575: case 'f': /* function key */
                    576: fnkey:
                    577: c = *s;
                    578: while(isdigit(c)) {
                    579: keynum = 10*keynum + c -'0';
                    580: c = *++s;
                    581: }
                    582: if(keynum <= 0 || keynum > 10) return 3;
                    583: keynum += 0x3a;
                    584: if(shiftkey) keynum += 0x19;
                    585: if(ctrlkey) keynum += 0x23;
                    586: if(altkey) keynum += 0x2d;
                    587: break;
                    588: 
                    589: case '#': /* number pad */
                    590: c = *s++;
                    591: if(c < '.' || c > '9') return 3;
                    592: keynum = pad_cmd[c-'.'];
                    593: if(!keynum) return 3;
                    594: break;
                    595: 
                    596: case '^': /* control key */
                    597: ctrlkey = 1;
                    598: if(*s == 'f' && isdigit(s[1])) { ++s; goto fnkey; }
                    599: letter:
                    600: c = *s++;
                    601: if(!islower(c)) return 3;
                    602: c -= '`';
                    603: if(altkey)
                    604: keynum = alpha_alt[c];
                    605: else keynum = c + 119;
                    606: break;
                    607: 
                    608: default: return 3;
                    609: } /* end switch on first char */
                    610: 
                    611: if(*s == ' ') ++s;
                    612: 
                    613: if(*s == '<') { /* macro */
                    614: ++s;
                    615: c = 10*sdsession + sdc->macsel;
                    616: if(t = submlookup(c, keynum)) {
                    617: /* drop old definition */
                    618: i = *t;
                    619: maclen -= i;
                    620: memcpy(t, t+i, maclen - (t-mactbl) + 1);
                    621: }
                    622: 
                    623: if(*s) { /* add new definition */
                    624: i = strlen(s);
                    625: if(maclen+i+4 >= macmax) return 4;
                    626: t = mactbl + maclen;
                    627: memcpy(t+3, s, i+1);
                    628: t[1] = c;
                    629: t[2] = keynum;
                    630: i += 3;
                    631: *t = i;
                    632: maclen += i;
                    633: }
                    634: return 0;
                    635: } /* end macro */
                    636: 
                    637: if(!*s) { /* unbind key */
                    638: sdc->keymap[keynum] = 0;
                    639: return 0;
                    640: }
                    641: 
                    642: /* look for this command designator */
                    643: cmdp = &sdcmds[1];
                    644: while(*(t = cmdp->brief)) {
                    645: for(i=0; s[i]; ++i)
                    646: if(s[i] != t[i]) break;
                    647: if(!(s[i] | t[i])) {
                    648: sdc->keymap[keynum] = cmdp - sdcmds;
                    649: return 0; /* key binding successful */
                    650: }
                    651: ++cmdp;
                    652: } /* end loop through speech functions */
                    653: 
                    654: return 3; /* no such function */
                    655: } /* keybind */
                    656: 
                    657: /* expand macro or simply place the key on the input queue */
                    658: mexpand(session, key, xcmd)
                    659: short key, xcmd;
                    660: {
                    661: struct SDCONTROL *o = sdcontrol[session];
                    662: char *t;
                    663: short n;
                    664: 
                    665: if(xcmd) {
                    666: n = 10*session + o->macsel;
                    667: if(t = submlookup(n, xcmd)) {
                    668: n = *t;
                    669: n -= 3, t += 3;
                    670: while(n--) {
                    671: /* warning!! MSDOS input expects shorts, not chars.
                    672:  * The high byte is suppose to contain status bits, indicating
                    673:  * shift/control/whatever.  I hope command.com, or whatever program
                    674:  * is reading this input, does not really need these bits when
                    675:  * the characters are simple ASCII. */
                    676: #ifdef MSDOS
                    677: if((*o->dev_in)(*t++)) {
                    678: if(!session) sdsound(3);
                    679: return;
                    680: }
                    681: #else
                    682: (*o->dev_in)(*t++);
                    683: #endif
                    684: } /* end pushing macro onto input queue */
                    685: return;
                    686: } /* is macro defined */
                    687: }
                    688: 
                    689: #ifdef MSDOS
                    690: if((*o->dev_in)(key)) {
                    691: if(!session) sdsound(3);
                    692: }
                    693: #else
                    694: (*o->dev_in)(key);
                    695: #endif
                    696: } /* mexpand */
                    697: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.