FreeBASIC  0.91.0
hlp-str.bas
Go to the documentation of this file.
1 '' string helpers
2 ''
3 ''
4 
5 
6 #include once "fb.bi"
7 #include once "fbint.bi"
8 #include once "dstr.bi"
9 
10 '':::::
11 #define ASSIGN_SETUP(dst, src, _type) _
12  dim as integer dst_len, src_len :_
13  :_
14  if( src = NULL ) then :_
15  src_len = 0 :_
16  else :_
17  src_len = len( *src ) :_
18  end if :_
19  :_
20  if( src_len = 0 ) then :_
21  if( *dst <> NULL ) then :_
22  deallocate( *dst ) :_
23  *dst = NULL :_
24  exit sub :_
25  end if :_
26  end if :_
27  :_
28  if( *dst = NULL ) then :_
29  dst_len = 0 :_
30  else :_
31  dst_len = len( **dst ) :_
32  end if :_
33  :_
34  if( dst_len <> src_len ) then :_
35  *dst = xallocate( (src_len+1) * len( _type ) ) :_
36  end if
37 
38 '':::::
39 #define CONCATASSIGN_SETUP(dst, src, _type) _
40  dim as integer dst_len, src_len :_
41  :_
42  if( src = NULL ) then :_
43  exit sub :_
44  end if :_
45  :_
46  src_len = len( *src ) :_
47  if( src_len = 0 ) then :_
48  exit sub :_
49  end if :_
50  :_
51  if( *dst = NULL ) then :_
52  dst_len = 0 :_
53  *dst = xallocate( (src_len+1) * len( _type ) ) :_
54  else :_
55  dst_len = len( **dst ) :_
56  *dst = xreallocate( *dst, (dst_len+src_len+1) * len( _type ) ) :_
57  end if
58 
59 '':::::
60 sub ZstrAssign _
61  ( _
62  byval dst as zstring ptr ptr, _
63  byval src as zstring ptr _
64  )
65 
66  ASSIGN_SETUP( dst, src, zstring )
67 
68  if( *dst <> NULL ) then
69  **dst = *src
70  end if
71 
72 end sub
73 
74 '':::::
75 sub ZstrAssignW _
76  ( _
77  byval dst as zstring ptr ptr, _
78  byval src as wstring ptr _
79  )
80 
81  ASSIGN_SETUP( dst, src, zstring )
82 
83  if( *dst <> NULL ) then
84  **dst = *src
85  end if
86 
87 end sub
88 
89 '':::::
90 sub ZstrConcatAssign _
91  ( _
92  byval dst as zstring ptr ptr, _
93  byval src as zstring ptr _
94  )
95 
96  CONCATASSIGN_SETUP( dst, src, zstring )
97 
98  if( *dst <> NULL ) then
99  *(*dst + dst_len) = *src
100  end if
101 
102 end sub
103 
104 '':::::
105 sub ZstrConcatAssignW _
106  ( _
107  byval dst as zstring ptr ptr, _
108  byval src as wstring ptr _
109  )
110 
111  CONCATASSIGN_SETUP( dst, src, zstring )
112 
113  if( *dst <> NULL ) then
114  *(*dst + dst_len) = *src
115  end if
116 
117 end sub
118 
119 
120 '':::::
121 sub WstrAssign _
122  ( _
123  byval dst as wstring ptr ptr, _
124  byval src as wstring ptr _
125  )
126 
127  ASSIGN_SETUP( dst, src, wstring )
128 
129  if( *dst <> NULL ) then
130  **dst = *src
131  end if
132 
133 end sub
134 
135 '':::::
136 sub WstrAssignA _
137  ( _
138  byval dst as wstring ptr ptr, _
139  byval src as zstring ptr _
140  )
141 
142  ASSIGN_SETUP( dst, src, wstring )
143 
144  if( *dst <> NULL ) then
145  **dst = *src
146  end if
147 
148 end sub
149 
150 '':::::
151 sub WstrConcatAssign _
152  ( _
153  byval dst as wstring ptr ptr, _
154  byval src as wstring ptr _
155  )
156 
157  CONCATASSIGN_SETUP( dst, src, wstring )
158 
159  if( *dst <> NULL ) then
160  *(*dst + dst_len) = *src
161  end if
162 
163 end sub
164 
165 '':::::
166 sub WstrConcatAssignW _
167  ( _
168  byval dst as wstring ptr ptr, _
169  byval src as zstring ptr _
170  )
171 
172  CONCATASSIGN_SETUP( dst, src, wstring )
173 
174  if( *dst <> NULL ) then
175  *(*dst + dst_len) = *src
176  end if
177 
178 end sub
179 
180 '':::::
181 function ZstrDup _
182  ( _
183  byval s as zstring ptr _
184  ) as zstring ptr
185 
186  dim as zstring ptr dst
187 
188  dst = xallocate( len( *s ) + 1 )
189  *dst = *s
190 
191  function = dst
192 
193 end function
194 
195 '':::::
196 function WstrDup _
197  ( _
198  byval s as wstring ptr _
199  ) as wstring ptr
200 
201  dim as wstring ptr dst
202 
203  dst = xallocate( len( *s ) * len( wstring ) + len( wstring ) )
204  *dst = *s
205 
206  function = dst
207 
208 end function
209 
210 '':::::
211 function hReplace _
212  ( _
213  byval orgtext as zstring ptr, _
214  byval oldtext as zstring ptr, _
215  byval newtext as zstring ptr _
216  ) as string static
217 
218  dim as integer oldlen, newlen, p
219  static as string text, remtext
220 
221  oldlen = len( *oldtext )
222  newlen = len( *newtext )
223 
224  text = *orgtext
225  p = 0
226  do
227  p = instr( p+1, text, *oldtext )
228  if( p = 0 ) then
229  exit do
230  end if
231 
232  remtext = mid( text, p + oldlen )
233  text = left( text, p-1 )
234  text += *newtext
235  text += remtext
236  p += newlen-1
237  loop
238 
239  function = text
240 
241 end function
242 
243 '':::::
244 function hReplaceW _
245  ( _
246  byval orgtext as wstring ptr, _
247  byval oldtext as wstring ptr, _
248  byval newtext as wstring ptr _
249  ) as wstring ptr static
250 
251  dim as integer oldlen, newlen, p
252  static as DWSTRING text, remtext
253 
254  oldlen = len( *oldtext )
255  newlen = len( *newtext )
256 
257  DWstrAssign( text, orgtext )
258 
259  p = 0
260  do
261  p = instr( p+1, *text.data, *oldtext )
262  if( p = 0 ) then
263  exit do
264  end if
265 
266  DWstrAssign( remtext, mid( *text.data, p + oldlen ) )
267  DWstrAssign( text, left( *text.data, p-1 ) )
268  DWstrConcatAssign( text, newtext )
269  DWstrConcatAssign( text, remtext.data )
270  p += newlen-1
271  loop
272 
273  function = text.data
274 
275 end function
276 
277 '':::::
278 function hReplaceChar _
279  ( _
280  byval orgtext as zstring ptr, _
281  byval oldchar as integer, _
282  byval newchar as integer _
283  ) as zstring ptr
284 
285  for i as integer = 0 to len( *orgtext ) - 1
286  if( orgtext[i] = oldchar ) then
287  orgtext[i] = newchar
288  end if
289  next
290 
291  function = orgtext
292 
293 end function
294 
295 '':::::
296 function hReEscape _
297  ( _
298  byval text as zstring ptr, _
299  byref textlen as integer, _
300  byref isunicode as integer _
301  ) as zstring ptr static
302 
303  static as DZSTRING res
304  dim as integer char, lgt, i, value, isnumber
305  dim as zstring ptr src, dst, src_end
306 
307  '' convert escape sequences to internal format
308 
309  isunicode = FALSE
310  textlen = 0
311 
312  lgt = len( *text )
313  if( lgt = 0 ) then
314  return text
315  end if
316 
317  DZstrAllocate( res, lgt * 2 )
318 
319  src = text
320  dst = res.data
321 
322  src_end = src + lgt
323  do while( src < src_end )
324  char = *src
325  src += 1
326 
327  '' '\'?
328  if( char = CHAR_RSLASH ) then
329 
330  if( src >= src_end ) then exit do
331 
332  '' change to internal
333  *dst = FB_INTSCAPECHAR
334  dst += 1
335 
336  isnumber = FALSE
337 
338  char = *src
339  src += 1
340 
341  '' if it's a literal number, convert to octagonal
342  select case char
343  case CHAR_0 to CHAR_9
344  isnumber = TRUE
345 
346  value = (char - CHAR_0)
347  '' max 3 digits
348  for i = 2 to 3
349  if( src >= src_end ) then exit for
350 
351  char = *src
352  if( (char < CHAR_0) or (char > CHAR_9) ) then
353  exit for
354  end if
355  value = (value * 10) + (char - CHAR_0)
356  src += 1
357  next
358 
359  case CHAR_AMP, CHAR_XUPP, CHAR_XLOW
360  if( src >= src_end ) then exit do
361 
362  value = 0
363 
364  if( char = CHAR_AMP ) then
365  char = *src
366  src += 1
367  else
368  '' make '\x', '\X' look like '\&H'
369  char = CHAR_HUPP
370  end if
371 
372  select case as const char
373  '' hex?
374  case CHAR_HUPP, CHAR_HLOW
375  isnumber = TRUE
376 
377  '' max 2 digits
378  for i = 1 to 2
379  if( src >= src_end ) then exit for
380 
381  char = *src
382  select case char
383  case CHAR_ALOW to CHAR_FLOW, _
384  CHAR_AUPP to CHAR_FUPP, _
385  CHAR_0 to CHAR_9
386  char -= CHAR_0
387  if( char > 9 ) then
388  char -= (CHAR_AUPP - CHAR_9 - 1)
389  end if
390  if( char > 16 ) then
391  char -= (CHAR_ALOW - CHAR_AUPP)
392  end if
393 
394  value = (value * 16) + char
395 
396  case else
397  exit for
398  end select
399  src += 1
400  next
401 
402  '' oct?
403  case CHAR_OUPP, CHAR_OLOW
404  isnumber = TRUE
405 
406  '' max 3 digits
407  for i = 1 to 3
408  if( src >= src_end ) then exit for
409 
410  char = *src
411  if( (char < CHAR_0) or (char > CHAR_7) ) then
412  exit for
413  end if
414  value = (value * 8) + (char - CHAR_0)
415  src += 1
416  next
417 
418  '' bin?
419  case CHAR_BUPP, CHAR_BLOW
420  isnumber = TRUE
421 
422  '' max 8 digits
423  for i = 1 to 8
424  if( src >= src_end ) then exit for
425 
426  char = *src
427  if( (char < CHAR_0) or (char > CHAR_1) ) then
428  exit for
429  end if
430  value = (value * 2) + (char - CHAR_0)
431  src += 1
432  next
433 
434  end select
435 
436  case CHAR_ALOW
437  '' GAS does not support '\a'
438  isnumber = TRUE
439  value = CHAR_BELL
440 
441  '' 16-bit unicode?
442  case CHAR_ULOW
443  isunicode = TRUE
444 
445  '' 'u'
446  *dst = char
447  dst += 1
448 
449  for i = 1 to 4
450  *dst = *src
451  dst += 1
452  src += 1
453  next
454 
455  textlen += 2
456 
457  continue do
458 
459  '' 32-bit unicode?
460  case CHAR_UUPP
461  isunicode = TRUE
462 
463  '' break in two 16-bit..
464 
465  '' 'u'
466  *dst = CHAR_UUPP
467  dst += 1
468 
469  for i = 1 to 4
470  *dst = *src
471  dst += 1
472  src += 1
473  next
474 
475  '' '\u'
476  dst[0] = FB_INTSCAPECHAR
477  dst[1] = CHAR_UUPP
478  dst += 2
479 
480  for i = 1 to 4
481  *dst = *src
482  dst += 1
483  src += 1
484  next
485 
486  textlen += 4
487 
488  continue do
489 
490  end select
491 
492  if( isnumber ) then
493  if( cuint( value ) > 255 ) then
494  errReportWarn( FB_WARNINGMSG_NUMBERTOOBIG )
495  value = 255
496  end if
497 
498  '' save the oct len, or concatenation would fail
499  '' if other numeric characters follow
500  if( value < 8 ) then
501  lgt = 1
502  elseif( value < 64 ) then
503  lgt = 2
504  else
505  lgt = 3
506  end if
507 
508  *dst = lgt
509  dst += 1
510 
511  *dst = oct( value )
512  dst += lgt
513 
514  textlen += 1
515 
516  continue do
517  end if
518 
519  end if
520 
521  *dst = char
522  dst += 1
523  textlen += 1
524  loop
525 
526  '' null-term
527  *dst = 0
528 
529  function = res.data
530 
531 end function
532 
533 '':::::
534 function hReEscapeW _
535  ( _
536  byval text as wstring ptr, _
537  byref textlen as integer _
538  ) as wstring ptr static
539 
540  static as DWSTRING res
541  dim as integer char, lgt, i, isnumber
542  dim as uinteger value
543  dim as wstring ptr src, dst, src_end
544 
545  '' convert escape sequences to internal format
546 
547  textlen = 0
548 
549  lgt = len( *text )
550  if( lgt = 0 ) then
551  return text
552  end if
553 
554  DWstrAllocate( res, lgt * 2 )
555 
556  src = text
557  dst = res.data
558 
559  src_end = src + lgt
560  do while( src < src_end )
561  char = *src
562  src += 1
563 
564  '' '\'?
565  if( char = CHAR_RSLASH ) then
566 
567  if( src >= src_end ) then exit do
568 
569  '' change to internal
570  *dst = FB_INTSCAPECHAR
571  dst += 1
572 
573  isnumber = FALSE
574 
575  char = *src
576  src += 1
577 
578  '' if it's a literal number, convert to octagonal
579  select case char
580  case CHAR_0 to CHAR_9
581  isnumber = TRUE
582 
583  value = (char - CHAR_0)
584  '' max 5 digits
585  for i = 2 to 5
586  if( src >= src_end ) then exit for
587 
588  char = *src
589  if( (char < CHAR_0) or (char > CHAR_9) ) then
590  exit for
591  end if
592  value = (value * 10) + (char - CHAR_0)
593  src += 1
594  next
595 
596  case CHAR_AMP, CHAR_XUPP, CHAR_XLOW
597  if( src >= src_end ) then exit do
598 
599  value = 0
600 
601  if( char = CHAR_AMP ) then
602  char = *src
603  src += 1
604  else
605  '' make '\x', '\X' look like '\&H'
606  char = CHAR_HUPP
607  end if
608 
609  select case as const char
610  '' hex?
611  case CHAR_HUPP, CHAR_HLOW
612  isnumber = TRUE
613 
614  '' max 4 digits
615  for i = 1 to 4
616  if( src >= src_end ) then exit for
617 
618  char = *src
619  select case char
620  case CHAR_ALOW to CHAR_FLOW, _
621  CHAR_AUPP to CHAR_FUPP, _
622  CHAR_0 to CHAR_9
623  char -= CHAR_0
624  if( char > 9 ) then
625  char -= (CHAR_AUPP - CHAR_9 - 1)
626  end if
627  if( char > 16 ) then
628  char -= (CHAR_ALOW - CHAR_AUPP)
629  end if
630 
631  value = (value * 16) + char
632 
633  case else
634  exit for
635  end select
636  src += 1
637  next
638 
639  '' oct?
640  case CHAR_OUPP, CHAR_OLOW
641  isnumber = TRUE
642 
643  '' max 6 digits
644  for i = 1 to 6
645  if( src >= src_end ) then exit for
646 
647  char = *src
648  if( (char < CHAR_0) or (char > CHAR_7) ) then
649  exit for
650  end if
651  value = (value * 8) + (char - CHAR_0)
652  src += 1
653  next
654 
655  '' bin?
656  case CHAR_BUPP, CHAR_BLOW
657  isnumber = TRUE
658 
659  '' max 16 digits
660  for i = 1 to 16
661  if( src >= src_end ) then exit for
662 
663  char = *src
664  if( (char < CHAR_0) or (char > CHAR_1) ) then
665  exit for
666  end if
667  value = (value * 2) + (char - CHAR_0)
668  src += 1
669  next
670 
671  end select
672 
673  '' 16-bit unicode?
674  case CHAR_ULOW
675  '' 'u'
676  *dst = char
677  dst += 1
678 
679  for i = 1 to 4
680  *dst = *src
681  dst += 1
682  src += 1
683  next
684 
685  textlen += 2
686 
687  continue do
688 
689  '' 32-bit unicode?
690  case CHAR_UUPP
691  '' break in two 16-bit..
692 
693  '' 'u'
694  *dst = CHAR_UUPP
695  dst += 1
696 
697  for i = 1 to 4
698  *dst = *src
699  dst += 1
700  src += 1
701  next
702 
703  '' '\u'
704  dst[0] = FB_INTSCAPECHAR
705  dst[1] = CHAR_UUPP
706  dst += 2
707 
708  for i = 1 to 4
709  *dst = *src
710  dst += 1
711  src += 1
712  next
713 
714  textlen += 4
715 
716  continue do
717 
718  end select
719 
720  if( isnumber ) then
721  if( cuint( value ) > 65535 ) then
722  errReportWarn( FB_WARNINGMSG_NUMBERTOOBIG )
723  value = 65535
724  end if
725 
726  '' save the oct len, or concatenation would fail
727  '' if other numeric characters follow
728  lgt = 1
729  do while( value > 7 )
730  value shr= 3
731  lgt += 1
732  loop
733 
734  *dst = lgt
735  dst += 1
736 
737  *dst = woct( value )
738  dst += lgt
739 
740  textlen += 1
741 
742  continue do
743  end if
744 
745  end if
746 
747  *dst = char
748  dst += 1
749  textlen += 1
750  loop
751 
752  '' null-term
753  *dst = 0
754 
755  function = res.data
756 
757 end function
758 
759 '':::::
760 function hEscape _
761  ( _
762  byval text as const zstring ptr _
763  ) as const zstring ptr static
764 
765  static as DZSTRING res
766  dim as integer c, octlen, lgt
767 /'dst,'/ src_end
768  dim as zstring ptr dst
769 
770  '' convert the internal escape sequences to GAS format
771 
772  octlen = 0
773 
774  lgt = len( *text )
775  if( lgt = 0 ) then
776  return text
777  end if
778 
779  DZstrAllocate( res, lgt * 4 )
780 
781  src = text
782  dst = res.data
783 
784  src_end = src + lgt
785  do while( src < src_end )
786  c = *src
787  src += 1
788 
789  select case c
790  case CHAR_RSLASH, CHAR_QUOTE
791  *dst = CHAR_RSLASH
792  dst += 1
793 
794  case FB_INTSCAPECHAR
795  *dst = CHAR_RSLASH
796  dst += 1
797 
798  if( src >= src_end ) then exit do
799  c = *src
800  src += 1
801 
802  '' octagonal?
803  if( c >= 1 and c <= 3 ) then
804  octlen = c
805  if( src >= src_end ) then exit do
806  c = *src
807  src += 1
808  end if
809 
810  case 0 to 31, 128 to 255
811  *dst = CHAR_RSLASH
812  dst += 1
813 
814  if( c < 8 ) then
815  c += CHAR_0
816 
817  elseif( c < 64 ) then
818  *dst = CHAR_0 + (c shr 3)
819  dst += 1
820  c = CHAR_0 + (c and 7)
821 
822  else
823  dst[0] = CHAR_0 + (c shr 6)
824  dst[1] = CHAR_0 + ((c and &b00111000) shr 3)
825  dst += 2
826  c = CHAR_0 + (c and 7)
827  end if
828 
829  end select
830 
831  *dst = c
832  dst += 1
833 
834  '' add quote's when the octagonal escape ends
835  if( octlen > 0 ) then
836  octlen -= 1
837  if( octlen = 0 ) then
838  dst[0] = CHAR_QUOTE
839  dst[1] = CHAR_QUOTE
840  dst += 2
841  end if
842  end if
843  loop
844 
845  '' null-term
846  *dst = 0
847 
848  function = res.data
849 
850 end function
851 
852 '':::::
853 function hRemapChar _
854  ( _
855  byval char as integer _
856  ) as integer static
857 
858  select case as const char
859  case asc( "r" )
860  function = CHAR_CR
861 
862  case asc( "l" ), asc( "n" )
863  function = CHAR_LF
864 
865  case asc( "t" )
866  function = CHAR_TAB
867 
868  case asc( "b" )
869  function = CHAR_BKSPC
870 
871  case asc( "a" )
872  function = CHAR_BELL
873 
874  case asc( "f" )
875  function = CHAR_FORMFEED
876 
877  case asc( "v" )
878  function = CHAR_VTAB
879 
880  case else
881  function = char
882  end select
883 
884 end function
885 
886 '':::::
887 function hHasEscape _
888  ( _
889  byval text as zstring ptr _
890  ) as integer static
891 
892  dim as uinteger char
893  dim as integer lgt
894 
895  lgt = len( *text )
896  do while( lgt > 0 )
897  '' '\'?
898  if( *text = CHAR_RSLASH ) then
899  text += 1
900 
901  char = *text
902  select case as const char
903  case asc( "r" ), _
904  asc( "l" ), _
905  asc( "n" ), _
906  asc( "t" ), _
907  asc( "b" ), _
908  asc( "a" ), _
909  asc( "f" ), _
910  asc( "v" ), _
911  CHAR_QUOTE, _
912  CHAR_0 to CHAR_9, _
913  CHAR_AMP, _
914  CHAR_ULOW, CHAR_UUPP, _
915  CHAR_RSLASH
916 
917  return TRUE
918  end select
919  end if
920 
921  text += 1
922  lgt -= 1
923  loop
924 
925  function = FALSE
926 
927 end function
928 
929 '':::::
930 function hHasEscapeW _
931  ( _
932  byval text as wstring ptr _
933  ) as integer static
934 
935  dim as uinteger char
936  dim as integer lgt
937 
938  lgt = len( *text )
939  do while( lgt > 0 )
940  '' '\'?
941  if( *text = CHAR_RSLASH ) then
942  text += 1
943 
944  char = *text
945  select case as const char
946  case asc( "r" ), _
947  asc( "l" ), _
948  asc( "n" ), _
949  asc( "t" ), _
950  asc( "b" ), _
951  asc( "a" ), _
952  asc( "f" ), _
953  asc( "v" ), _
954  CHAR_QUOTE, _
955  CHAR_0 to CHAR_9, _
956  CHAR_AMP, _
957  CHAR_ULOW, CHAR_UUPP, _
958  CHAR_RSLASH
959 
960  return TRUE
961  end select
962  end if
963 
964  text += 1
965  lgt -= 1
966  loop
967 
968  function = FALSE
969 
970 end function
971 
972 ''::::
973 function hU16ToWchar _
974  ( _
975  byval src as wstring ptr _
976  ) as uinteger static
977 
978  dim as uinteger char, c
979  dim as integer i
980 
981  '' x86 little-endian assumption
982  char = 0
983 
984  for i = 1 to 4
985  c = *src - CHAR_0
986  src += 1
987 
988  if( c > 9 ) then
989  c -= (CHAR_AUPP - CHAR_9 - 1)
990  end if
991  if( c > 16 ) then
992  c -= (CHAR_ALOW - CHAR_AUPP)
993  end if
994 
995  char = (char * 16) or c
996  next
997 
998  function = char
999 
1000 end function
1001 
1002 
1003 '':::::
1004 function hEscapeW _
1005  ( _
1006  byval text as wstring ptr _
1007  ) as zstring ptr static
1008 
1009  static as DZSTRING res
1010  dim as uinteger char, c
1011  dim as integer lgt, i, wcharlen
1012  dim as wstring ptr src, src_end
1013  dim as zstring ptr dst
1014 
1015  '' convert the internal escape sequences to GAS format
1016 
1017  wcharlen = typeGetSize( FB_DATATYPE_WCHAR )
1018 
1019  '' up to (4 * wcharlen) ascii chars can be used per unicode char
1020  '' (up to one '\ooo' per byte of wchar)
1021  lgt = len( *text )
1022  if( lgt = 0 ) then
1023  return NULL
1024  end if
1025 
1026  DZstrAllocate( res, lgt * (1+3) * wcharlen )
1027 
1028  src = text
1029  dst = res.data
1030 
1031  src_end = src + lgt
1032  do while( src < src_end )
1033  char = *src
1034  src += 1
1035 
1036  '' internal espace char?
1037  if( char = FB_INTSCAPECHAR ) then
1038  if( src >= src_end ) then exit do
1039  char = *src
1040  src += 1
1041 
1042  '' octagonal? convert to integer..
1043  '' note: it can be up to 6 digits due wchr()
1044  '' when evaluated at compile-time
1045  if( (char >= 1) and (char <= 6) ) then
1046  i = char
1047  char = 0
1048 
1049  if( src + i > src_end ) then exit do
1050 
1051  do while( i > 0 )
1052  char = (char * 8) + (*src - CHAR_0)
1053  src += 1
1054  i -= 1
1055  loop
1056 
1057  else
1058  '' unicode 16-bit?
1059  if( char = asc( "u" ) ) then
1060  if( src + 4 > src_end ) then exit do
1061  char = hU16ToWchar( src )
1062  src += 4
1063 
1064  '' remap char as they will become a octagonal seq
1065  else
1066  char = hRemapChar( char )
1067  end if
1068  end if
1069 
1070  end if
1071 
1072  '' convert every char to octagonal form as GAS can't
1073  '' handle unicode literal strings
1074  for i = 1 to wcharlen
1075  *dst = CHAR_RSLASH
1076  dst += 1
1077 
1078  '' x86 little-endian assumption
1079  c = char and 255
1080  if( c < 8 ) then
1081  dst[0] = CHAR_0 + c
1082  dst += 1
1083 
1084  elseif( c < 64 ) then
1085  dst[0] = CHAR_0 + (c shr 3)
1086  dst[1] = CHAR_0 + (c and 7)
1087  dst += 2
1088 
1089  else
1090  dst[0] = CHAR_0 + (c shr 6)
1091  dst[1] = CHAR_0 + ((c and &b00111000) shr 3)
1092  dst[2] = CHAR_0 + (c and 7)
1093  dst += 3
1094  end if
1095 
1096  char shr= 8
1097  next
1098 
1099  loop
1100 
1101  '' null=term
1102  *dst = 0
1103 
1104  function = res.data
1105 
1106 end function
1107 
1108 '':::::
1109 function hUnescape _
1110  ( _
1111  byval text as zstring ptr _
1112  ) as zstring ptr static
1113 
1114  static as DZSTRING res
1115  dim as integer char, lgt, i
1116  dim as zstring ptr src, dst, src_end
1117 
1118  lgt = len( *text )
1119  if( lgt = 0 ) then
1120  return text
1121  end if
1122 
1123  DZstrAllocate( res, lgt )
1124 
1125  src = text
1126  dst = res.data
1127 
1128  src_end = src + lgt
1129  do while( src < src_end )
1130  char = *src
1131  src += 1
1132 
1133  if( char = FB_INTSCAPECHAR ) then
1134 
1135  if( src >= src_end ) then exit do
1136  char = *src
1137  src += 1
1138 
1139  '' octagonal? convert to integer..
1140  if( (char >= 1) and (char <= 3) ) then
1141  i = char
1142  char = 0
1143  do while( i > 0 )
1144  char = (char * 8) + (*src - CHAR_0)
1145  src += 1
1146  i -= 1
1147  loop
1148 
1149  else
1150  '' remap char
1151  char = hRemapChar( char )
1152 
1153  '' note: zstring's won't contain \u seqs
1154  end if
1155 
1156  end if
1157 
1158  *dst = char
1159  dst += 1
1160 
1161  loop
1162 
1163  '' null-term
1164  *dst = 0
1165 
1166  function = res.data
1167 
1168 end function
1169 
1170 '':::::
1171 function hUnescapeW _
1172  ( _
1173  byval text as wstring ptr _
1174  ) as wstring ptr static
1175 
1176  static as DWSTRING res
1177  dim as integer char, lgt, i
1178  dim as wstring ptr src, dst, src_end
1179 
1180  lgt = len( *text )
1181  if( lgt = 0 ) then
1182  return text
1183  end if
1184 
1185  DWstrAllocate( res, lgt )
1186 
1187  src = text
1188  dst = res.data
1189 
1190  src_end = src + lgt
1191  do while( src < src_end )
1192  char = *src
1193  src += 1
1194 
1195  if( char = FB_INTSCAPECHAR ) then
1196 
1197  if( src >= src_end ) then exit do
1198  char = *src
1199  src += 1
1200 
1201  '' octagonal? convert to integer..
1202  '' note: it can be up to 6 digits due wchr()
1203  '' when evaluated at compile-time
1204  if( (char >= 1) and (char <= 6) ) then
1205  i = char
1206  char = 0
1207  do while( i > 0 )
1208  char = (char * 8) + (*src - CHAR_0)
1209  src += 1
1210  i -= 1
1211  loop
1212 
1213  else
1214  '' unicode 16-bit?
1215  if( char = asc( "u" ) ) then
1216  if( src + 4 > src_end ) then exit do
1217  char = hU16ToWchar( src )
1218  src += 4
1219 
1220  '' remap char as they will become a octagonal seq
1221  else
1222  char = hRemapChar( char )
1223  end if
1224  end if
1225 
1226  end if
1227 
1228  *dst = char
1229  dst += 1
1230 
1231  loop
1232 
1233  '' null-term
1234  *dst = 0
1235 
1236  function = res.data
1237 
1238 end function
1239 
1240 function hCharNeedsEscaping _
1241  ( _
1242  byval ch as integer, _
1243  byval quotechar as integer _
1244  ) as integer
1245 
1246  '' Any special char, backslashes and single/double quotes (depending on
1247  '' context) must be escaped. Also any high (i.e. non-ASCII) codepage or
1248  '' Unicode chars should be escaped, to be safe.
1249  function = (ch < 32) or (ch >= 127) or _
1250  (ch = asc( $"\" )) or (ch = quotechar)
1251 end function
1252 
1253 function hIsValidHexDigit( byval ch as integer ) as integer
1254  function = ((ch >= asc( "0" )) and (ch <= asc( "9" ))) or _
1255  ((ch >= asc( "a" )) and (ch <= asc( "f" ))) or _
1256  ((ch >= asc( "A" )) and (ch <= asc( "F" )))
1257 end function
1258