File:  [gforth] / gforth / contrib / strings.fs
Revision 1.1: download - view: text, annotated - select for diffs
Fri Nov 5 14:27:33 2004 UTC (19 years, 5 months ago) by anton
Branches: MAIN
CVS tags: v0-7-0, HEAD
added Krishna Myneni's serial.fs, terminal.fs, and support stuff to contrib

    1: \ strings.fs
    2: \
    3: \ Gforth Version of the kForth string utility words
    4: \
    5: \ Copyright (c) 1999--2004 Krishna Myneni
    6: \
    7: \ This software is provided under the terms of the
    8: \ GNU General Public License.
    9: \
   10: \ Revisions:
   11: \
   12: \	03-24-1999  created  km
   13: \	03-25-1999  added number to string conversions  km
   14: \	08-12-1999  fixed f>string  km
   15: \	10-11-1999  added blank  km
   16: \	12-12-1999  fixed f>string for zero case  km
   17: \	12-22-1999  added -trailing, scan, and skip  km
   18: \	01-23-2000  replaced char with [char] for ANS Forth compatibility  km
   19: \	06-16-2000  added isdigit and modified string>s and string>f  km
   20: \	09-02-2000  fixed u>string to work over full range  km
   21: \	07-12-2001  used built-in Forth words <# #s #> for conversions,
   22: \	              added ud>string and d>string. f>string now can handle
   23: \                     decimal places greater than 8  km
   24: \	09-21-2001  changed occurences of DO to ?DO  km
   25: \	10-02-2001  added parse_args  km
   26: \	10-10-2001  fixed problem with f>string when number is 0e  km
   27: \	10-15-2001  added /STRING  km
   28: \	03-28-2002  added SEARCH, PARSE_TOKEN, PARSE_LINE, IS_LC_ALPHA  km
   29: \	07-31-2002  added SLITERAL; removed SEARCH since SEARCH and
   30: \		      COMPARE are now part of kForth  km
   31: \       04-12-2003  ported to PFE, gforth. removed defs of intrinsic words,
   32: \		      recoded for separate fp stack  km
   33: 
   34: : parse_token ( a u -- a2 u2 a3 u3)
   35: 	\ parse next token from the string; a3 u3 is the token string
   36: 	BL SKIP 2DUP BL SCAN 2>R R@ - 2R> 2SWAP ;
   37: 
   38: : parse_line ( a u -- a1 u1 a2 u2 ... n )
   39: 	( -trailing)
   40: 	0 >r
   41: 	begin
   42: 	  parse_token
   43: 	  dup
   44: 	while
   45: 	  r> 1+ >r
   46: 	  2swap
   47: 	repeat  
   48: 	2drop 2drop r> ;
   49: 
   50: : is_lc_alpha ( n -- flag | true if n is a lower case alphabetical character)
   51: 	DUP 96 > SWAP 123 < AND ;	
   52: 	
   53: : isdigit ( n -- flag | return true if n is ascii value of '0' through '9' )
   54: 	dup [char] / > swap [char] : < and ;
   55: 
   56: : strcpy ( ^str addr -- | copy a counted string to addr )
   57: 	>r dup c@ 1+ r> swap cmove ;
   58: 
   59: : strlen ( addr -- len | determine length of a null terminated string )
   60: 	\ This word is not intended for use on counted strings;
   61: 	\ Use "count" to obtain the length of a counted string.
   62: 	0
   63: 	begin
   64: 	  over c@ 0= dup invert if -rot 1+ swap 1+ swap rot then 
   65: 	until
   66: 	nip ;
   67: 
   68: 
   69: 16384 constant STR_BUF_SIZE
   70: create string_buf STR_BUF_SIZE allot	\ dynamic string buffer
   71: variable str_buf_ptr
   72: string_buf str_buf_ptr !
   73: 
   74: : adjust_str_buf_ptr ( u -- | adjust pointer to accomodate u bytes )
   75: 	str_buf_ptr @ swap +
   76: 	string_buf STR_BUF_SIZE + >=
   77: 	if
   78: 	  string_buf str_buf_ptr !	\ wrap pointer
   79: 	then ;
   80: 
   81: : strbufcpy ( ^str1 -- ^str2 | copy a counted string to the dynamic string buffer )
   82: 	dup c@ 1+ dup adjust_str_buf_ptr
   83: 	swap str_buf_ptr @ strcpy
   84: 	str_buf_ptr @ dup rot + str_buf_ptr ! ;
   85: 
   86: : strcat ( addr1 u1 addr2 u2 -- addr3 u3 )
   87: 	rot 2dup + 1+ adjust_str_buf_ptr 
   88: 	-rot
   89: 	2swap dup >r
   90: 	str_buf_ptr @ swap cmove
   91: 	str_buf_ptr @ r@ +
   92: 	swap dup r> + >r
   93: 	cmove 
   94: 	str_buf_ptr @
   95: 	dup r@ + 0 swap c!
   96: 	dup r@ + 1+ str_buf_ptr !
   97: 	r> ;
   98: 
   99: : strpck ( addr u -- ^str | create counted string )
  100: 	255 min dup 1+ adjust_str_buf_ptr 
  101: 	dup str_buf_ptr @ c!
  102: 	tuck str_buf_ptr @ 1+ swap cmove
  103: 	str_buf_ptr @ over + 1+ 0 swap c!
  104: 	str_buf_ptr @
  105: 	dup rot 1+ + str_buf_ptr ! ;
  106: 
  107: \
  108: \ Base 10 number to string conversions and vice-versa
  109: \
  110: 
  111: 32 constant NUMBER_BUF_LEN
  112: create number_buf NUMBER_BUF_LEN allot
  113: 
  114: create fnumber_buf 64 allot
  115: variable number_sign
  116: variable number_val
  117: variable fnumber_sign
  118: fvariable fnumber_val
  119: fvariable fnumber_divisor
  120: variable fnumber_power
  121: variable fnumber_digits
  122: variable fnumber_whole_part
  123: 
  124: variable number_count
  125: 
  126: : u>string ( u -- ^str | create counted string to represent u in base 10 )
  127: 	base @ swap decimal 0 <# #s #> strpck swap base ! ;
  128: 
  129: : ud>string ( ud -- ^str | create counted string to represent ud in base 10 )
  130: 	base @ >r decimal <# #s #> strpck r> base ! ;
  131: 
  132: : d>string ( d -- ^str | create counted string to represent d in base 10 )
  133: 	dup >r dabs ud>string r> 0< if s" -" rot count strcat strpck then ;
  134: 
  135: : s>string ( n -- ^str | create counted string to represent n in  base 10 )
  136: 	dup >r abs u>string
  137: 	r> 0< if
  138: 	  s" -" rot count strcat strpck
  139: 	then ;
  140: 
  141: : string>s ( ^str -- n | always interpret in base 10 )
  142: 	0 number_val !
  143: 	false number_sign !
  144: 	count
  145: 	0 ?do
  146: 	  dup c@
  147: 	  case
  148: 	    [char] -  of true number_sign ! endof 
  149: 	    [char] +  of false number_sign ! endof 
  150: 	    dup isdigit 
  151: 	    if
  152: 	      dup [char] 0 - number_val @ 10 * + number_val !
  153: 	    then
  154: 	  endcase
  155: 	  1+
  156: 	loop
  157: 	drop
  158: 	number_val @ number_sign @ if negate then ;
  159: 
  160:   \ conversion is in exponential format with n places 
  161: 
  162: : f>string ( n -- ^str ) ( F: f -- )
  163: 	fdup f0=
  164: 	if
  165: 	  f>d <# rot 0 ?do # loop #> s" e0" strcat 
  166: 	  s"  0." 2swap strcat strpck exit	  
  167: 	then
  168: 	dup 16 swap u< if drop fdrop c" ******" exit then  \ test for invalid n
  169: 	fnumber_digits !
  170: 	0 fnumber_power !
  171: 	fdup 0e f< fnumber_sign ! 
  172: 	fabs
  173: 	fdup 1e f<
  174: 	if
  175: 	  fdup 0e f>
  176: 	  if
  177: 	    begin
  178: 	      10e f* -1 fnumber_power +!
  179: 	      fdup 1e f>=
  180: 	    until
  181: 	  then
  182: 	else
  183: 	  fdup 
  184: 	  10e f>=
  185: 	  if
  186: 	    begin
  187: 	      10e f/ 1 fnumber_power +!
  188: 	      fdup 10e f<
  189: 	    until
  190: 	  then
  191: 	then
  192: 	10e fnumber_digits @ ( s>f) s>d d>f  f**
  193: 	f* floor f>d d>string
  194: 	count drop dup fnumber_buf
  195: 	fnumber_sign @ 
  196: 	if [char] - else bl then 
  197: 	swap c!
  198: 	fnumber_buf 1+ 1 cmove
  199: 	1+
  200: 	[char] . fnumber_buf 2 + c!
  201: 	fnumber_buf 3 + fnumber_digits @ cmove
  202: 	fnumber_buf fnumber_digits @ 3 +	
  203: 	s" e" strcat
  204: 	fnumber_power @ s>string count strcat
  205: 	strpck 	;
  206: 
  207: 	 
  208: : string>f ( ^str -- f )
  209: 	true fnumber_whole_part !
  210: 	0e fnumber_val f!
  211: 	1e fnumber_divisor f!
  212: 	false fnumber_sign !
  213: 	count 2dup + 1- nip swap
  214: 	begin
  215: 	  dup c@
  216: 	  case  
  217: 	    [char] - of true fnumber_sign ! endof
  218: 	    [char] + of false fnumber_sign ! endof
  219: 	    [char] . of false fnumber_whole_part ! endof
  220: 	    dup isdigit
  221: 	    if  
  222: 	      dup [char] 0 - ( s>f) s>d d>f
  223: 	      fnumber_whole_part @
  224: 	      if
  225: 	        fnumber_val f@ 10e f*
  226: 	      else
  227: 	        fnumber_divisor f@ 10e f*
  228: 	        fdup fnumber_divisor f!
  229: 	        f/ fnumber_val f@
  230: 	      then
  231: 	      f+ fnumber_val f!
  232: 	    else
  233: 	      dup dup [char] E = swap [char] e = or
  234: 	      if
  235: 	        drop 2dup
  236: 		- 
  237: 	        dup 0>
  238: 	        if
  239: 	          number_buf c!
  240: 	          dup 1+ number_buf 1+ number_buf c@ cmove
  241: 	          2drop
  242: 	          number_buf string>s ( s>f) s>d d>f 10e fswap f**
  243: 	        else
  244: 	          drop 2drop 1e
  245: 	        then
  246: 	        fnumber_val f@ f* fnumber_sign @ if fnegate then
  247: 	        exit
  248: 	      then
  249: 	    then
  250: 	  endcase
  251: 	  1+ 2dup <
  252: 	until	              
  253: 	2drop
  254: 	fnumber_val f@ 
  255: 	fnumber_sign @ if fnegate then ;	 
  256: 
  257: 
  258: \ parse a string delimited by spaces into fp args 
  259: 
  260: : parse_args ( a u -- n ) ( F: -- f1 ... fn )
  261: 	0 >r 
  262: 	begin
  263: 	  dup 0>
  264: 	while
  265: 	  bl skip 
  266: 	  2dup 
  267: 	  bl scan 2>r
  268: 	  r@ - dup 0= 
  269: 	  if drop r> 0 >r then
  270: 	  strpck string>f
  271: 	  2r> r> 
  272: 	  1+ >r
  273: 	repeat
  274: 	2drop r> ;
  275: 	  

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>