|
|
1.1 ! root 1: \ ***************************************************************************** ! 2: \ * Copyright (c) 2004, 2008 IBM Corporation ! 3: \ * All rights reserved. ! 4: \ * This program and the accompanying materials ! 5: \ * are made available under the terms of the BSD License ! 6: \ * which accompanies this distribution, and is available at ! 7: \ * http://www.opensource.org/licenses/bsd-license.php ! 8: \ * ! 9: \ * Contributors: ! 10: \ * IBM Corporation - initial implementation ! 11: \ ****************************************************************************/ ! 12: ! 13: \ Hash for faster lookup ! 14: #include <find-hash.fs> ! 15: ! 16: : >name ( xt -- nfa ) \ note: still has the "immediate" field! ! 17: BEGIN char- dup c@ UNTIL ( @lastchar ) ! 18: dup dup aligned - cell+ char- ( @lastchar lenmodcell ) ! 19: dup >r - ! 20: BEGIN dup c@ r@ <> WHILE ! 21: cell- r> cell+ >r ! 22: REPEAT ! 23: r> drop char- ! 24: ; ! 25: ! 26: \ Words missing in *.in files ! 27: VARIABLE mask -1 mask ! ! 28: ! 29: VARIABLE huge-tftp-load 1 huge-tftp-load ! ! 30: \ Default implementation for sms-get-tftp-blocksize that return 1432 (decimal) ! 31: : sms-get-tftp-blocksize 598 ; ! 32: ! 33: : default-hw-exception s" Exception #" type . ; ! 34: ! 35: ' default-hw-exception to hw-exception-handler ! 36: ! 37: : diagnostic-mode? false ; \ 2B DOTICK'D later in envvar.fs ! 38: ! 39: : memory-test-suite ( addr len -- fail? ) ! 40: diagnostic-mode? IF ! 41: ." Memory test mask value: " mask @ . cr ! 42: ." No memory test suite currently implemented! " cr ! 43: THEN ! 44: false ! 45: ; ! 46: ! 47: : 0.r 0 swap <# 0 ?DO # LOOP #> type ; ! 48: ! 49: \ count the number of bits equal 1 ! 50: \ the idea is to clear in each step the least significant bit ! 51: \ v&(v-1) does exactly this, so count the steps until v == 0 ! 52: : cnt-bits ( 64-bit-value -- #bits=1 ) ! 53: dup IF ! 54: 41 1 DO dup 1- and dup 0= IF drop i LEAVE THEN LOOP ! 55: THEN ! 56: ; ! 57: ! 58: : bcd-to-bin ( bcd -- bin ) ! 59: dup f and swap 4 rshift a * + ! 60: ; ! 61: ! 62: \ calcs the exponent of the highest power of 2 not greater than n ! 63: : 2log ( n -- lb{n} ) ! 64: 8 cells 0 DO 1 rshift dup 0= IF drop i LEAVE THEN LOOP ! 65: ; ! 66: ! 67: \ calcs the exponent of the lowest power of 2 not less than n ! 68: : log2 ( n -- log2-n ) ! 69: 1- 2log 1+ ! 70: ; ! 71: ! 72: \ Standard compliant $find ! 73: : $find ( str len -- xt true | str len false ) ! 74: 2dup $find ! 75: IF ! 76: drop nip nip TRUE ! 77: ELSE ! 78: FALSE ! 79: THEN ! 80: ; ! 81: ! 82: CREATE $catpad 100 allot ! 83: : $cat ( str1 len1 str2 len2 -- str3 len3 ) ! 84: >r >r dup >r $catpad swap move ! 85: r> dup $catpad + r> swap r@ move ! 86: r> + $catpad swap ; ! 87: ! 88: \ WARNING: The following two ($cat-comm & $cat-space) are dirty in a sense ! 89: \ that they add 1 or 2 characters to str1 before executing $cat ! 90: \ The ASSUMPTION is that str1 buffer provides that extra space and it is ! 91: \ responsibility of the code owner to ensure that ! 92: : $cat-comma ( str2 len2 str1 len1 -- "str1, str2" len1+len2+2 ) ! 93: 2dup + s" , " rot swap move 2+ 2swap $cat ! 94: ; ! 95: ! 96: : $cat-space ( str2 len2 str1 len1 -- "str1 str2" len1+len2+1 ) ! 97: 2dup + bl swap c! 1+ 2swap $cat ! 98: ; ! 99: : $cathex ( str len val -- str len' ) ! 100: (u.) $cat ! 101: ; ! 102: ! 103: ! 104: ! 105: : 2CONSTANT CREATE , , DOES> 2@ ; ! 106: : $2CONSTANT $CREATE , , DOES> 2@ ; ! 107: : 2VARIABLE CREATE 0 , 0 , DOES> ; ! 108: ! 109: : (is-user-word) ( name-str name-len xt -- ) -rot $CREATE , DOES> @ execute ; ! 110: ! 111: : zplace ( str len buf -- ) 2dup + 0 swap c! swap move ; ! 112: : rzplace ( str len buf -- ) 2dup + 0 swap rb! swap rmove ; ! 113: ! 114: : strdup ( str len -- dupstr len ) here over allot swap 2dup 2>r move 2r> ; ! 115: ! 116: : str= ( str1 len1 str2 len2 -- equal? ) ! 117: rot over <> IF 3drop false ELSE comp 0= THEN ; ! 118: ! 119: : #aligned ( adr alignment -- adr' ) negate swap negate and negate ; ! 120: : #join ( lo hi #bits -- x ) lshift or ; ! 121: : #split ( x #bits -- lo hi ) 2dup rshift dup >r swap lshift xor r> ; ! 122: ! 123: : /string ( str len u -- str' len' ) ! 124: >r swap r@ chars + swap r> - ; ! 125: : skip ( str len c -- str' len' ) ! 126: >r BEGIN dup WHILE over c@ r@ = WHILE 1 /string REPEAT THEN r> drop ; ! 127: : scan ( str len c -- str' len' ) ! 128: >r BEGIN dup WHILE over c@ r@ <> WHILE 1 /string REPEAT THEN r> drop ; ! 129: : split ( str len char -- left len right len ) ! 130: >r 2dup r> findchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; ! 131: \ reverse findchar -- search from the end of the string ! 132: : rfindchar ( str len char -- offs true | false ) ! 133: swap 1 - 0 swap do ! 134: over i + c@ ! 135: over dup bl = if <= else = then if ! 136: 2drop i dup dup leave ! 137: then ! 138: -1 +loop = ! 139: ; ! 140: \ reverse split -- split at the last occurence of char ! 141: : rsplit ( str len char -- left len right len ) ! 142: >r 2dup r> rfindchar IF >r over r@ 2swap r> 1+ /string ELSE 0 0 THEN ; ! 143: ! 144: : left-parse-string ( str len char -- R-str R-len L-str L-len ) ! 145: split 2swap ; ! 146: : replace-char ( str len chout chin -- ) ! 147: >r -rot BEGIN 2dup 4 pick findchar WHILE tuck - -rot + r@ over c! swap REPEAT ! 148: r> 2drop 2drop ! 149: ; ! 150: \ Duplicate string and replace \ with / ! 151: : \-to-/ ( str len -- str' len ) strdup 2dup [char] \ [char] / replace-char ; ! 152: ! 153: : // dup >r 1- + r> / ; \ division, round up ! 154: ! 155: : c@+ ( adr -- c adr' ) dup c@ swap char+ ; ! 156: : 2c@ ( adr -- c1 c2 ) c@+ c@ ; ! 157: : 4c@ ( adr -- c1 c2 c3 c4 ) c@+ c@+ c@+ c@ ; ! 158: : 8c@ ( adr -- c1 c2 c3 c4 c5 c6 c7 c8 ) c@+ c@+ c@+ c@+ c@+ c@+ c@+ c@ ; ! 159: ! 160: ! 161: : 4dup ( n1 n2 n3 n4 -- n1 n2 n3 n4 n1 n2 n3 n4 ) 2over 2over ; ! 162: : 4drop ( n1 n2 n3 n4 -- ) 2drop 2drop ; ! 163: ! 164: \ yes sometimes even something like this is needed ! 165: : 6dup ( 1 2 3 4 5 6 -- 1 2 3 4 5 6 1 2 3 4 5 6 ) ! 166: 5 pick 5 pick 5 pick 5 pick 5 pick 5 pick ! 167: ; ! 168: ! 169: \ convert a 32 bit signed into a 64 signed ! 170: \ ( propagate bit 31 to all bits 32:63 ) ! 171: : signed ( n1 -- n2 ) dup 80000000 and IF FFFFFFFF00000000 or THEN ; ! 172: ! 173: : <l@ ( addr -- x ) l@ signed ; ! 174: ! 175: : -leading BEGIN dup WHILE over c@ bl <= WHILE 1 /string REPEAT THEN ; ! 176: : (parse-line) skipws 0 parse ; ! 177: ! 178: ! 179: \ Append two character to hex byte, if possible ! 180: ! 181: : hex-byte ( char0 char1 -- value true|false ) ! 182: 10 digit IF ! 183: swap 10 digit IF ! 184: 4 lshift or true EXIT ! 185: ELSE ! 186: 2drop 0 ! 187: THEN ! 188: ELSE ! 189: drop ! 190: THEN ! 191: false EXIT ! 192: ; ! 193: ! 194: \ Parse hex string within brackets ! 195: ! 196: : parse-hexstring ( dst-adr -- dst-adr' ) ! 197: [char] ) parse cr ( dst-adr str len ) ! 198: bounds ?DO ( dst-adr ) ! 199: i c@ i 1+ c@ hex-byte IF ( dst-adr hex-byte ) ! 200: >r dup r> swap c! 1+ 2 ( dst-adr+1 2 ) ! 201: ELSE ! 202: drop 1 ( dst-adr 1 ) ! 203: THEN ! 204: +LOOP ! 205: ; ! 206: ! 207: \ Add special character to string ! 208: ! 209: : add-specialchar ( dst-adr special -- dst-adr' ) ! 210: over c! 1+ ( dst-adr' ) ! 211: 1 >in +! \ advance input-index ! 212: ; ! 213: ! 214: \ Parse upto next " ! 215: ! 216: : parse-" ( dst-adr -- dst-adr' ) ! 217: [char] " parse dup 3 pick + >r ( dst-adr str len R: dst-adr' ) ! 218: >r swap r> move r> ( dst-adr' ) ! 219: ; ! 220: ! 221: : (") ( dst-adr -- dst-adr' ) ! 222: begin ( dst-adr ) ! 223: parse-" ( dst-adr' ) ! 224: >in @ dup span @ >= IF ( dst-adr' >in-@ ) ! 225: drop ! 226: EXIT ! 227: THEN ! 228: ! 229: ib + c@ ! 230: CASE ! 231: [char] ( OF parse-hexstring ENDOF ! 232: [char] " OF [char] " add-specialchar ENDOF ! 233: dup OF EXIT ENDOF ! 234: ENDCASE ! 235: again ! 236: ; ! 237: ! 238: CREATE "pad 100 allot ! 239: ! 240: \ String with embedded hex strings ! 241: \ Example: " ba"( 12 34,4567)ab" -> >x62x61x12x34x45x67x61x62< ! 242: ! 243: : " ( [text<">< >] -- text-str text-len ) ! 244: state @ IF \ compile sliteral, pstr into dict ! 245: "pad dup (") over - ( str len ) ! 246: ['] sliteral compile, dup c, ( str len ) ! 247: bounds ?DO i c@ c, LOOP ! 248: align ['] count compile, ! 249: ELSE ! 250: pocket dup (") over - \ Interpretation, put string ! 251: THEN \ in temp buffer ! 252: ; immediate ! 253: ! 254: \ Remove command old-name and all subsequent definitions ! 255: ! 256: : $forget ( str len -- ) ! 257: 2dup last @ ( str len str len last-bc ) ! 258: BEGIN ! 259: dup >r ( str len str len last-bc R: last-bc ) ! 260: cell+ char+ count ( str len str len found-str found-len R: last-bc ) ! 261: string=ci IF ( str len R: last-bc ) ! 262: r> @ last ! 2drop clean-hash EXIT ( -- ) ! 263: THEN ! 264: 2dup r> @ dup 0= ( str len str len next-bc next-bc ) ! 265: UNTIL ! 266: drop 2drop 2drop \ clean hash table ! 267: ; ! 268: ! 269: : forget ( "old-name<>" -- ) ! 270: parse-word $forget ! 271: ; ! 272: ! 273: #include <search.fs> ! 274: ! 275: \ The following constants are required in some parts ! 276: \ of the code, mainly instance variables and see. Having to reverse ! 277: \ engineer our own CFAs seems somewhat weird, but we gained a bit speed. ! 278: ! 279: \ Each colon definition is surrounded by colon and semicolon ! 280: \ constant below contain address of their xt ! 281: ! 282: : (function) ; ! 283: defer (defer) ! 284: 0 value (value) ! 285: 0 constant (constant) ! 286: variable (variable) ! 287: create (create) ! 288: alias (alias) (function) ! 289: cell buffer: (buffer:) ! 290: ! 291: ' (function) @ \ ( <colon> ) ! 292: ' (function) cell + @ \ ( ... <semicolon> ) ! 293: ' (defer) @ \ ( ... <defer> ) ! 294: ' (value) @ \ ( ... <value> ) ! 295: ' (constant) @ \ ( ... <constant> ) ! 296: ' (variable) @ \ ( ... <variable> ) ! 297: ' (create) @ \ ( ... <create> ) ! 298: ' (alias) @ \ ( ... <alias> ) ! 299: ' (buffer:) @ \ ( ... <buffer:> ) ! 300: ! 301: \ now clean up the test functions ! 302: forget (function) ! 303: ! 304: \ and remember the constants ! 305: constant <buffer:> ! 306: constant <alias> ! 307: constant <create> ! 308: constant <variable> ! 309: constant <constant> ! 310: constant <value> ! 311: constant <defer> ! 312: constant <semicolon> ! 313: constant <colon> ! 314: ! 315: ' lit constant <lit> ! 316: ' sliteral constant <sliteral> ! 317: ' 0branch constant <0branch> ! 318: ' branch constant <branch> ! 319: ' doloop constant <doloop> ! 320: ' dotick constant <dotick> ! 321: ' doto constant <doto> ! 322: ' do?do constant <do?do> ! 323: ' do+loop constant <do+loop> ! 324: ' do constant <do> ! 325: ' exit constant <exit> ! 326: ' doleave constant <doleave> ! 327: ' do?leave constant <do?leave> ! 328: ! 329: ! 330: \ provide the memory management words ! 331: \ #include <claim.fs> ! 332: \ #include "memory.fs" ! 333: #include <alloc-mem.fs> ! 334: ! 335: #include <node.fs> ! 336: ! 337: : find-substr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) ! 338: \ if substr-len == 0 ? ! 339: dup 0 = IF ! 340: \ return 0 ! 341: 2drop 2drop 0 exit THEN ! 342: \ if substr-len <= basestr-len ? ! 343: dup 3 pick <= IF ! 344: \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 ! 345: 2 pick over - 1+ 0 DO dup 0 DO ! 346: \ substr-ptr[i] == basestr-ptr[j+i] ? ! 347: over i + c@ 4 pick j + i + c@ = IF ! 348: \ (I+1) == substr-len ? ! 349: dup i 1+ = IF ! 350: \ return J ! 351: 2drop 2drop j unloop unloop exit THEN ! 352: ELSE leave THEN ! 353: LOOP LOOP ! 354: THEN ! 355: \ if there is no match then exit with basestr-len as return value ! 356: 2drop nip ! 357: ; ! 358: ! 359: : find-isubstr ( basestr-ptr basestr-len substr-ptr substr-len -- pos ) ! 360: \ if substr-len == 0 ? ! 361: dup 0 = IF ! 362: \ return 0 ! 363: 2drop 2drop 0 exit THEN ! 364: \ if substr-len <= basestr-len ? ! 365: dup 3 pick <= IF ! 366: \ run J from 0 to "basestr-len"-"substr-len" and I from 0 to "substr-len"-1 ! 367: 2 pick over - 1+ 0 DO dup 0 DO ! 368: \ substr-ptr[i] == basestr-ptr[j+i] ? ! 369: over i + c@ lcc 4 pick j + i + c@ lcc = IF ! 370: \ (I+1) == substr-len ? ! 371: dup i 1+ = IF ! 372: \ return J ! 373: 2drop 2drop j unloop unloop exit THEN ! 374: ELSE leave THEN ! 375: LOOP LOOP ! 376: THEN ! 377: \ if there is no match then exit with basestr-len as return value ! 378: 2drop nip ! 379: ; ! 380: ! 381: : find-nextline ( str-ptr str-len -- pos ) ! 382: \ run I from 0 to "str-len"-1 and check str-ptr[i] ! 383: dup 0 ?DO over i + c@ CASE ! 384: \ 0x0a (=LF) found ? ! 385: 0a OF ! 386: \ if current cursor is at end position (I == "str-len"-1) ? ! 387: dup 1- i = IF ! 388: \ return I+1 ! 389: 2drop i 1+ unloop exit THEN ! 390: \ if str-ptr[I+1] == 0x0d (=CR) ? ! 391: over i 1+ + c@ 0d = IF ! 392: \ return I+2 ! 393: 2drop i 2+ ELSE ! 394: \ else return I+1 ! 395: 2drop i 1+ THEN ! 396: unloop exit ! 397: ENDOF ! 398: \ 0x0d (=CR) found ? ! 399: 0d OF ! 400: \ if current cursor is at end position (I == "str-len"-1) ? ! 401: dup 1- i = IF ! 402: \ return I+1 ! 403: 2drop i 1+ unloop exit THEN ! 404: \ str-ptr[I+1] == 0x0a (=LF) ? ! 405: over i 1+ + c@ 0a = IF ! 406: \ return I+2 ! 407: 2drop i 2+ ELSE ! 408: \ return I+1 ! 409: 2drop i 1+ THEN ! 410: unloop exit ! 411: ENDOF ! 412: ENDCASE LOOP nip ! 413: ; ! 414: ! 415: : string-at ( str1-ptr str1-len pos -- str2-ptr str2-len ) ! 416: -rot 2 pick - -rot swap chars + swap ! 417: ; ! 418: ! 419: \ appends the string beginning at addr2 to the end of the string ! 420: \ beginning at addr1 ! 421: \ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! ! 422: \ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! ! 423: ! 424: : string-cat ( addr1 len1 addr2 len2 -- addr1 len1+len2 ) ! 425: \ len1 := len1+len2 ! 426: rot dup >r over + -rot ! 427: ( addr1 len1+len2 dest-ptr src-ptr len2 ) ! 428: 3 pick r> chars + -rot ! 429: ( ... dest-ptr src-ptr ) ! 430: 0 ?DO ! 431: 2dup c@ swap c! ! 432: char+ swap char+ swap ! 433: LOOP 2drop ! 434: ; ! 435: ! 436: \ appends a character to the end of the string beginning at addr ! 437: \ !!! THERE MUST BE SUFFICIENT MEMORY RESERVED FOR THE STRING !!! ! 438: \ !!! BEGINNING AT ADDR1 (cp. 'strcat' in 'C' ) !!! ! 439: ! 440: : char-cat ( addr len character -- addr len+1 ) ! 441: -rot 2dup >r >r 1+ rot r> r> chars + c! ! 442: ; ! 443: ! 444: \ Returns true if source and destination overlap ! 445: : overlap ( src dest size -- true|false ) ! 446: 3dup over + within IF 3drop true ELSE rot tuck + within THEN ! 447: ; ! 448: ! 449: : parse-2int ( str len -- val.lo val.hi ) ! 450: \ ." parse-2int ( " 2dup swap . . ." -- " ! 451: [char] , split ?dup IF eval ELSE drop 0 THEN ! 452: -rot ?dup IF eval ELSE drop 0 THEN ! 453: \ 2dup swap . . ." )" cr ! 454: ; ! 455: ! 456: \ peek/poke minimal implementation, just to support FCode drivers ! 457: \ Any implmentation with full error detection will be platform specific ! 458: : cpeek ( addr -- false | byte true ) c@ true ; ! 459: : cpoke ( byte addr -- success? ) c! true ; ! 460: : wpeek ( addr -- false | word true ) w@ true ; ! 461: : wpoke ( word addr -- success? ) w! true ; ! 462: : lpeek ( addr -- false | lword true ) l@ true ; ! 463: : lpoke ( lword addr -- success? ) l! true ; ! 464: ! 465: defer reboot ( -- ) ! 466: defer halt ( -- ) ! 467: defer disable-watchdog ( -- ) ! 468: defer reset-watchdog ( -- ) ! 469: defer set-watchdog ( +n -- ) ! 470: defer set-led ( type instance state -- status ) ! 471: defer get-flashside ( -- side ) ! 472: defer set-flashside ( side -- status ) ! 473: defer read-bootlist ( -- ) ! 474: defer furnish-boot-file ( -- adr len ) ! 475: defer set-boot-file ( adr len -- ) ! 476: defer mfg-mode? ( -- flag ) ! 477: defer of-prompt? ( -- flag ) ! 478: defer debug-boot? ( -- flag ) ! 479: defer bmc-version ( -- adr len ) ! 480: defer cursor-on ( -- ) ! 481: defer cursor-off ( -- ) ! 482: ! 483: : nop-reboot ( -- ) ." reboot not available" abort ; ! 484: : nop-halt ( -- ) ." halt not available" abort ; ! 485: : nop-disable-watchdog ( -- ) ; ! 486: : nop-reset-watchdog ( -- ) ; ! 487: : nop-set-watchdog ( +n -- ) drop ; ! 488: : nop-set-led ( type instance state -- status ) drop drop drop ; ! 489: : nop-get-flashside ( -- side ) ." Cannot get flashside" cr ABORT ; ! 490: : nop-set-flashside ( side -- status ) ." Cannot set flashside" cr ABORT ; ! 491: : nop-read-bootlist ( -- ) ; ! 492: : nop-furnish-bootfile ( -- adr len ) s" net:" ; ! 493: : nop-set-boot-file ( adr len -- ) 2drop ; ! 494: : nop-mfg-mode? ( -- flag ) false ; ! 495: : nop-of-prompt? ( -- flag ) false ; ! 496: : nop-debug-boot? ( -- flag ) false ; ! 497: : nop-bmc-version ( -- adr len ) s" XXXXX" ; ! 498: : nop-cursor-on ( -- ) ; ! 499: : nop-cursor-off ( -- ) ; ! 500: ! 501: ' nop-reboot to reboot ! 502: ' nop-halt to halt ! 503: ' nop-disable-watchdog to disable-watchdog ! 504: ' nop-reset-watchdog to reset-watchdog ! 505: ' nop-set-watchdog to set-watchdog ! 506: ' nop-set-led to set-led ! 507: ' nop-get-flashside to get-flashside ! 508: ' nop-set-flashside to set-flashside ! 509: ' nop-read-bootlist to read-bootlist ! 510: ' nop-furnish-bootfile to furnish-boot-file ! 511: ' nop-set-boot-file to set-boot-file ! 512: ' nop-mfg-mode? to mfg-mode? ! 513: ' nop-of-prompt? to of-prompt? ! 514: ' nop-debug-boot? to debug-boot? ! 515: ' nop-bmc-version to bmc-version ! 516: ' nop-cursor-on to cursor-on ! 517: ' nop-cursor-off to cursor-off ! 518: ! 519: : reset-all reboot ; ! 520: ! 521: \ Load base ! 522: 10000000 value load-base ! 523: 2000000 value flash-load-base ! 524: ! 525: \ provide first level debug support ! 526: #include "debug.fs" ! 527: \ provide 7.5.3.1 Dictionary search ! 528: #include "dictionary.fs" ! 529: \ block data access for IO devices - ought to be implemented in engine ! 530: #include "rmove.fs" ! 531: \ provide a simple run time preprocessor ! 532: #include <preprocessor.fs> ! 533: ! 534: : $dnumber base @ >r decimal $number r> base ! ; ! 535: : (.d) base @ >r decimal (.) r> base ! ; ! 536: ! 537: \ IP address conversion ! 538: ! 539: : (ipaddr) ( "a.b.c.d" -- FALSE | n1 n2 n3 n4 TRUE ) ! 540: base @ >r decimal ! 541: over s" 000.000.000.000" comp 0= IF 2drop false r> base ! EXIT THEN ! 542: [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot ! 543: [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot ! 544: [char] . left-parse-string $number IF 2drop false r> base ! EXIT THEN -rot ! 545: $number IF false r> base ! EXIT THEN ! 546: true r> base ! ! 547: ; ! 548: ! 549: : (ipformat) ( n1 n2 n3 n4 -- str len ) ! 550: base @ >r decimal ! 551: 0 <# # # # [char] . hold drop # # # [char] . hold ! 552: drop # # # [char] . hold drop # # #s #> ! 553: r> base ! ! 554: ; ! 555: ! 556: : ipformat ( n1 n2 n3 n4 -- ) (ipformat) type ; ! 557: ! 558:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.