1 /******************************************************************************
2 *
3 * Copyright (C) 2006, The Gentee Group. All rights reserved.
4 * This file is part of the Gentee open source project - http://www.gentee.com.
5 *
6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT").
7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS
8 * ACCEPTANCE OF THE AGREEMENT.
9 *
10 * ID: str 18.10.06 0.0.A.
11 *
12 * Author: Alexey Krivonogov
13 *
14 * Summary: This file provides functionality for 'str' type.
15 *
16 ******************************************************************************/
17
18 #include "str.h"
19 #include "../genteeapi/gentee.h"
20 #include "../os/user/defines.h"
21
22 /*-----------------------------------------------------------------------------
23 * Id: str_opadd F4
24 *
25 * Summary: Appending types to the string. Append #b(str) to #b(str) =>
26 #b( str += str ).
27 *
28 * Title: str += type
29 *
30 * Return: The result string.
31 *
32 * Define: operator str +=( str left, str right )
33 *
34 -----------------------------------------------------------------------------*/
35
36 pstr STDCALL str_add( pstr dest, pstr src )
37 {
38 dest->use--;
39 return buf_add( dest, src );
40 }
41
42 /*-----------------------------------------------------------------------------
43 * Id: str_opadd_1 FC
44 *
45 * Summary: Append #b(uint) to #b(str) => #b( str += uint ).
46 *
47 * Define: operator str +=( str left, uint right )
48 *
49 -----------------------------------------------------------------------------*/
50
51 pstr STDCALL str_appenduint( pstr ps, uint val )
52 {
53 return str_printf( ps, "%u", val );
54 }
55
56 /*-----------------------------------------------------------------------------
57 * str_clear F3
58 *
59 * Summary: Clear the string.
60 *
61 * Return: #lng/retobj#
62 *
63 * Define: method str str.clear()
64 *
65 -----------------------------------------------------------------------------*/
66
67 pstr STDCALL str_clear( pstr ps )
68 {
69 ps->use = 1;
70 ps->data[0] = 0;
71
72 return ps;
73 }
74
75 /*-----------------------------------------------------------------------------
76 * Id: str_opeq F4
77 *
78 * Summary: Copy the string.
79 *
80 * Return: The result string.
81 *
82 * Define: operator str =( str left, str right )
83 *
84 -----------------------------------------------------------------------------*/
85
86 pstr STDCALL str_copy( pstr dest, pstr src )
87 {
88 return buf_copy( ( pbuf )dest, str_ptr( src ), src->use );
89 }
90
91 /*-----------------------------------------------------------------------------
92 * Id: str_copy F2
93 *
94 * Summary: Copying. The method copies data into a string.
95 *
96 * Title: str.copy...
97 *
98 * Params: ptr - The pointer to the data being copied. All data to the zero /
99 character will be copied.
100 *
101 * Return: #lng/retobj#
102 *
103 * Define: method str str.copy( uint ptr )
104 *
105 -----------------------------------------------------------------------------*/
106
107 pstr STDCALL str_copyzero( pstr ps, pubyte src )
108 {
109 ps->use--;
110 buf_copyzero( ps, src );
111 return ps;
112 }
113
114 /*-----------------------------------------------------------------------------
115 * Id: str_copy_1 FA
116 *
117 * Summary: The method copies the specified size of the data into a string.
118 *
119 * Params: ptr - The pointer to the data being copied. If data does not end in /
120 a zero, it will be added automatically.
121 len - The size of the data being copied.
122 *
123 * Return: #lng/retobj#
124 *
125 * Define: method str str.load( uint ptr, uint len )
126 *
127 -----------------------------------------------------------------------------*/
128
129 pstr STDCALL str_copylen( pstr ps, pubyte src, uint len )
130 {
131 ps->use--;
132 // print("String Load %i %x\n", len, src );
133 buf_copy( ps, src, len );
134 return buf_appendch( ps, 0 );
135 }
136
137 //--------------------------------------------------------------------------
138
139 pstr STDCALL str_dirfile( pstr dir, pstr name, pstr ret )
140 {
141 str_copy( ret, dir );
142 str_trim( ret, SLASH, TRIM_ONE | TRIM_RIGHT );
143 return str_printf( ret, "%c%s", SLASH, str_ptr( name ));
144 }
145
146 /*-----------------------------------------------------------------------------
147 * Id: str_substr F2
148 *
149 * Summary: Getting a substring.
150 *
151 * Params: src - Initial string.
152 off - Substring offset.
153 len - Substring size.
154 *
155 * Return: #lng/retobj#
156 *
157 * Define: method str str.substr( str src, uint off, uint len )
158 *
159 -----------------------------------------------------------------------------*/
160
161 pstr STDCALL str_substr( pstr dest, pstr src, uint off, uint len )
162 {
163 uint slen = str_len( src );
164
165 if ( len && off < slen )
166 {
167 if ( len > slen - off )
168 len = slen - off;
169 str_copylen( dest, str_ptr( src ) + off, len );
170 }
171 else
172 str_clear( dest );
173
174 return dest;
175 }
176
177 /*-----------------------------------------------------------------------------
178 *
179 * ID: str_getdirfile 19.10.06 0.0.A.
180 *
181 * Summary: Get directory and filename
182 *
183 -----------------------------------------------------------------------------*/
184
185 uint STDCALL str_getdirfile( pstr src, pstr dir, pstr name )
186 {
187 uint separ = str_find( src, 0, SLASH, 1 );
188 uint off;
189
190 off = separ >= str_len( src ) ? 0 : separ + 1;
191
192 if ( name )
193 str_copyzero( name, str_ptr( src ) + off );
194 if ( dir )
195 str_substr( dir, src, 0, separ < str_len( src ) ? separ : 0 );
196 return 1;
197 }
198
199 pstr STDCALL str_init( pstr ps )
200 {
201 mem_zero( ps, sizeof( str ));
202
203 buf_alloc( ps, 32 );
204 ps->data[0] = 0;
205 ps->use = 1;
206 // print("String Init ps=%x len = %i data = %x ptr=%s\n", ps, ps->use, ps->data,
207 // ps->data );
208 return ps;
209 }
210
211 /*-----------------------------------------------------------------------------
212 * Id: str_find F2
213 *
214 * Summary: Find the character in the string.
215 *
216 * Title: str.find...
217 *
218 * Params: offset - The offset to start searching from.
219 symbol - Search character.
220 fromend - If it equals 1, the search will be carried out from the /
221 end of the string.
222 *
223 * Return: The offset of the character if it is found. If the character is not
224 found, the length of the string is returned.
225 *
226 * Define: method uint str.findch( uint offset, uint symbol, uint fromend )
227 *
228 -----------------------------------------------------------------------------*/
229
230 uint STDCALL str_find( pstr ps, uint offset, ubyte symbol, uint fromend )
231 {
232 pubyte cur = ps->data + offset;
233 pubyte end = ps->data + str_len( ps );
234 pubyte last;
235
236 if ( _gentee.multib )
237 {
238 last = end;
239 while ( cur < end )
240 {
241 if ( os_isleadbyte( *cur ))
242 cur++;
243 else
244 if ( *cur == symbol )
245 if ( fromend )
246 last = cur;
247 else
248 break;
249 cur++;
250 }
251 if ( fromend )
252 cur = last;
253 }
254 else
255 if ( fromend )
256 {
257 cur = end;
258 while ( cur >= ps->data )
259 {
260 if ( *cur == symbol )
261 break;
262 cur--;
263 }
264 if ( cur < ps->data )
265 cur = end;
266 }
267 else
268 {
269 while ( cur < end )
270 {
271 if ( *cur == symbol )
272 break;
273 cur++;
274 }
275 }
276
277 return ( cur < end ? cur - ps->data : str_len( ps ));
278 }
279
280 /*-----------------------------------------------------------------------------
281 * Id: str_find_1 FA
282 *
283 * Summary: Find the character from the beginning of the string.
284 *
285 * Params: symbol - Search character.
286 *
287 * Define: method uint str.findch( uint symbol )
288 *
289 -----------------------------------------------------------------------------*/
290
291 uint STDCALL str_findch( pstr ps, ubyte symbol )
292 {
293 return str_find( ps, 0, symbol, 0 );
294 }
295
296 /*-----------------------------------------------------------------------------
297 * Id: str_oplen F4
298 *
299 * Summary: Get the length of a string.
300 *
301 * Return: The length of the string.
302 *
303 * Define: operator uint *( str left )
304 *
305 -----------------------------------------------------------------------------*/
306
307 uint STDCALL str_len( pstr ps )
308 {
309 return ps->use - 1;
310 }
311
312 /*-----------------------------------------------------------------------------
313 *
314 * ID: str_print 19.10.06 0.0.A.
315 *
316 * Summary: Output wsprintf to str.
317 *
318 -----------------------------------------------------------------------------*/
319
320 pstr CDECLCALL str_printf( pstr ps, pubyte output, ... )
321 {
322 va_list args;
323 uint len = ps->use - 1;
324
325 str_expand( ps, 512 );
326 va_start( args, output );
327 str_setlen( ps, len + vsprintf( ps->data + len, output, args ));
328 va_end( args );
329
330 return ps;
331 }
332
333 /*-----------------------------------------------------------------------------
334 * Id: str_printf F2
335 *
336 * Summary: Write formatted data to a string. The method formats and stores a
337 series of characters and values in string. Each argument is
338 converted and output according to the corresponding C/C++ format
339 specification (printf) in format parameter.
340 *
341 * Params: format - The format of the output.
342 clt - Optional arguments.
343 *
344 * Return: #lng/retobj#
345 *
346 * Define: method str str.printf( str format, collection clt )
347 *
348 -----------------------------------------------------------------------------*/
349
350 pstr STDCALL str_sprintf( pstr ps, pstr output, pcollect pclt )
351 {
352 uint args[32];
353 uint len = ps->use - 1;
354 uint i, k = 0, itype;
355
356 str_expand( ps, 1024 );
357 for ( i = 0; i < collect_count( pclt ); i++ )
358 {
359 itype = collect_gettype( pclt, i );
360 if ( itype == TDouble || itype == TLong || itype == TUlong )
361 {
362 args[k++] = *( puint )collect_index( pclt, i );
363 args[k++] = *(( puint )collect_index( pclt, i ) + 1 );
364 }
365 else
366 {
367 args[k++] = *( puint )collect_index( pclt, i );
368 if ( itype == TStr )
369 args[k - 1] = (uint)(( pstr )args[k - 1])->data;
370 }
371 }
372 str_setlen( ps, len + vsprintf( ps->data + len, output->data, (pubyte)args ));
373
374 return ps;
375 }
376
377 /*-----------------------------------------------------------------------------
378 * Id: str_out4 F2
379 *
380 * Summary: Output a 32-bit value. The value is appended at the end of the
381 string.
382 *
383 * Params: format - The format of the output. It is the same as in the function /
384 'printf' in C programming language.
385 val - 32-bit value to be appended.
386 *
387 * Return: #lng/retobj#
388 *
389 * Define: method str str.out4( str format, uint val )
390 *
391 -----------------------------------------------------------------------------*/
392
393 pstr STDCALL str_out4( pstr ps, pstr format, uint val )
394 {
395 return str_printf( ps, str_ptr( format ), val );
396 }
397
398 /*-----------------------------------------------------------------------------
399 * Id: str_out4_1 FA
400 *
401 * Summary: Output a 64-bit value. The value is appended at the end of the
402 string.
403 *
404 * Params: format - The format of the output. It is the same as in the function /
405 'printf' in C programming language.
406 val - 64-bit value to be appended.
407 *
408 * Return: #lng/retobj#
409 *
410 * Define: method str str.out8( str format, ulong val )
411 *
412 -----------------------------------------------------------------------------*/
413
414 pstr STDCALL str_out8( pstr ps, pstr format, ulong64 val )
415 {
416 // print("Printf %x %s %I64u\n", ps, str_ptr(ps), format );
417 // print("Printf %s\n", str_ptr( format ) );
418 return str_printf( ps, str_ptr( format ), val );
419 }
420
421 /*-----------------------------------------------------------------------------
422 * Id: str_print F3
423 *
424 * Summary: Print a string into the console window.
425 *
426 * Define: method str.print()
427 *
428 -----------------------------------------------------------------------------*/
429
430 void STDCALL str_output( pstr ps )
431 {
432 _gentee.print( str_ptr( ps ), str_len( ps ));
433 }
434
435 /*-----------------------------------------------------------------------------
436 * Id: str_print_1 F8
437 *
438 * Summary: Print a string into the console window.
439 *
440 * Params: output - The output string.
441 *
442 * Define: func print( str output )
443 *
444 -----------------------------------------------------------------------------*/
445
446 /*-----------------------------------------------------------------------------
447 * Id: str_setlen F2
448 *
449 * Summary: Setting a new string size. The method does not reserve space.
450 You cannot specify the size of a string greater than the reserved
451 space you have. Mostly, this function is used for specifying the
452 size of a string after external functions write data to it.
453 *
454 * Params: len - New string size.
455 *
456 * Return: #lng/retobj#
457 *
458 * Define: method str str.setlen( uint len )
459 *
460 -----------------------------------------------------------------------------*/
461
462 pstr STDCALL str_setlen( pstr ps, uint len )
463 {
464 if ( len >= ps->size )
465 len = 0;
466
467 ps->use = len + 1;
468 ps->data[ len ] = 0;
469
470 return ps;
471 }
472
473 /*-----------------------------------------------------------------------------
474 *
475 * ID: str_trim 19.10.06 0.0.A.
476 *
477 * Summary: Trim left and right characters
478 *
479 * Params:
480 *
481 -----------------------------------------------------------------------------*/
482
483 pstr STDCALL str_trim( pstr ps, uint symbol, uint flag )
484 {
485 uint len = str_len( ps );
486 /* uint rsymbol = symbol
487
488 if flag & $TRIM_PAIR
489 {
490 switch symbol
491 {
492 case '(' : rsymbol = ')'
493 case '{' : rsymbol = '}'
494 case '[' : rsymbol = ']'
495 case '<' : rsymbol = '>'
496 }
497 }*/
498 if ( flag & TRIM_RIGHT )
499 {
500 uint i = len;
501
502 while ( i && ps->data[ i - 1 ] == symbol )
503 {
504 i--;
505 if ( flag & TRIM_ONE )
506 break;
507 }
508 if ( i < len )
509 str_setlen( ps, i );
510 }
511 /* if flag & $TRIM_LEFT
512 {
513 uint cur = this.ptr()
514 uint end = cur + *this
515
516 while cur < end && cur->byte == symbol
517 {
518 cur++
519 if flag & $TRIM_ONE : break
520 }
521 if cur != this.ptr() : this.del( 0, cur - this.ptr())
522 }
523 */
524 return ps;
525 }
526
527 /*-----------------------------------------------------------------------------
528 *
529 * ID: str_new 19.10.06 0.0.A.
530 *
531 * Summary: Create str object.
532 *
533 -----------------------------------------------------------------------------*/
534
535 pstr STDCALL str_new( pubyte ptr )
536 {
537 pstr ret = mem_alloc( sizeof( str ));
538
539 str_init( ret );
540 if ( ptr )
541 str_copyzero( ret, ptr );
542
543 return ret;
544 }
545
546 /*-----------------------------------------------------------------------------
547 *
548 * ID: str_destroy 19.10.06 0.0.A.
549 *
550 * Summary: Destroy str object.
551 *
552 -----------------------------------------------------------------------------*/
553
554 void STDCALL str_destroy( pstr ps )
555 {
556 str_delete( ps );
557 mem_free( ps );
558 }
559
560 /*-----------------------------------------------------------------------------
561 *
562 * ID: str_isequalign 19.10.06 0.0.A.
563 *
564 * Summary: If two string equal.
565 *
566 -----------------------------------------------------------------------------*/
567
568 uint STDCALL str_isequalign( pstr left, pstr right )
569 {
570 return left->use == right->use &&
571 !mem_cmpign( str_ptr( left ), str_ptr( right ), left->use );
572 }
573
574 /*-----------------------------------------------------------------------------
575 *
576 * ID: str_pos2line 19.10.06 0.0.A.
577 *
578 * Summary: Get the line from absolute position.
579 *
580 -----------------------------------------------------------------------------*/
581
582 uint STDCALL str_pos2line( pstr ps, uint pos, puint lineoff )
583 {
584 uint i, off = 0;
585 uint line = 0;
586 pubyte cur = str_ptr( ps );
587
588 for ( i = 0; i < pos; i++ )
589 {
590 if ( cur[i] == 0xA )
591 {
592 line++;
593 off = i + 1;
594 }
595 }
596 if ( lineoff )
597 *lineoff = pos - off;
598 return line;
599 }
600
601 //--------------------------------------------------------------------------
602
603 uint STDCALL ptr_wildcardignore( pubyte src, pubyte mask )
604 {
605 while ( 1 )
606 {
607 if ( !*src )
608 return ( !*mask || ( *mask == '*' && !*( mask + 1 ))) ? TRUE : FALSE;
609 if ( !*mask )
610 break;
611 if ( os_lower( ( pubyte )*src ) == os_lower( ( pubyte )*mask ) ||
612 *mask == '?' )
613 {
614 src++;
615 mask++;
616 }
617 else
618 if ( *mask == '*' )
619 {
620 if ( os_lower( ( pubyte )*src ) == os_lower( ( pubyte )*( mask + 1 )) &&
621 ptr_wildcardignore( src, mask + 1 ))
622 return TRUE;
623 src++;
624 }
625 else
626 break;
627 }
628 return FALSE;
629 }
630
631 /*-----------------------------------------------------------------------------
632 ** Id: str_fwildcard F2
633 *
634 * Summary: Wildcard check. Check if a string coincides with the specified mask.
635 *
636 * Params: wildcard - The mask being checked. It can contain '?' (one character) /
637 and '*' (any number of characters).
638 *
639 * Return: Returns 1 if the string coincides with the mask.
640 *
641 * Define: method uint str.fwildcard( str wildcard )
642 *
643 -----------------------------------------------------------------------------*/
644
645 uint STDCALL str_fwildcard( pstr name, pstr mask )
646 {
647 uint ret;
648 uint dotstr;
649 uint dotmask;
650 pubyte pname = str_ptr( name );
651 pubyte pmask = str_ptr( mask );
652 uint isstr = FALSE;
653 uint ismask = FALSE;
654
655 dotstr = str_find( name, str_len( name ), '.', TRUE );
656 dotmask = str_find( mask, str_len( mask ), '.', TRUE );
657
658 if ( pname[ dotstr ] )
659 {
660 pname[ dotstr ] = 0;
661 isstr = TRUE;
662 }
663 if ( pmask[ dotmask ] )
664 {
665 pmask[ dotmask ] = 0;
666 ismask = TRUE;
667 }
668 ret = ptr_wildcardignore( pname, pmask );
669 if ( ismask || ( dotmask && pmask[ dotmask - 1 ] != '*' ))
670 ret &= ptr_wildcardignore( isstr ? pname + dotstr + 1 : "",
671 ismask ? pmask + dotmask + 1 : "" );
672 if ( isstr )
673 pname[ dotstr ] = '.';
674 if ( ismask )
675 pmask[ dotmask ] = '.';
676 return ret;
677 }
678
679 //--------------------------------------------------------------------------