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 #ifndef NOGENTEE
178
179 /*-----------------------------------------------------------------------------
180 *
181 * ID: str_getdirfile 19.10.06 0.0.A.
182 *
183 * Summary: Get directory and filename
184 *
185 -----------------------------------------------------------------------------*/
186
187 uint STDCALL str_getdirfile( pstr src, pstr dir, pstr name )
188 {
189 uint separ = str_find( src, 0, SLASH, 1 );
190 uint off;
191
192 off = separ >= str_len( src ) ? 0 : separ + 1;
193
194 if ( name )
195 str_copyzero( name, str_ptr( src ) + off );
196 if ( dir )
197 str_substr( dir, src, 0, separ < str_len( src ) ? separ : 0 );
198 return 1;
199 }
200
201 #endif // NOGENTEE
202
203 pstr STDCALL str_init( pstr ps )
204 {
205 mem_zero( ps, sizeof( str ));
206
207 buf_alloc( ps, 32 );
208 ps->data[0] = 0;
209 ps->use = 1;
210 // print("String Init ps=%x len = %i data = %x ptr=%s\n", ps, ps->use, ps->data,
211 // ps->data );
212 return ps;
213 }
214
215 #ifndef NOGENTEE
216
217 /*-----------------------------------------------------------------------------
218 * Id: str_find F2
219 *
220 * Summary: Find the character in the string.
221 *
222 * Title: str.find...
223 *
224 * Params: offset - The offset to start searching from.
225 symbol - Search character.
226 fromend - If it equals 1, the search will be carried out from the /
227 end of the string.
228 *
229 * Return: The offset of the character if it is found. If the character is not
230 found, the length of the string is returned.
231 *
232 * Define: method uint str.findch( uint offset, uint symbol, uint fromend )
233 *
234 -----------------------------------------------------------------------------*/
235
236 uint STDCALL str_find( pstr ps, uint offset, ubyte symbol, uint fromend )
237 {
238 pubyte cur = ps->data + offset;
239 pubyte end = ps->data + str_len( ps );
240 pubyte last;
241
242 if ( _gentee.multib )
243 {
244 last = end;
245 while ( cur < end )
246 {
247 if ( os_isleadbyte( *cur ))
248 cur++;
249 else
250 if ( *cur == symbol )
251 if ( fromend )
252 last = cur;
253 else
254 break;
255 cur++;
256 }
257 if ( fromend )
258 cur = last;
259 }
260 else
261 if ( fromend )
262 {
263 cur = end;
264 while ( cur >= ps->data )
265 {
266 if ( *cur == symbol )
267 break;
268 cur--;
269 }
270 if ( cur < ps->data )
271 cur = end;
272 }
273 else
274 {
275 while ( cur < end )
276 {
277 if ( *cur == symbol )
278 break;
279 cur++;
280 }
281 }
282
283 return ( cur < end ? cur - ps->data : str_len( ps ));
284 }
285
286 /*-----------------------------------------------------------------------------
287 * Id: str_find_1 FA
288 *
289 * Summary: Find the character from the beginning of the string.
290 *
291 * Params: symbol - Search character.
292 *
293 * Define: method uint str.findch( uint symbol )
294 *
295 -----------------------------------------------------------------------------*/
296
297 uint STDCALL str_findch( pstr ps, ubyte symbol )
298 {
299 return str_find( ps, 0, symbol, 0 );
300 }
301
302 #endif
303
304 /*-----------------------------------------------------------------------------
305 * Id: str_oplen F4
306 *
307 * Summary: Get the length of a string.
308 *
309 * Return: The length of the string.
310 *
311 * Define: operator uint *( str left )
312 *
313 -----------------------------------------------------------------------------*/
314
315 uint STDCALL str_len( pstr ps )
316 {
317 return ps->use - 1;
318 }
319
320 /*-----------------------------------------------------------------------------
321 *
322 * ID: str_print 19.10.06 0.0.A.
323 *
324 * Summary: Output wsprintf to str.
325 *
326 -----------------------------------------------------------------------------*/
327
328 pstr CDECLCALL str_printf( pstr ps, pubyte output, ... )
329 {
330 va_list args;
331 uint len = ps->use - 1;
332
333 str_expand( ps, 512 );
334 va_start( args, output );
335 str_setlen( ps, len + vsprintf( ps->data + len, output, args ));
336 va_end( args );
337
338 return ps;
339 }
340
341 #ifndef NOGENTEE
342
343 /*-----------------------------------------------------------------------------
344 * Id: str_printf F2
345 *
346 * Summary: Write formatted data to a string. The method formats and stores a
347 series of characters and values in string. Each argument is
348 converted and output according to the corresponding C/C++ format
349 specification (printf) in format parameter.
350 *
351 * Params: format - The format of the output.
352 clt - Optional arguments.
353 *
354 * Return: #lng/retobj#
355 *
356 * Define: method str str.printf( str format, collection clt )
357 *
358 -----------------------------------------------------------------------------*/
359
360 pstr STDCALL str_sprintf( pstr ps, pstr output, pcollect pclt )
361 {
362 uint args[32];
363 uint len = ps->use - 1;
364 uint i, k = 0, itype;
365
366 str_expand( ps, 1024 );
367 for ( i = 0; i < collect_count( pclt ); i++ )
368 {
369 itype = collect_gettype( pclt, i );
370 if ( itype == TDouble || itype == TLong || itype == TUlong )
371 {
372 args[k++] = *( puint )collect_index( pclt, i );
373 args[k++] = *(( puint )collect_index( pclt, i ) + 1 );
374 }
375 else
376 {
377 args[k++] = *( puint )collect_index( pclt, i );
378 if ( itype == TStr )
379 args[k - 1] = (uint)(( pstr )args[k - 1])->data;
380 }
381 }
382 str_setlen( ps, len + vsprintf( ps->data + len, output->data, (pubyte)args ));
383
384 return ps;
385 }
386
387 #endif // NOGENTEE
388
389 /*-----------------------------------------------------------------------------
390 * Id: str_out4 F2
391 *
392 * Summary: Output a 32-bit value. The value is appended at the end of the
393 string.
394 *
395 * Params: format - The format of the output. It is the same as in the function /
396 'printf' in C programming language.
397 val - 32-bit value to be appended.
398 *
399 * Return: #lng/retobj#
400 *
401 * Define: method str str.out4( str format, uint val )
402 *
403 -----------------------------------------------------------------------------*/
404
405 pstr STDCALL str_out4( pstr ps, pstr format, uint val )
406 {
407 return str_printf( ps, str_ptr( format ), val );
408 }
409
410 /*-----------------------------------------------------------------------------
411 * Id: str_out4_1 FA
412 *
413 * Summary: Output a 64-bit value. The value is appended at the end of the
414 string.
415 *
416 * Params: format - The format of the output. It is the same as in the function /
417 'printf' in C programming language.
418 val - 64-bit value to be appended.
419 *
420 * Return: #lng/retobj#
421 *
422 * Define: method str str.out8( str format, ulong val )
423 *
424 -----------------------------------------------------------------------------*/
425
426 pstr STDCALL str_out8( pstr ps, pstr format, ulong64 val )
427 {
428 // print("Printf %x %s %I64u\n", ps, str_ptr(ps), format );
429 // print("Printf %s\n", str_ptr( format ) );
430 return str_printf( ps, str_ptr( format ), val );
431 }
432
433 #ifndef NOGENTEE
434
435 /*-----------------------------------------------------------------------------
436 * Id: str_print F3
437 *
438 * Summary: Print a string into the console window.
439 *
440 * Define: method str.print()
441 *
442 -----------------------------------------------------------------------------*/
443
444 void STDCALL str_output( pstr ps )
445 {
446 _gentee.print( str_ptr( ps ), str_len( ps ));
447 }
448
449 #endif
450
451 /*-----------------------------------------------------------------------------
452 * Id: str_print_1 F8
453 *
454 * Summary: Print a string into the console window.
455 *
456 * Params: output - The output string.
457 *
458 * Define: func print( str output )
459 *
460 -----------------------------------------------------------------------------*/
461
462 /*-----------------------------------------------------------------------------
463 * Id: str_setlen F2
464 *
465 * Summary: Setting a new string size. The method does not reserve space.
466 You cannot specify the size of a string greater than the reserved
467 space you have. Mostly, this function is used for specifying the
468 size of a string after external functions write data to it.
469 *
470 * Params: len - New string size.
471 *
472 * Return: #lng/retobj#
473 *
474 * Define: method str str.setlen( uint len )
475 *
476 -----------------------------------------------------------------------------*/
477
478 pstr STDCALL str_setlen( pstr ps, uint len )
479 {
480 if ( len >= ps->size )
481 len = 0;
482
483 ps->use = len + 1;
484 ps->data[ len ] = 0;
485
486 return ps;
487 }
488
489 /*-----------------------------------------------------------------------------
490 *
491 * ID: str_trim 19.10.06 0.0.A.
492 *
493 * Summary: Trim left and right characters
494 *
495 * Params:
496 *
497 -----------------------------------------------------------------------------*/
498
499 pstr STDCALL str_trim( pstr ps, uint symbol, uint flag )
500 {
501 uint len = str_len( ps );
502 /* uint rsymbol = symbol
503
504 if flag & $TRIM_PAIR
505 {
506 switch symbol
507 {
508 case '(' : rsymbol = ')'
509 case '{' : rsymbol = '}'
510 case '[' : rsymbol = ']'
511 case '<' : rsymbol = '>'
512 }
513 }*/
514 if ( flag & TRIM_RIGHT )
515 {
516 uint i = len;
517
518 while ( i && ps->data[ i - 1 ] == symbol )
519 {
520 i--;
521 if ( flag & TRIM_ONE )
522 break;
523 }
524 if ( i < len )
525 str_setlen( ps, i );
526 }
527 /* if flag & $TRIM_LEFT
528 {
529 uint cur = this.ptr()
530 uint end = cur + *this
531
532 while cur < end && cur->byte == symbol
533 {
534 cur++
535 if flag & $TRIM_ONE : break
536 }
537 if cur != this.ptr() : this.del( 0, cur - this.ptr())
538 }
539 */
540 return ps;
541 }
542
543 /*-----------------------------------------------------------------------------
544 *
545 * ID: str_new 19.10.06 0.0.A.
546 *
547 * Summary: Create str object.
548 *
549 -----------------------------------------------------------------------------*/
550
551 pstr STDCALL str_new( pubyte ptr )
552 {
553 pstr ret = mem_alloc( sizeof( str ));
554
555 str_init( ret );
556 if ( ptr )
557 str_copyzero( ret, ptr );
558
559 return ret;
560 }
561
562 /*-----------------------------------------------------------------------------
563 *
564 * ID: str_destroy 19.10.06 0.0.A.
565 *
566 * Summary: Destroy str object.
567 *
568 -----------------------------------------------------------------------------*/
569
570 void STDCALL str_destroy( pstr ps )
571 {
572 str_delete( ps );
573 mem_free( ps );
574 }
575
576 /*-----------------------------------------------------------------------------
577 *
578 * ID: str_isequalign 19.10.06 0.0.A.
579 *
580 * Summary: If two string equal.
581 *
582 -----------------------------------------------------------------------------*/
583
584 uint STDCALL str_isequalign( pstr left, pstr right )
585 {
586 return left->use == right->use &&
587 !mem_cmpign( str_ptr( left ), str_ptr( right ), left->use );
588 }
589
590 /*-----------------------------------------------------------------------------
591 *
592 * ID: str_pos2line 19.10.06 0.0.A.
593 *
594 * Summary: Get the line from absolute position.
595 *
596 -----------------------------------------------------------------------------*/
597
598 uint STDCALL str_pos2line( pstr ps, uint pos, puint lineoff )
599 {
600 uint i, off = 0;
601 uint line = 0;
602 pubyte cur = str_ptr( ps );
603
604 for ( i = 0; i < pos; i++ )
605 {
606 if ( cur[i] == 0xA )
607 {
608 line++;
609 off = i + 1;
610 }
611 }
612 if ( lineoff )
613 *lineoff = pos - off;
614 return line;
615 }
616
617 //--------------------------------------------------------------------------
618
619 uint STDCALL ptr_wildcardignore( pubyte src, pubyte mask )
620 {
621 while ( 1 )
622 {
623 if ( !*src )
624 return ( !*mask || ( *mask == '*' && !*( mask + 1 ))) ? TRUE : FALSE;
625 if ( !*mask )
626 break;
627 if ( os_lower( ( pubyte )*src ) == os_lower( ( pubyte )*mask ) ||
628 *mask == '?' )
629 {
630 src++;
631 mask++;
632 }
633 else
634 if ( *mask == '*' )
635 {
636 if ( os_lower( ( pubyte )*src ) == os_lower( ( pubyte )*( mask + 1 )) &&
637 ptr_wildcardignore( src, mask + 1 ))
638 return TRUE;
639 src++;
640 }
641 else
642 break;
643 }
644 return FALSE;
645 }
646
647 #ifndef NOGENTEE
648
649 /*-----------------------------------------------------------------------------
650 ** Id: str_fwildcard F2
651 *
652 * Summary: Wildcard check. Check if a string coincides with the specified mask.
653 *
654 * Params: wildcard - The mask being checked. It can contain '?' (one character) /
655 and '*' (any number of characters).
656 *
657 * Return: Returns 1 if the string coincides with the mask.
658 *
659 * Define: method uint str.fwildcard( str wildcard )
660 *
661 -----------------------------------------------------------------------------*/
662
663 uint STDCALL str_fwildcard( pstr name, pstr mask )
664 {
665 uint ret;
666 uint dotstr;
667 uint dotmask;
668 pubyte pname = str_ptr( name );
669 pubyte pmask = str_ptr( mask );
670 uint isstr = FALSE;
671 uint ismask = FALSE;
672 uint empty = 0;
673
674 dotstr = str_find( name, 0, '.', TRUE );
675 dotmask = str_find( mask, 0, '.', TRUE );
676
677 if ( pname[ dotstr ] )
678 {
679 pname[ dotstr ] = 0;
680 isstr = TRUE;
681 }
682 if ( pmask[ dotmask ] )
683 {
684 pmask[ dotmask ] = 0;
685 ismask = TRUE;
686 }
687 ret = ptr_wildcardignore( pname, pmask );
688 if ( ismask || ( isstr && pmask[ dotmask - 1 ] != '*' ))
689 ret &= ptr_wildcardignore( isstr ? pname + dotstr + 1 : ( pubyte )&empty,
690 ismask ? pmask + dotmask + 1 : ( pubyte )&empty );
691 if ( isstr )
692 pname[ dotstr ] = '.';
693 if ( ismask )
694 pmask[ dotmask ] = '.';
695 return ret;
696 }
697
698 #endif
699 //--------------------------------------------------------------------------
700