|
|
1.1 ! root 1: /* getstr.cpp */ ! 2: ! 3: /* Synchronet string input routines */ ! 4: ! 5: /* $Id: getstr.cpp,v 1.22 2006/08/23 01:45:05 rswindell Exp $ */ ! 6: ! 7: /**************************************************************************** ! 8: * @format.tab-size 4 (Plain Text/Source Code File Header) * ! 9: * @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) * ! 10: * * ! 11: * Copyright 2006 Rob Swindell - http://www.synchro.net/copyright.html * ! 12: * * ! 13: * This program is free software; you can redistribute it and/or * ! 14: * modify it under the terms of the GNU General Public License * ! 15: * as published by the Free Software Foundation; either version 2 * ! 16: * of the License, or (at your option) any later version. * ! 17: * See the GNU General Public License for more details: gpl.txt or * ! 18: * http://www.fsf.org/copyleft/gpl.html * ! 19: * * ! 20: * Anonymous FTP access to the most recent released source is available at * ! 21: * ftp://vert.synchro.net, ftp://cvs.synchro.net and ftp://ftp.synchro.net * ! 22: * * ! 23: * Anonymous CVS access to the development source and modification history * ! 24: * is available at cvs.synchro.net:/cvsroot/sbbs, example: * ! 25: * cvs -d :pserver:[email protected]:/cvsroot/sbbs login * ! 26: * (just hit return, no password is necessary) * ! 27: * cvs -d :pserver:[email protected]:/cvsroot/sbbs checkout src * ! 28: * * ! 29: * For Synchronet coding style and modification guidelines, see * ! 30: * http://www.synchro.net/source.html * ! 31: * * ! 32: * You are encouraged to submit any modifications (preferably in Unix diff * ! 33: * format) via e-mail to [email protected] * ! 34: * * ! 35: * Note: If this box doesn't appear square, then you need to fix your tabs. * ! 36: ****************************************************************************/ ! 37: ! 38: #include "sbbs.h" ! 39: ! 40: /****************************************************************************/ ! 41: /* Waits for remote or local user to input a CR terminated string. 'length' */ ! 42: /* is the maximum number of characters that getstr will allow the user to */ ! 43: /* input into the string. 'mode' specifies upper case characters are echoed */ ! 44: /* or wordwrap or if in message input (^A sequences allowed). ^W backspaces */ ! 45: /* a word, ^X backspaces a line, ^Gs, BSs, TABs are processed, LFs ignored. */ ! 46: /* ^N non-destructive BS, ^V center line. Valid keys are echoed. */ ! 47: /****************************************************************************/ ! 48: size_t sbbs_t::getstr(char *strout, size_t maxlen, long mode) ! 49: { ! 50: size_t i,l,x,z; /* i=current position, l=length, j=printed chars */ ! 51: /* x&z=misc */ ! 52: char str1[256],str2[256],undo[256]; ! 53: uchar ch; ! 54: uchar atr; ! 55: ! 56: console&=~(CON_UPARROW|CON_DOWNARROW|CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE); ! 57: if(!(mode&K_WRAP)) ! 58: console&=~CON_INSERT; ! 59: sys_status&=~SS_ABORT; ! 60: if(mode&K_LINE && term_supports(ANSI) && !(mode&K_NOECHO)) { ! 61: attr(cfg.color[clr_inputline]); ! 62: for(i=0;i<maxlen;i++) ! 63: outchar(' '); ! 64: cursor_left(maxlen); ! 65: } ! 66: if(wordwrap[0]) { ! 67: strcpy(str1,wordwrap); ! 68: wordwrap[0]=0; ! 69: } ! 70: else str1[0]=0; ! 71: if(mode&K_EDIT) ! 72: strcat(str1,strout); ! 73: else ! 74: strout[0]=0; ! 75: if(strlen(str1)>maxlen) ! 76: str1[maxlen]=0; ! 77: atr=curatr; ! 78: if(!(mode&K_NOECHO)) { ! 79: if(mode&K_AUTODEL && str1[0]) { ! 80: i=(cfg.color[clr_inputline]&0x77)<<4; ! 81: i|=(cfg.color[clr_inputline]&0x77)>>4; ! 82: attr(i); ! 83: } ! 84: rputs(str1); ! 85: if(mode&K_EDIT && !(mode&(K_LINE|K_AUTODEL)) && term_supports(ANSI)) ! 86: cleartoeol(); /* destroy to eol */ ! 87: } ! 88: ! 89: SAFECOPY(undo,str1); ! 90: i=l=strlen(str1); ! 91: if(mode&K_AUTODEL && str1[0] && !(mode&K_NOECHO)) { ! 92: ch=getkey(mode|K_GETSTR); ! 93: attr(atr); ! 94: if(isprint(ch) || ch==DEL) { ! 95: for(i=0;i<l;i++) ! 96: backspace(); ! 97: i=l=0; ! 98: } ! 99: else { ! 100: for(i=0;i<l;i++) ! 101: outchar(BS); ! 102: rputs(str1); ! 103: i=l; ! 104: } ! 105: if(ch!=' ' && ch!=TAB) ! 106: ungetkey(ch); ! 107: } ! 108: ! 109: if(mode&K_USEOFFSET) { ! 110: i=getstr_offset; ! 111: if(i>l) ! 112: i=l; ! 113: if(l-i) { ! 114: cursor_left(l-i); ! 115: } ! 116: } ! 117: ! 118: if(console&CON_INSERT && term_supports(ANSI) && !(mode&K_NOECHO)) ! 119: insert_indicator(); ! 120: ! 121: while(!(sys_status&SS_ABORT) && online && input_thread_running) { ! 122: if(mode&K_LEFTEXIT ! 123: && console&(CON_LEFTARROW|CON_BACKSPACE|CON_DELETELINE)) ! 124: break; ! 125: if(console&CON_UPARROW) ! 126: break; ! 127: if((ch=getkey(mode|K_GETSTR))==CR) ! 128: break; ! 129: if(sys_status&SS_ABORT || !online) ! 130: break; ! 131: if(ch==LF && mode&K_MSG) { /* Down-arrow same as CR */ ! 132: console|=CON_DOWNARROW; ! 133: break; ! 134: } ! 135: if(ch==TAB && (mode&K_TAB || !(mode&K_WRAP))) /* TAB same as CR */ ! 136: break; ! 137: if(!i && mode&K_UPRLWR && (ch==' ' || ch==TAB)) ! 138: continue; /* ignore beginning white space if upper/lower */ ! 139: if(mode&K_E71DETECT && (uchar)ch==(CR|0x80) && l>1) { ! 140: if(strstr(str1,"��")) { ! 141: bputs("\r\n\r\nYou must set your terminal to NO PARITY, " ! 142: "8 DATA BITS, and 1 STOP BIT (N-8-1).\7\r\n"); ! 143: return(0); ! 144: } ! 145: } ! 146: getstr_offset=i; ! 147: switch(ch) { ! 148: case CTRL_A: /* Ctrl-A for ANSI */ ! 149: if(!(mode&K_MSG) || useron.rest&FLAG('A') || i>maxlen-3) ! 150: break; ! 151: if(console&CON_INSERT) { ! 152: if(l<maxlen) ! 153: l++; ! 154: for(x=l;x>i;x--) ! 155: str1[x]=str1[x-1]; ! 156: rprintf("%.*s",l-i,str1+i); ! 157: cursor_left(l-i); ! 158: #if 0 ! 159: if(i==maxlen-1) ! 160: console&=~CON_INSERT; ! 161: #endif ! 162: } ! 163: outchar(str1[i++]=1); ! 164: break; ! 165: case CTRL_B: /* Ctrl-B Beginning of Line */ ! 166: if(term_supports(ANSI) && i && !(mode&K_NOECHO)) { ! 167: cursor_left(i); ! 168: i=0; ! 169: } ! 170: break; ! 171: case CTRL_D: /* Ctrl-D Delete word right */ ! 172: if(i<l) { ! 173: x=i; ! 174: while(x<l && str1[x]!=' ') { ! 175: outchar(' '); ! 176: x++; ! 177: } ! 178: while(x<l && str1[x]==' ') { ! 179: outchar(' '); ! 180: x++; ! 181: } ! 182: cursor_left(x-i); /* move cursor back */ ! 183: z=i; ! 184: while(z<l-(x-i)) { /* move chars in string */ ! 185: outchar(str1[z]=str1[z+(x-i)]); ! 186: z++; ! 187: } ! 188: while(z<l) { /* write over extra chars */ ! 189: outchar(' '); ! 190: z++; ! 191: } ! 192: cursor_left(z-i); ! 193: l-=x-i; /* l=new length */ ! 194: } ! 195: break; ! 196: case CTRL_E: /* Ctrl-E End of line */ ! 197: if(term_supports(ANSI) && i<l) { ! 198: cursor_right(l-i); /* move cursor to eol */ ! 199: i=l; ! 200: } ! 201: break; ! 202: case CTRL_F: /* Ctrl-F move cursor forewards */ ! 203: if(i<l && term_supports(ANSI)) { ! 204: cursor_right(); /* move cursor right one */ ! 205: i++; ! 206: } ! 207: break; ! 208: case CTRL_G: /* Bell */ ! 209: if(!(mode&K_MSG)) ! 210: break; ! 211: if(useron.rest&FLAG('B')) { ! 212: if (i+6<maxlen) { ! 213: if(console&CON_INSERT) { ! 214: for(x=l+6;x>i;x--) ! 215: str1[x]=str1[x-6]; ! 216: if(l+5<maxlen) ! 217: l+=6; ! 218: #if 0 ! 219: if(i==maxlen-1) ! 220: console&=~CON_INSERT; ! 221: #endif ! 222: } ! 223: str1[i++]='('; ! 224: str1[i++]='b'; ! 225: str1[i++]='e'; ! 226: str1[i++]='e'; ! 227: str1[i++]='p'; ! 228: str1[i++]=')'; ! 229: if(!(mode&K_NOECHO)) ! 230: bputs("(beep)"); ! 231: } ! 232: if(console&CON_INSERT) ! 233: redrwstr(str1,i,l,0); ! 234: break; ! 235: } ! 236: if(console&CON_INSERT) { ! 237: if(l<maxlen) ! 238: l++; ! 239: for(x=l;x>i;x--) ! 240: str1[x]=str1[x-1]; ! 241: #if 0 ! 242: if(i==maxlen-1) ! 243: console&=~CON_INSERT; ! 244: #endif ! 245: } ! 246: if(i<maxlen) { ! 247: str1[i++]=BEL; ! 248: if(!(mode&K_NOECHO)) ! 249: outchar(BEL); ! 250: } ! 251: break; ! 252: case CTRL_H: /* Ctrl-H/Backspace */ ! 253: if(i==0) { ! 254: console|=CON_BACKSPACE; ! 255: break; ! 256: } ! 257: i--; ! 258: l--; ! 259: if(i!=l) { /* Deleting char in middle of line */ ! 260: outchar(BS); ! 261: z=i; ! 262: while(z<l) { /* move the characters in the line */ ! 263: outchar(str1[z]=str1[z+1]); ! 264: z++; ! 265: } ! 266: outchar(' '); /* write over the last char */ ! 267: cursor_left((l-i)+1); ! 268: } ! 269: else if(!(mode&K_NOECHO)) ! 270: backspace(); ! 271: break; ! 272: case CTRL_I: /* Ctrl-I/TAB */ ! 273: if(!(i%EDIT_TABSIZE)) { ! 274: if(console&CON_INSERT) { ! 275: if(l<maxlen) ! 276: l++; ! 277: for(x=l;x>i;x--) ! 278: str1[x]=str1[x-1]; ! 279: #if 0 ! 280: if(i==maxlen-1) ! 281: console&=~CON_INSERT; ! 282: #endif ! 283: } ! 284: str1[i++]=' '; ! 285: if(!(mode&K_NOECHO)) ! 286: outchar(' '); ! 287: } ! 288: while(i<maxlen && i%EDIT_TABSIZE) { ! 289: if(console&CON_INSERT) { ! 290: if(l<maxlen) ! 291: l++; ! 292: for(x=l;x>i;x--) ! 293: str1[x]=str1[x-1]; ! 294: #if 0 ! 295: if(i==maxlen-1) ! 296: console&=~CON_INSERT; ! 297: #endif ! 298: } ! 299: str1[i++]=' '; ! 300: if(!(mode&K_NOECHO)) ! 301: outchar(' '); ! 302: } ! 303: if(console&CON_INSERT && !(mode&K_NOECHO)) ! 304: redrwstr(str1,i,l,0); ! 305: break; ! 306: ! 307: case CTRL_L: /* Ctrl-L Center line (used to be Ctrl-V) */ ! 308: str1[l]=0; ! 309: l=bstrlen(str1); ! 310: if(!l) break; ! 311: for(x=0;x<(maxlen-l)/2;x++) ! 312: str2[x]=' '; ! 313: str2[x]=0; ! 314: strcat(str2,str1); ! 315: strcpy(strout,str2); ! 316: l=strlen(strout); ! 317: if(mode&K_NOECHO) ! 318: return(l); ! 319: if(mode&K_MSG) ! 320: redrwstr(strout,i,l,K_MSG); ! 321: else { ! 322: while(i--) ! 323: bputs("\b"); ! 324: bputs(strout); ! 325: if(mode&K_LINE) ! 326: attr(LIGHTGRAY); ! 327: } ! 328: if(!(mode&K_NOCRLF)) ! 329: CRLF; ! 330: return(l); ! 331: ! 332: case CTRL_N: /* Ctrl-N Next word */ ! 333: if(i<l && term_supports(ANSI)) { ! 334: x=i; ! 335: while(str1[i]!=' ' && i<l) ! 336: i++; ! 337: while(str1[i]==' ' && i<l) ! 338: i++; ! 339: cursor_right(i-x); ! 340: } ! 341: break; ! 342: case CTRL_R: /* Ctrl-R Redraw Line */ ! 343: if(!(mode&K_NOECHO)) ! 344: redrwstr(str1,i,l,0); ! 345: break; ! 346: case CTRL_V: /* Ctrl-V Toggles Insert/Overwrite */ ! 347: if(!term_supports(ANSI) || mode&K_NOECHO) ! 348: break; ! 349: console^=CON_INSERT; ! 350: insert_indicator(); ! 351: break; ! 352: case CTRL_W: /* Ctrl-W Delete word left */ ! 353: if(i<l) { ! 354: x=i; /* x=original offset */ ! 355: while(i && str1[i-1]==' ') { ! 356: outchar(BS); ! 357: i--; ! 358: } ! 359: while(i && str1[i-1]!=' ') { ! 360: outchar(BS); ! 361: i--; ! 362: } ! 363: z=i; /* i=z=new offset */ ! 364: while(z<l-(x-i)) { /* move chars in string */ ! 365: outchar(str1[z]=str1[z+(x-i)]); ! 366: z++; ! 367: } ! 368: while(z<l) { /* write over extra chars */ ! 369: outchar(' '); ! 370: z++; ! 371: } ! 372: cursor_left(z-i); /* back to new x corridnant */ ! 373: l-=x-i; /* l=new length */ ! 374: } else { ! 375: while(i && str1[i-1]==' ') { ! 376: i--; ! 377: l--; ! 378: if(!(mode&K_NOECHO)) ! 379: backspace(); ! 380: } ! 381: while(i && str1[i-1]!=' ') { ! 382: i--; ! 383: l--; ! 384: if(!(mode&K_NOECHO)) ! 385: backspace(); ! 386: } ! 387: } ! 388: break; ! 389: case CTRL_Y: /* Ctrl-Y Delete to end of line */ ! 390: if(i!=l) { /* if not at EOL */ ! 391: if(term_supports(ANSI) && !(mode&K_NOECHO)) ! 392: cleartoeol(); ! 393: l=i; ! 394: break; ! 395: } ! 396: /* fall-through */ ! 397: case CTRL_X: /* Ctrl-X Delete entire line */ ! 398: if(mode&K_NOECHO) ! 399: l=0; ! 400: else { ! 401: if(term_supports(ANSI)) { ! 402: cursor_left(i); ! 403: cleartoeol(); ! 404: l=0; ! 405: } else { ! 406: while(i<l) { ! 407: outchar(' '); ! 408: i++; ! 409: } ! 410: while(l) { ! 411: l--; ! 412: backspace(); ! 413: } ! 414: } ! 415: } ! 416: i=0; ! 417: console|=CON_DELETELINE; ! 418: break; ! 419: case CTRL_Z: /* Undo */ ! 420: SAFECOPY(str1,undo); ! 421: i=l=strlen(str1); ! 422: rprintf("\r%s",str1); ! 423: if(term_supports(ANSI)) ! 424: cleartoeol(); /* destroy to eol */ ! 425: break; ! 426: case 28: /* Ctrl-\ Previous word */ ! 427: if(i && term_supports(ANSI) && !(mode&K_NOECHO)) { ! 428: x=i; ! 429: while(str1[i-1]==' ' && i) ! 430: i--; ! 431: while(str1[i-1]!=' ' && i) ! 432: i--; ! 433: cursor_left(x-i); ! 434: } ! 435: break; ! 436: case 29: /* Ctrl-]/Left Arrow Reverse Cursor Movement */ ! 437: if(i==0) { ! 438: if(mode&K_LEFTEXIT) ! 439: console|=CON_LEFTARROW; ! 440: break; ! 441: } ! 442: if(term_supports(ANSI) && !(mode&K_NOECHO)) { ! 443: cursor_left(); /* move cursor left one */ ! 444: i--; ! 445: } ! 446: break; ! 447: case 30: /* Ctrl-^/Up Arrow */ ! 448: if(!(mode&K_EDIT)) ! 449: break; ! 450: #if 1 ! 451: if(i>l) ! 452: l=i; ! 453: str1[l]=0; ! 454: strcpy(strout,str1); ! 455: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO)) ! 456: redrwstr(strout,i,l,K_MSG); ! 457: if(mode&K_LINE && !(mode&K_NOECHO)) ! 458: attr(LIGHTGRAY); ! 459: console|=CON_UPARROW; ! 460: return(l); ! 461: #else ! 462: console|=CON_UPARROW; ! 463: break; ! 464: #endif ! 465: case DEL: /* Ctrl-BkSpc (DEL) Delete current char */ ! 466: if(i==l) { /* Backspace if end of line */ ! 467: if(i) { ! 468: i--; ! 469: l--; ! 470: if(!(mode&K_NOECHO)) ! 471: backspace(); ! 472: } ! 473: break; ! 474: } ! 475: l--; ! 476: z=i; ! 477: while(z<l) { /* move the characters in the line */ ! 478: outchar(str1[z]=str1[z+1]); ! 479: z++; ! 480: } ! 481: outchar(' '); /* write over the last char */ ! 482: cursor_left((l-i)+1); ! 483: break; ! 484: default: ! 485: if(mode&K_WRAP && i==maxlen && ch>=' ' && !(console&CON_INSERT)) { ! 486: str1[i]=0; ! 487: if(ch==' ' && !(mode&K_CHAT)) { /* don't wrap a space */ ! 488: strcpy(strout,str1); /* as last char */ ! 489: if(strip_invalid_attr(strout) && !(mode&K_NOECHO)) ! 490: redrwstr(strout,i,l,K_MSG); ! 491: if(!(mode&(K_NOECHO|K_NOCRLF))) ! 492: CRLF; ! 493: return(i); ! 494: } ! 495: x=i-1; ! 496: z=1; ! 497: wordwrap[0]=ch; ! 498: while(str1[x]!=' ' && x) ! 499: wordwrap[z++]=str1[x--]; ! 500: if(x<(maxlen/2)) { ! 501: wordwrap[1]=0; /* only wrap one character */ ! 502: strcpy(strout,str1); ! 503: if(strip_invalid_attr(strout) && !(mode&K_NOECHO)) ! 504: redrwstr(strout,i,l,K_MSG); ! 505: if(!(mode&(K_NOECHO|K_NOCRLF))) ! 506: CRLF; ! 507: return(i); ! 508: } ! 509: wordwrap[z]=0; ! 510: if(!(mode&K_NOECHO)) ! 511: while(z--) { ! 512: backspace(); ! 513: i--; ! 514: } ! 515: strrev(wordwrap); ! 516: str1[x]=0; ! 517: strcpy(strout,str1); ! 518: if(strip_invalid_attr(strout) && !(mode&K_NOECHO)) ! 519: redrwstr(strout,i,x,mode); ! 520: if(!(mode&(K_NOECHO|K_NOCRLF))) ! 521: CRLF; ! 522: return(x); ! 523: } ! 524: if(i<maxlen && ch>=' ') { ! 525: if(mode&K_UPRLWR) ! 526: if(!i || (i && (str1[i-1]==' ' || str1[i-1]=='-' ! 527: || str1[i-1]=='.' || str1[i-1]=='_'))) ! 528: ch=toupper(ch); ! 529: else ! 530: ch=tolower(ch); ! 531: if(console&CON_INSERT && i!=l) { ! 532: if(l<maxlen) /* l<maxlen */ ! 533: l++; ! 534: for(x=l;x>i;x--) ! 535: str1[x]=str1[x-1]; ! 536: rprintf("%.*s",l-i,str1+i); ! 537: cursor_left(l-i); ! 538: #if 0 ! 539: if(i==maxlen-1) { ! 540: bputs(" \b\b"); ! 541: console&=~CON_INSERT; ! 542: } ! 543: #endif ! 544: } ! 545: str1[i++]=ch; ! 546: if(!(mode&K_NOECHO)) ! 547: outchar(ch); ! 548: } else ! 549: outchar(BEL); /* Added at Angus McLeod's request */ ! 550: } ! 551: if(i>l) ! 552: l=i; ! 553: if(mode&K_CHAT && !l) ! 554: return(0); ! 555: } ! 556: getstr_offset=i; ! 557: if(!online) ! 558: return(0); ! 559: if(i>l) ! 560: l=i; ! 561: str1[l]=0; ! 562: if(!(sys_status&SS_ABORT)) { ! 563: strcpy(strout,str1); ! 564: if((strip_invalid_attr(strout) || console&CON_INSERT) && !(mode&K_NOECHO)) ! 565: redrwstr(strout,i,l,K_MSG); ! 566: } ! 567: else ! 568: l=0; ! 569: if(mode&K_LINE && !(mode&K_NOECHO)) attr(LIGHTGRAY); ! 570: if(!(mode&(K_NOCRLF|K_NOECHO))) { ! 571: outchar(CR); ! 572: if(!(mode&K_MSG && sys_status&SS_ABORT)) ! 573: outchar(LF); ! 574: lncntr=0; ! 575: } ! 576: return(l); ! 577: } ! 578: ! 579: /****************************************************************************/ ! 580: /* Hot keyed number input routine. */ ! 581: /* Returns a valid number between 1 and max, 0 if no number entered, or -1 */ ! 582: /* if the user hit 'Q' or ctrl-c */ ! 583: /****************************************************************************/ ! 584: long sbbs_t::getnum(ulong max) ! 585: { ! 586: uchar ch,n=0; ! 587: long i=0; ! 588: ! 589: while(online) { ! 590: ch=getkey(K_UPPER); ! 591: if(ch>0x7f) ! 592: continue; ! 593: if(ch=='Q') { ! 594: outchar('Q'); ! 595: if(useron.misc&COLDKEYS) ! 596: ch=getkey(K_UPPER); ! 597: if(ch==BS || ch==DEL) { ! 598: backspace(); ! 599: continue; ! 600: } ! 601: CRLF; ! 602: lncntr=0; ! 603: return(-1); ! 604: } ! 605: else if(sys_status&SS_ABORT) { ! 606: CRLF; ! 607: lncntr=0; ! 608: return(-1); ! 609: } ! 610: else if(ch==CR) { ! 611: CRLF; ! 612: lncntr=0; ! 613: return(i); ! 614: } ! 615: else if((ch==BS || ch==DEL) && n) { ! 616: backspace(); ! 617: i/=10; ! 618: n--; ! 619: } ! 620: else if(isdigit(ch) && (i*10UL)+(ch&0xf)<=max && (ch!='0' || n)) { ! 621: i*=10L; ! 622: n++; ! 623: i+=ch&0xf; ! 624: outchar(ch); ! 625: if(i*10UL>max && !(useron.misc&COLDKEYS)) { ! 626: CRLF; ! 627: lncntr=0; ! 628: return(i); ! 629: } ! 630: } ! 631: } ! 632: return(0); ! 633: } ! 634: ! 635: void sbbs_t::insert_indicator(void) ! 636: { ! 637: ANSI_SAVE(); ! 638: GOTOXY(cols,1); ! 639: uchar z=curatr; /* and go to EOL */ ! 640: if(console&CON_INSERT) { ! 641: attr(BLINK|BLACK|(LIGHTGRAY<<4)); ! 642: outchar('I'); ! 643: } else { ! 644: attr(LIGHTGRAY); ! 645: outchar(' '); ! 646: } ! 647: attr(z); ! 648: ANSI_RESTORE(); ! 649: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.