Objective-C++ Preprocessor  5.0 with ARC & GC
C++ classes to enhance syntax and manage reference counting.
objstr.h
Go to the documentation of this file.
1 /*
2  * objstr.h - NSString based string class with operators
3  * ========
4  *
5  * Created by John Holdsworth on 01/04/2009.
6  * Copyright 2009 © John Holdsworth. All Rights Reserved.
7  *
8  * $Id: //depot/ObjCpp/objstr.h#113 $
9  * $DateTime: 2014/01/31 00:43:52 $
10  *
11  * C++ classes to wrap up XCode classes for operator overload of
12  * useful operations such as access to NSArrays and NSDictionary
13  * by subscript or NSString operators such as + for concatenation.
14  *
15  * This works as the Apple Objective-C compiler supports source
16  * which mixes C++ with objective C. To enable this: for each
17  * source file which will include/import this header file, select
18  * it in Xcode and open it's "Info". To enable mixed compilation,
19  * for the file's "File Type" select: "sourcecode.cpp.objcpp".
20  *
21  * For bugs or ommisions please email objcpp@johnholdsworth.com
22  *
23  * Home page for updates and docs: http://objcpp.johnholdsworth.com
24  *
25  * If you find it useful please send a donation via paypal to account
26  * objcpp@johnholdsworth.com. Thanks.
27  *
28  * License
29  * =======
30  *
31  * You may make commercial use of this source in applications without
32  * charge but not sell it as source nor can you remove this notice from
33  * this source if you redistribute. You can make any changes you like
34  * to this code before redistribution but you must annotate them below.
35  *
36  * For further details http://objcpp.johnholdsworth.com/license.html
37  *
38  * THIS CODE IS PROVIDED “AS IS” WITHOUT WARRANTY OF ANY KIND EITHER
39  * EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
40  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
41  *
42  * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
43  * WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
44  * THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING
45  * ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT
46  * OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
47  * TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED
48  * BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH
49  * ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN
50  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
51  *
52  */
53 
54 #ifndef _objstr_h_
55 #define _objstr_h_
56 #ifdef __cplusplus
57 #import "objcpp.h"
58 #import <wctype.h>
59 
60 // very shortcuts
61 #define OO (OOString)
62 #define OOFmt OOFormat
63 
64 // shortcut equivalent for [NSString stringWithFormat:]
65 inline NSMutableString *OOFormat( NSString *format, ... ) NS_FORMAT_FUNCTION(1,2) OO_AUTORETURNS;
66 inline NSMutableString *OOFormat( NSString *format, ... ) {
67  va_list argp;
68  va_start(argp, format);
69  NSMutableString *str = [[NSMutableString alloc] initWithFormat:format arguments:argp];
70  va_end( argp );
71  return OO_AUTORELEASE( str );
72 }
73 
74 /*====================================================================================*/
75 /*============================= String classes =======================================*/
76 
77 /**
78  Internal class representing a susbscript operation into a string to access or assign
79  to individual characters or ranges
80 
81  Usage:
82  <pre>
83  OOString str <<= @"JOHN";
84  if ( str[1] != 'O' )
85  str[1] = 'O';
86  </pre>
87  */
88 
89 class OOStringSub {
90  friend class OOString;
92  NSRange idx;
93 
94  oo_inline OOStringSub( NSMutableString *ref, int sub ) {
95  str = ref;
96  idx = NSMakeRange( sub < 0 ? [str length]+sub : sub, 1 );
97  }
98  oo_inline OOStringSub( NSMutableString *ref, const NSRange &sub ) {
99  str = ref;
100  idx = sub;
101  if ( (NSInteger)idx.length < 0 )
102  idx.length = [str length] + idx.length - idx.location;
103  else if ( idx.length == NSNotFound )
104  idx.length = [str length] - idx.location;
105  }
106 public:
107  oo_inline BOOL isupper() { return iswupper( **this ); }
108  oo_inline BOOL islower() { return iswlower( **this ); }
109  oo_inline unichar operator + () { return towupper( **this ); }
110  oo_inline unichar operator - () { return towlower( **this ); }
111 
112  oo_inline operator unichar () const {
113  return **this;
114  }
115  oo_inline unichar operator * () const {
116  return !!str && idx.location<[str length] ?
117  [str characterAtIndex:idx.location] : 0;///
118  }
119  oo_inline operator NSString * () const OO_AUTORETURNS {
120  return [str substringWithRange:idx];
121  }
122 
123  oo_inline OOStringSub & operator = ( NSString *val ) {
124  [str replaceCharactersInRange:idx withString:val];
125  return *this;
126  }
127  oo_inline OOStringSub & operator = ( unichar val ) {
128  return *this = [NSString stringWithFormat:@"%c", val];
129  }
130  oo_inline OOStringSub & operator = ( const char *val ) {
131  return *this = [NSString stringWithUTF8String:val];
132  }
133 };
134 
135 class OOStringSearch;
136 class OOTmpString;
137 class OOPattern;
138 
139 /**
140  A string class wrapping around NSString with all the usual operators including subscript.
141  OOStringArray is \#defined as OOArray<OOString> and OOStringDict is \#defined as OODictionary<OString>
142  for convenience.
143 
144  Operators:
145  <table cellspacing=0><tr><th>operator<th>inplace<th>binary<th>arguments
146  <tr><td>assign<td>=<td>&nbsp;<td>String or NSString
147  <tr><td>copy<td>&lt;&lt;=<td>&nbsp;<td>String or NSString
148  <tr><td>append<td>+=<td>+<td>string or number
149  <tr><td>remove<td>-=<td>-<td>string
150  <tr><td>repeat<td>*=<td>*<td>count
151  <tr><td>split<td>&nbsp;<td>/<td>string
152  <tr><td>find<td><td>&amp;<td>pattern
153  <tr><td>parse<td><td>^<td>pattern
154  <tr><td>replace<td>|=<td>|<td>replace string = "/pat/with/"
155  <tr><td>subscript<td>&nbsp;<td>[]<td>character number
156  <tr><td>search<td>&nbsp;<td>[]<td>string
157  </table>
158 
159  Usage:
160  <pre>
161  OOString str <<= @"The time is ";
162  NSLog( "%@", *(str+ctime()) );
163  </pre>
164  */
165 
166 class OOString : public OOReference<NSMutableString *> {
167 #ifdef __OBJC_GC__
168  NSMutableString *ref2;
169  oo_inline virtual id rawset( NSMutableString *val ) OO_RETURNS {
170  return OOReference<NSMutableString *>::rawset( ref2 = val );
171  }
172 #endif
173 public:
175  oo_inline OOString( id val ) { set( val ); }
176  oo_inline OOString( cOOString str ) { *this = str; } /// <<= ??
177  oo_inline OOString( cOOString str, NSRange range ) {
178  if ( range.location != NSNotFound )
179  *this = [str substringWithRange:range];
180  }
181  oo_inline OOString( CFNullRef obj ) { set( OO_BRIDGE(id)obj ); }
182  oo_inline OOString( CFStringRef obj ) { set( OO_BRIDGE(id)obj ); }
183  oo_inline OOString( const OOStringSub &sub ) { *this = sub; }
184  //oo_inline OOString( const OOArraySub<OOString> &sub ) { *this = sub; }
185  //oo_inline OOString( const OODictionarySub<OOString> &sub ) { *this = sub; }
186  oo_inline OOString( const OONode &sub );
187  oo_inline OOString( const OONodeSub &sub );
188  oo_inline OOString( const OONodeArraySub &sub );
189  oo_inline OOString( int nilOrCapacity ) { *this = nilOrCapacity; }
190  oo_inline OOString( long nilOrCapacity ) { *this = nilOrCapacity; }
192  oo_inline OOString( NSMutableString *str ) { *this = str; }
193  oo_inline OOString( NSString *str ) { *this = str; }
194  oo_inline OOString( double val ) { *this += val; }
195  oo_inline OOString( const char *val ) {
196  if ( !val ) OOWarn( @"NULL const char * for OOString create" );
197  else rawset( [[NSMutableString alloc] initWithUTF8String:val] );
198  }
199  oo_inline OOString( const char *val, NSInteger len, int encoding = NSUTF8StringEncoding ) {
200  if ( !val ) OOWarn( @"NULL const char * passed in for OOString with len create" );
201  else if ( len < 0 ) OOWarn( @"Negative length %d for const char * OOString create", (int)len );
202  else rawset( [[NSMutableString alloc] initWithBytes:val length:len encoding:encoding] );
203  }
204  oo_inline OOString( OOData data, NSStringEncoding encoding = NSUTF8StringEncoding ) {
205  if ( !data ) OOWarn( @"nil OOData passed in for OOString create" );
206  else rawset( [[NSMutableString alloc] initWithData:data encoding:encoding] );
207  }
209  *this = val.join( @" " );
210  }
211 
212 #ifdef _LIBCPP_STRING
213  oo_inline OOString( const std::string &val ) { *this = val; }
214  oo_inline OOString &operator = ( const std::string &val ) { *this = val.c_str(); return *this; }///
215  oo_inline operator std::string () const { return [get() UTF8String]; }
216 #endif
217 
218  oo_inline OOData utf8Data( NSStringEncoding encoding = NSUTF8StringEncoding ) const {
219  NSInteger len = [get() lengthOfBytesUsingEncoding:encoding];
220  char *bytes = (char *)malloc( len+1 );
221  [get() getCString:bytes maxLength:len+1 encoding:encoding];
222  OOData out = [[NSData alloc] initWithBytesNoCopy:bytes length:len freeWhenDone:YES];
223  OO_RELEASE( *out );
224  return out;
225  }
226 
227  // basic operators
228  /// oo_inline NSMutableString *operator & () const { return autoget(); } ////
229  oo_inline operator const char * () const {
230  if ( get() )
231  return [get() UTF8String];
232  else
233 #ifdef DEBUG
234  return NULL; // hard crash on nil string during debugging
235 #else
236  return "(nil)"; // be more forgiving on released code
237 #endif
238  }
239  oo_inline operator OOData () const { return utf8Data(); }
240 
241  // string is "true" if it contains non-numeric or non-zero value
242  oo_inline operator double () const {
243  unichar firstChar = (*this)[0];
244  return iswdigit( firstChar ) || firstChar == '.' || firstChar == '-' || firstChar == '+' ?
245  [get() doubleValue] : get() ? firstChar : 0;
246  }
247 
248  oo_inline OOString capitalize() { return [get() capitalizedString]; }
249  oo_inline OOString operator + () { return [get() uppercaseString]; }
250  oo_inline OOString operator - () { return [get() lowercaseString]; }
251 
252  // assignment
253  oo_inline OOString &operator = ( NSMutableString *val ) { set( val ); return *this; }
254  oo_inline OOString &operator = ( OOReference<NSMutableString *> val ) { set( val ); return *this; }
255  oo_inline OOString &operator = ( NSString *val ) {
256  OOCopyImmutable( (NSMutableString *)val );
257  return *this;
258  }
259  oo_inline OOString &operator = ( int nilOrCapacity ) { set( nilOrCapacity ); return *this; }
260  oo_inline OOString &operator = ( long nilOrCapacity ) { set( nilOrCapacity ); return *this; }
261  oo_inline OOString &operator = ( const char *val ) { set( OOString(val).get() ); return *this; }
262  oo_inline OOString &operator = ( id val ) { set( val ); return *this; }
263 
264  oo_inline OOString &operator = ( cOOString val ) { set( val.get() ); return *this; }
265  oo_inline OOString &operator = ( const OOStringSub &val ) { OOCopyImmutable( (NSMutableString *)val ); return *this; }
266  oo_inline OOString &operator = ( const OOArraySub<OOString> &val ) { set( val.get() ); return *this; }
267  oo_inline OOString &operator = ( const OODictionarySub<OOString> &val ) { set( val.get() ); return *this; }
268  oo_inline OOString &operator = ( const OONodeArraySub &sub );
269  oo_inline OOString &operator = ( const OONodeSub &sub );
270  oo_inline OOString &operator = ( const OONode &sub );
271 
272  // inplace operators - append, remove, repeat
273  oo_inline OOString &operator += ( id val ) { [alloc() appendString:[val description]]; return *this; }
274  oo_inline OOString &operator += ( int val ) { [alloc() appendFormat:@"%d", val]; return *this; }
275  oo_inline OOString &operator += ( double val ) { [alloc() appendFormat:@"%f", val]; return *this; }
276  oo_inline OOString &operator += ( const char *val ) { [alloc() appendString:OOString( val ).get()]; return *this; }
277  oo_inline OOString &operator += ( NSMutableString *str ) { [alloc() appendString:str]; return *this; }
278  oo_inline OOString &operator += ( NSString *str ) { [alloc() appendString:!str ? @"(nil)" : str]; return *this; }
279  oo_inline OOString &operator += ( cOOString str ) { [alloc() appendString:!str ? @"(nil)" : str.get()]; return *this; }
280  oo_inline OOString &operator += ( const OOArraySub<OOString> &str ) { [alloc() appendString:str.get()]; return *this; }
281  oo_inline OOString &operator += ( const OODictionarySub<OOString> &str ) { [alloc() appendString:str.get()]; return *this; }
282 
284  oo_inline OOString &operator -= ( NSRange range ) {
285  [get() replaceCharactersInRange:range withString:@""];
286  return *this;
287  }
288  oo_inline OOString &operator *= ( NSUInteger count ) {
289  NSString *str =[get() copy];
290  *this = "";
291  for ( int i=0 ; i<count ; i++ )
292  *this += str;
293  OO_RELEASE( str );
294  return *this;
295  }
297  [alloc() setString:val];
298  return *this;
299  }
300 
301  // string comparison
302  oo_inline BOOL operator == ( const char *str ) const { return [get() isEqualToString:OOString(str).get()]; }
303  oo_inline BOOL operator != ( const char *str ) const { return !operator == ( str ); }
304  oo_inline BOOL operator < ( const char *str ) const { return [get() caseInsensitiveCompare:OOString(str).get()] == NSOrderedAscending; }
305  oo_inline BOOL operator >= ( const char *str ) const { return !operator < ( str ); }
306  oo_inline BOOL operator > ( const char *str ) const { return [get() caseInsensitiveCompare:OOString(str).get()] == NSOrderedDescending; }
307  oo_inline BOOL operator <= ( const char *str ) const { return !operator > ( str ); }
308  oo_inline BOOL operator == ( NSString *str ) const { return [get() isEqualToString:str]; }
309  oo_inline BOOL operator != ( NSString *str ) const { return !operator == ( str ); }
310  oo_inline BOOL operator < ( NSString *str ) const { return [get() caseInsensitiveCompare:str] == NSOrderedAscending; }
311  oo_inline BOOL operator >= ( NSString *str ) const { return !operator < ( str ); }
312  oo_inline BOOL operator > ( NSString *str ) const { return [get() caseInsensitiveCompare:str] == NSOrderedDescending; }
313  oo_inline BOOL operator <= ( NSString *str ) const { return !operator > ( str ); }
314  oo_inline BOOL operator == ( NSMutableString *str ) const { return [get() isEqualToString:str]; }
315  oo_inline BOOL operator != ( NSMutableString *str ) const { return !operator == ( str ); }
316  oo_inline BOOL operator < ( NSMutableString *str ) const { return [get() caseInsensitiveCompare:str] == NSOrderedAscending; }
317  oo_inline BOOL operator >= ( NSMutableString *str ) const { return !operator < ( str ); }
318  oo_inline BOOL operator > ( NSMutableString *str ) const { return [get() caseInsensitiveCompare:str] == NSOrderedDescending; }
319  oo_inline BOOL operator <= ( NSMutableString *str ) const { return !operator > ( str ); }
320  oo_inline BOOL operator == ( cOOString str ) const { return [get() isEqualToString:str.get()]; }
321  oo_inline BOOL operator != ( cOOString str ) const { return !operator == ( str ); }
322  oo_inline BOOL operator < ( cOOString str ) const { return [get() caseInsensitiveCompare:str.get()] == NSOrderedAscending; }
323  oo_inline BOOL operator >= ( cOOString str ) const { return !operator < ( str ); }
324  oo_inline BOOL operator > ( cOOString str ) const { return [get() caseInsensitiveCompare:str.get()] == NSOrderedDescending; }
325  oo_inline BOOL operator <= ( cOOString str ) const { return !operator > ( str ); }
326 
327  // used for appending strings
328  oo_inline OOTmpString tmpcopy() const;
329 
330 #if 0
331  // inplace left associative string concatenation
332  oo_inline OOString &operator % ( int n ) { return *this += n; }
333  oo_inline OOString &operator % ( float n ) { return *this += n; }
334  oo_inline OOString &operator % ( double n ) { return *this += n; }
335  oo_inline OOString &operator % ( NSString *str ) { return *this += str; }
336  oo_inline OOString &operator % ( cOOString str ) { return *this += str; }
337 #endif
338 
339  // split by str
342  return [noalloc() componentsSeparatedByString:sep];
343  }
344  oo_inline OOStringArray operator / ( const OOPattern &sep ) const;
345 
346  // index into string by character number or perform search
347  oo_inline OOStringSub operator [] ( int sub ) const { return OOStringSub( get(), sub ); }
348  oo_inline OOStringSub operator [] ( const NSRange &sub ) const { return OOStringSub( get(), sub ); }
350  oo_inline OOStringSearch operator [] ( const char *sub ) const;
351  oo_inline OOStringSearch operator [] ( NSString *sub ) const;
352 
353  oo_inline OOString &operator <<= ( NSString *val ) { copy( (NSMutableString *)val ); return *this; }
354  oo_inline OOString &operator <<= ( cOOString val ) { copy( val.get() ); return *this; }
355  // &|^ bitwise operators for pattern matching - see below...
356 };
357 
358 class OOTmpString : public OOString {
359 public:
361  oo_inline OOTmpString( cOOString str ) { set( str.get() ); }
362  oo_inline OOTmpString tmpcopy() { return *this; }
363 };
364 
366  OOTmpString tmp;
367  tmp.copy( *this );
368 #ifndef OO_ARC ////////
369  tmp.autoget();
370 #endif
371  return tmp;
372 }
373 
374 #define OOSTRING_CONCATS( _type ) \
375 \
376  inline OOTmpString operator + ( _type left, NSString *str ) {\
377  return left.tmpcopy() += str;\
378  }\
379  inline OOTmpString operator + ( _type left, int val ) {\
380  return left.tmpcopy() += val;\
381  }\
382  inline OOTmpString operator + ( _type left, float val ) {\
383  return left.tmpcopy() += val;\
384  }\
385  inline OOTmpString operator + ( _type left, double val ) {\
386  return left.tmpcopy() += val;\
387  }\
388  inline OOTmpString operator + ( _type left, cOOString str ) {\
389  return operator + ( left, str.get() );\
390  }\
391  inline OOTmpString operator + ( _type left, const char *str ) {\
392  return operator + ( left, OOString( str ) );\
393  }\
394  inline OOTmpString operator + ( _type left, const OOArraySub<OOString> &str ) {\
395  return operator + ( left, str.get() );\
396  }\
397  inline OOTmpString operator + ( _type left, const OODictionarySub<OOString> &str ) {\
398  return operator + ( left, str.get() );\
399  }\
400  inline OOTmpString operator + ( _type left, const OOArraySub<NSString *> &str ) {\
401  return operator + ( left, str.get() );\
402  }\
403  inline OOTmpString operator + ( _type left, const OODictionarySub<NSString *> &str ) {\
404  return operator + ( left, str.get() );\
405  }\
406 \
407 \
408  inline OOTmpString operator - ( _type left, cOOString str ) {\
409  return left.tmpcopy() -= str;\
410  }\
411  inline OOTmpString operator - ( _type left, NSString *str ) {\
412  return left.tmpcopy() -= str;\
413  }\
414  inline OOTmpString operator - ( _type left, const char *val ) {\
415  return operator - ( left, OOString( val ).get() );\
416  }
417 
420 
421 
422 // replicate string
423 inline OOString operator * ( cOOString str, int count ) {
424  OOString out = "";
425  for ( int i=0 ; i<count ; i++ )
426  out += str;
427  return out;
428 }
429 
430 
431 template <typename ETYPE>
433  return [get() componentsJoinedByString:sep];
434 }
435 
436 // misc forward references to OOString
437 template <typename ETYPE>
438 inline OOString operator / ( const OOArray<ETYPE> &left, cOOString sep ) {
439  return left.join( sep );
440 }
441 
442 template <typename ETYPE>
443 inline OOArray<ETYPE> &OOArray<ETYPE>::operator = ( const char *val ) {
444  *this = OOString(val) / @" ";
445  return *this;
446 }
447 template <typename ETYPE>
448 inline OOArray<ETYPE> &OOArray<ETYPE>::operator = ( const char **val ) {
449  [alloc() removeAllObjects];
450  while ( *val )
451  *this += OOString( *val++ );
452  return *this;
453 }
454 
455 template <typename ETYPE>
457  *this = OOStringArray(val);
458  return *this;
459 }
460 template <typename ETYPE>
462  *this = OOStringArray( val );
463  return *this;
464 }
465 
466 template <typename ETYPE>
467 inline OODictionarySub<ETYPE> OODictionary<ETYPE>::operator [] ( cOOString sub ) const {
468  return OODictionarySub<ETYPE>( this, sub.get() );
469 }
470 
471 template <typename ETYPE>
472 inline OODictionarySub<ETYPE> OODictionary<ETYPE>::operator [] ( const OOArraySub<OOString> &sub ) const {
473  return OODictionarySub<ETYPE>( this, sub.get() );
474 }
475 
476 template <typename ETYPE>
477 inline OODictionarySub<ETYPE> OODictionary<ETYPE>::operator [] ( const OODictionarySub<OOString> &sub ) const {
478  return OODictionarySub<ETYPE>( this, sub.get() );
479 }
480 
481 template <typename ETYPE,typename RTYPE,typename STYPE>
482 inline OODictionarySub<STYPE> OOSubscript<ETYPE,RTYPE,STYPE>::operator [] ( cOOString sub ) const {
483  return operator [] ( sub.get() );
484 }
485 
486 template <typename ETYPE,typename RTYPE,typename STYPE>
487 inline OODictionarySub<STYPE> OOSubscript<ETYPE,RTYPE,STYPE>::operator [] ( const char *sub ) const {
488  return (*this)[OOString(sub)];
489 }
490 
491 template <typename ETYPE,typename RTYPE,typename STYPE>
493  set( OOString( val ) );
494  return *this;
495 }
496 
497 template <typename ETYPE>
498 inline OOArraySub<ETYPE> &OOArraySub<ETYPE>::operator = ( ETYPE val ) { set( val ); return *this; }
499 
500 template <typename ETYPE>
501 inline OODictionarySub<ETYPE> &OODictionarySub<ETYPE>::operator = ( ETYPE val ) { set( val ); return *this; }
502 
503 template <typename ETYPE>
504 inline OOArraySub<ETYPE> &OOArraySub<ETYPE>::operator = ( const char *val ) { *this = OOString(val).get(); return *this; }
505 
506 template <typename ETYPE>
507 inline OODictionarySub<ETYPE> &OODictionarySub<ETYPE>::operator = ( const char *val ) { *this = OOString(val).get(); return *this; }
508 
509 template <typename ETYPE>
511  [alloc() addObject:!val ? OONull : (id)val];
512  return *this;
513 }
514 
515 // initial operand in concatenation not OOString
516 inline OOString operator + ( NSString *left, cOOString right ) { return OOString( left )+right; }
517 inline OOString operator + ( NSString *left, const OOArraySub<OOString> &right ) { return OOString( left )+*right; }
518 inline OOString operator + ( NSString *left, const OODictionarySub<OOString> &right ) { return OOString( left )+*right; }
519 
520 inline OOString operator + ( const char *left, cOOString right ) { return OOString( left )+right; }
521 inline OOString operator + ( const char *left, const OOArraySub<OOString> &right ) { return OOString( left )+*right; }
522 inline OOString operator + ( const char *left, const OODictionarySub<OOString> &right ) { return OOString( left )+*right; }
523 
524 // initial operand in comparison not OOString
525 inline BOOL operator == ( NSString *left, cOOString right ) { return OOString( left )==right; }
526 inline BOOL operator != ( NSString *left, cOOString right ) { return OOString( left )!=right; }
527 inline BOOL operator == ( const char *left, cOOString right ) { return OOString( left )==right; }
528 inline BOOL operator != ( const char *left, cOOString right ) { return OOString( left )!=right; }
529 
530 // string || string for default values
531 inline OOString operator || ( cOOString left, cOOString right ) { return !left ? right : left; }
532 inline OOString operator || ( cOOString left, NSString *right ) { return left || OO right ; }
533 inline OOString operator || ( cOOString left, const char *right ) { return left || OO right ; }
534 inline OOString operator || ( NSString *left, cOOString right ) { return OO left || right; }
535 inline OOString operator || ( const char *left, cOOString right ) { return OO left || right; }
536 
537 /**
538  A class to represent a C pointer inside an NSValue object for ref counting and
539  so it can be stored inside the OSX buffs NSDictionary etc.
540 
541  Usage:
542  <pre>
543  OOPointer<void *> ptr = malloc(1000);
544  void *p = ptr;
545  </pre>
546  */
547 
548 template <typename PTYPE>
549 class OOPointer : public OOReference<NSValue *> {
550  PTYPE ptr;
551 protected:
552  oo_inline NSValue *pset( NSValue *val ) OO_RETURNS {
553  // recover pointer from NSValue object
554  set( val );
555  ptr = val == OONull || ![val respondsToSelector:@selector(pointerValue)] ?
556  NULL : (PTYPE)[val pointerValue];
557  return val;
558  }
559  oo_inline PTYPE pset( PTYPE ptr ) {
560  // store pointer in NSValue objects so it can be referrence counted
561  OO_RELEASE( pset( [[NSValue alloc] initWithBytes:&ptr objCType:@encode(PTYPE)] ) );
562  return ptr;
563  }
564  oo_inline PTYPE pget() {
565  return !*this ? NULL : ptr;
566  }
567 public:
569  oo_inline OOPointer( PTYPE ptr ) { *this = ptr; }
570  oo_inline OOPointer( NSValue *val ) { *this = val; }
571  oo_inline OOPointer( const OOPointer &val ) { *this = val; }
572 
573  oo_inline operator PTYPE () { return pget(); }
574  oo_inline PTYPE operator * () { return pget(); }
575  oo_inline PTYPE operator -> () { return pget(); }
576 
577  oo_inline OOPointer &operator = ( PTYPE ptr ) { pset( ptr ); return *this; }
578  oo_inline OOPointer &operator = ( NSValue *val ) { pset( val ); return *this; }
579  oo_inline OOPointer &operator = ( const OOPointer &val ) { pset( val.get() ); return *this; }
580 };
581 
582 /*=================================================================================*/
583 /*================================ Pattern matching classes =======================*/
584 
586 
587 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7 \
588 || __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_4_0
589 
590 #define OO_REG_FLAGS NSRegularExpressionDotMatchesLineSeparators
591 
592 /**
593  All compiled regular expressions are cached.
594  */
595 
596 static OOArray<NSRegularExpression *> cache;
597 
598 /**
599  A class to represent a patten matching operations against a string.
600 
601  Usage:
602  <pre>
603  OOStringArray words = OOPattern( @"\\w+" ).match();
604  </pre>
605  */
606 
607 class OOPattern {
608  friend class OOReplace;
610 #ifndef __clang__
611 public:
612 #endif
613  OORef<NSRegularExpression *> regex;
614 
615  oo_inline OOStringArray matchGroups( cOOString str, NSTextCheckingResult *matches ) const {
616  OOStringArray groups;
617  for ( int i=0 ; i<=[regex numberOfCaptureGroups] ; i++ )
618  groups[i] = OOString( str, [matches rangeAtIndex:i] );
619  return groups;
620  }
621 
622 public:
624  oo_inline OOPattern( cOOString patin, NSRegularExpressionOptions flags = OO_REG_FLAGS ) {
625  init( patin, flags );
626  }
627 
628  oo_inline void init( cOOString patin, NSRegularExpressionOptions flags = OO_REG_FLAGS ) {
629  if ( !patin )
630  OOWarn( @"OOPattern::init - nil pattern passed" );
631 
632  pat <<= patin.get();
633 
634  if ( !!cache[flags][patin] ) {
635  regex = *cache[flags][patin];
636  return;
637  }
638 
639  NSError *error = nil;
640  regex = [NSRegularExpression regularExpressionWithPattern:pat
641  options:flags error:&error];
642  if ( error )
643  OOWarn( @"OOPattern::init() Regex compilation error: %@, in pattern: \"%@\"",
644  [error localizedDescription], *pat );
645  else
646  cache[flags][patin] = regex;
647  }
648 
649 
650  oo_inline NSTextCheckingResult *exec( cOOString input ) const {
651  return [regex firstMatchInString:input options:0 range:NSMakeRange(0,[input length])];
652  }
653  oo_inline NSRange range( cOOString input ) {
654  return [regex rangeOfFirstMatchInString:input options:0 range:NSMakeRange(0,[input length])];
655  }
656 
658  NSUInteger pos = 0;
659  OOStringArray out;
660 
661  for ( NSTextCheckingResult *result in [regex matchesInString:str options:0 range:NSMakeRange(0,[str length])] ) {
662  out += OOString( str, OORange(pos,result.range.location) );
663  pos = result.range.location+result.range.length;
664  };
665 
666  return out += OOString( str, OORange(pos,[str length]) );
667  }
668 
670  OOStringArray out;
671  for ( NSTextCheckingResult *result in [regex matchesInString:str options:0 range:NSMakeRange(0,[str length])] )
672  out += OOString( str, [result range] );
673  return out;
674  }
676  if ( ![regex numberOfCaptureGroups] )
677  return matchAll( str );
678 
679  OOStringArray out;
680  for ( NSTextCheckingResult *result in [regex matchesInString:str options:0 range:NSMakeRange(0,[str length])] )
681  for ( int i=1 ; i<=[regex numberOfCaptureGroups] ; i++ )
682  out += OOString( str, [result rangeAtIndex:i] );
683  return out;
684  }
685 
687  OOStringArray out;
688 
689  NSTextCheckingResult *result = exec( str );
690  if ( result )
691  out = matchGroups( str, result );
692 
693  return out;
694  }
696  OOStringArrayArray out;
697  for ( NSTextCheckingResult *result in [regex matchesInString:str options:0 range:NSMakeRange(0,[str length])] )
698  out += matchGroups( str, result );
699  return out;
700  }
702  NSUInteger pos = 0;
703  OOString out;
704 
705  for ( NSTextCheckingResult *result in [regex matchesInString:str options:0 range:NSMakeRange(0,[str length])] ) {
706  out += OOString( str, OORange(pos,result.range.location) );
707  out += callback( matchGroups( str, result ) ).get();
708  pos = result.range.location+result.range.length;
709  }
710 
711  return out += OOString( str, OORange(pos,[str length]) );
712  }
713 };
714 
715 class OOReplace {
718 
719 public:
721  oo_inline OOReplace( const char *expr ) {
722  init( expr );
723  }
725  init( expr );
726  }
728  init( pat, rep, flags );
729  }
730 
731  oo_inline void init( cOOString expr ) {
732  OOPool pool;
733  OOStringArray split = expr / expr[NSMakeRange(0,1)];
734  int flags = OO_REG_FLAGS;
735 
736  for ( const char *options = *split[3] ; *options ; options++ )
737  switch ( *options ) {
738  case 'i': flags |= NSRegularExpressionCaseInsensitive; break;
739  case 'm': flags |= NSRegularExpressionAnchorsMatchLines; break; ////
740  }
741 
742  init( *split[1], *split[2], flags );
743  }
744  oo_inline void init( cOOString pat, cOOString rep, int flags = OO_REG_FLAGS ) {
745  pattern.init( pat, flags );
746  replace <<= rep;
747  }
748 
749  oo_inline OOString exec( cOOString input ) const {
750  return [pattern.regex stringByReplacingMatchesInString:input options:0 range:NSMakeRange(0,[input length]) withTemplate:replace];
751  }
752 
753  oo_inline OOString exec( cOOString input, cOOStringArray outputs ) const {
754  __block NSUInteger pos = 0;
755  __block int ono = 0;
756 #ifndef __clang__
757  __block
758 #endif
759  OOString out = 100;
760 
761  [pattern.regex enumerateMatchesInString:input options:0 range:NSMakeRange(0,[input length])
762  usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
763  [out appendString:OOString( input, OORange(pos,result.range.location) )];
764  [out appendString:[pattern.regex replacementStringForResult:result inString:input
765  offset:0 template:*outputs[ono++]]];
766  pos = result.range.location+result.range.length;
767  if ( ono>=outputs )
768  *stop = YES;
769  }];
770 
771  return out += OOString( input, OORange(pos,[input length]) );
772  }
773 
774 };
775 
776 #else
777 // previous C library based implementation
778 #import "objexp.h"
779 #endif
780 
781 // obsolete regexp operators left in for now
782 
783 // array of matches in string
784 inline OOStringArray operator & ( cOOString str, const OOPattern &pattern ) { return pattern.matchAll( str ); }
785 inline OOStringArray operator & ( cOOString str, const OOPattern *pattern ) { return str & *pattern; }
786 inline OOStringArray operator & ( cOOString str, const OOString &patexpr ) { return str & OOPattern( patexpr ); }
787 
788 // groups found in single match
789 inline OOStringArray operator ^ ( cOOString str, const OOPattern &pattern ) { return pattern.parse( str ); }
790 inline OOStringArray operator ^ ( cOOString str, const OOPattern *pattern ) { return str ^ *pattern; }
791 inline OOStringArray operator ^ ( cOOString str, const OOString &patexpr ) { return str ^ OOPattern( patexpr ); }
792 
793 inline OOStringArray OOString::operator / ( const OOPattern &sep ) const {
794  return sep.split( *this );
795 }
796 
797 
798 // apply replacement string e.g. @"/a/b/"
799 inline OOString operator | ( cOOString str, const OOReplace &replace ) { OOPoolIfRequired; return replace.exec( str ); }
800 inline OOString operator | ( cOOString str, const OOReplace *replace ) { return str | *replace; }
801 inline OOString operator | ( cOOString str, const OOString &patrepl ) { return str | OOReplace( patrepl ); }
802 
803 // ... inplace
804 inline OOString &operator |= ( OOString &str, const OOReplace &replace ) { return str = str | replace; }
805 inline OOString &operator |= ( OOString &str, const OOReplace *replace ) { return str = str | replace; }
806 inline OOString &operator |= ( OOString &str, const OOString &patrepl ) { return str = str | patrepl; }
807 
808 /**
809  Internal class representing subscript by string which performs a search into the
810  string. Assigning to for example str[@"BARRY"] = @"BAZ" will change all occurances
811  of "BARRY" in the string to "BAZ".
812 
813  Usage:
814  <pre>
815  OOString str <<= @"BARRY is great";
816  str[@"great"] = @"an egotist";
817  </pre>
818  */
819 
820 /**
821  A class to represent a match and replace operations against a string.
822  uses BSD regex documented in "man regex"
823 
824  Usage:
825  <pre>
826  OOString quoted = OOReplace( @"/(\\w+)/'$1'/" ).exec();
827  </pre>
828  */
829 
831  friend class OOString;
832  OOString *str, idx;
834  str = (OOString *)ref;
835  idx = sub;
836  if ( !*ref ) {
837  NSLog( @"** nil string for subscripted match with pattern: %@", *sub );
838 #ifndef DEBUG
839  *str = @""; // avoid crash unless debugging
840 #endif
841  }
842  if ( !sub )
843  NSLog( @"** nil pattern in subscripted match" );
844  }
845 
847  return OOPattern( idx );
848  }
849 public:
850  oo_inline NSRange range() const {
851  return pattern().range( *str );
852  }
853  oo_inline operator NSRange () const {
854  return range();
855  }
856  // ! change here with version 5.0 !
857  // BOOL more usefull than location.
858 #if 0
859  oo_inline operator NSUInteger () const {
860  return range().location;
861  }
862 #else
863  oo_inline operator BOOL () const {
864  return !!*this;
865  }
866 #endif
867  oo_inline BOOL operator ! () const {
868  return !*str || !pattern().exec( *str );
869  }
870  oo_inline NSRange operator & () const {
871  return range();
872  }
873 
875  return OOString( *str, range() );
876  }
877  oo_inline operator OOString () const {
878  return **this;
879  }
880 
882  return pattern().match( *str );
883  }
884 
885  oo_inline operator OOStringArray () const {
886  return match();
887  }
888  oo_inline operator OOStringArrayArray () const{
889  return pattern().parseAll( *str );
890  }
891 
892  oo_inline OOString &operator = ( cOOString replacement ) {
893  return *str = OOReplace( idx, replacement ).exec( *str );
894  }
895  oo_inline OOString &operator = ( NSString *replacement ) {
896  return *str = OOReplace( idx, replacement ).exec( *str );
897  }
898  oo_inline OOString &operator = ( const char *replacement ) {
899  return *this = *OOString( replacement );
900  }
901  oo_inline OOString &operator = ( cOOStringArray replacements ) {
902  return *str = OOReplace( idx, nil ).exec( *str, replacements );
903  }
904  oo_inline OOString &operator = ( OOReplaceBlock callback ) {
905  return *str = pattern().blockReplace( *str, callback );
906  }
907  oo_inline OOString &operator = ( OOTmpString (^callback)( cOOStringArray groups ) ) {
908  return *this = (OOReplaceBlock)callback;
909  }
910  oo_inline OOString &operator = ( cOOStringDictionary replacements ) {
911  return *this = ^( cOOStringArray groups ) {
912  return *replacements[groups[0]]||*groups[0];
913  };
914  }
915 
916  oo_inline OOString operator [] ( int group ) const {
917  return pattern().match( *str )[group];
918  }
919  oo_inline OOStringArray operator ~ () {
920  OOStringArray match = pattern().parse( *str );
921  *str -= range();
922  return match;
923  }
924 };
925 
927  return OOStringSearch( this, sub );
928 }
929 inline OOStringSearch OOString::operator [] ( NSString *sub ) const {
930  return OOStringSearch( this, sub );
931 }
932 inline OOStringSearch OOString::operator [] ( const char *sub ) const {
933  return OOStringSearch( this, sub );
934 }
935 
936 template <typename ETYPE>
938  return *this = search.match();
939 }
940 
941 template <typename ETYPE>
943  return *this = search.match();
944 }
945 
947  alloc();
948  (*this)[str] = @"";
949  return *this;
950 } ////
951 
952 /**
953  Assign to up to 10 variables directly from an array.
954  */
955 
956 #define OOVars( _type, _vars... ) _type _vars; OOAssign<_type>( _vars )
957 #define OOStringVars( _vars... ) OOVars( OOString, _vars )
958 #define OOStringAssign OOAssign<OOString>
959 
960 template <typename ETYPE>
961 class OOAssign {
962  ETYPE *vars[10];
963 public:
964  oo_inline OOAssign( ETYPE &v0,
965  ETYPE &v1 = *(ETYPE *)NULL, ETYPE &v2 = *(ETYPE *)NULL, ETYPE &v3 = *(ETYPE *)NULL,
966  ETYPE &v4 = *(ETYPE *)NULL, ETYPE &v5 = *(ETYPE *)NULL, ETYPE &v6 = *(ETYPE *)NULL,
967  ETYPE &v7 = *(ETYPE *)NULL, ETYPE &v8 = *(ETYPE *)NULL, ETYPE &v9 = *(ETYPE *)NULL ) {
968  vars[0] = (ETYPE *)v0.ptr();
969  vars[1] = (ETYPE *)v1.ptr(); vars[2] = (ETYPE *)v2.ptr(); vars[3] = (ETYPE *)v3.ptr();
970  vars[4] = (ETYPE *)v4.ptr(); vars[5] = (ETYPE *)v5.ptr(); vars[6] = (ETYPE *)v6.ptr();
971  vars[7] = (ETYPE *)v7.ptr(); vars[8] = (ETYPE *)v8.ptr(); vars[9] = (ETYPE *)v9.ptr();
972  }
973  oo_inline OOArray<ETYPE> operator = ( const OOArray<ETYPE> &in ) {
974  for ( int i=0 ; vars[i] && i<sizeof vars/sizeof vars[0] ; i++ )
975  if ( i<[in count] )
976  *vars[i] = in[i];
977  else
978  *vars[i] = OONil;
979  return in;
980  }
981 };
982 
983 /*=================================================================================*/
984 /*================================ Utility classes ================================*/
985 
986 #define cOORequest const OORequest &
987 #define cOOURL const OOURL &
988 #define cOOFile const OOFile &
989 #define cOOData const OOData &
990 
991 static jmp_buf oo_jmp_env;
992 
993 static void oo_trapper( int sig ) {
994  NSLog( @"SIGNAL %d", sig );
995  longjmp( oo_jmp_env, 1 );
996 }
997 
998 inline int OOTrap() {
999  signal( SIGSEGV, oo_trapper );
1000  signal( SIGBUS, oo_trapper );
1001  return setjmp( oo_jmp_env );
1002 }
1003 
1004 /**
1005  Network request on which you can POST data or set HTP header values.
1006  */
1007 
1008 class OOURL;
1009 class OORequestSub;
1011 public:
1012  NSURLResponse *lastResponse;
1013  NSError *error;
1014 
1016  oo_inline OORequest( cOOURL url );
1017  oo_inline OORequest( NSURL *url,
1018  NSURLRequestCachePolicy cachePolicy = NSURLRequestUseProtocolCachePolicy,
1019  NSTimeInterval timeoutInterval = 60. ) {
1020  rawset( [[NSMutableURLRequest alloc] initWithURL:url cachePolicy:cachePolicy
1021  timeoutInterval:timeoutInterval] );
1022  }
1023  oo_inline OORequest( NSString *url ) {
1024  setURL( url );
1025  }
1027  setURL( url );
1028  }
1030  set( req.get() );
1031  }
1032  oo_inline OORequest( NSURLRequest *req ) {
1033  *this = req; /////
1034  }
1035 
1036  oo_inline void setURL( NSString *url ) {
1037  NSURL *URL = [[NSURL alloc] initWithString:url];
1038  rawset( [[NSMutableURLRequest alloc] initWithURL:URL] );
1039  OO_RELEASE( URL );
1040  }
1041 
1042  oo_inline OORequest &operator = ( NSURLRequest *val ) {
1043  set( (id)val ); return *this; /////
1044  }
1045  oo_inline OORequestSub operator [] ( cOOString sub );
1046  oo_inline OORequest &post( NSData *data ) {
1047  [get() setHTTPMethod:@"POST"];
1048  [get() setValue:OOFormat( @"%d", (int)[data length] )
1049  forHTTPHeaderField:@"Content-Length"];
1050  [get() setHTTPBody:data];
1051  return *this;
1052  }
1053  oo_inline OORequest &post( cOOString str, NSStringEncoding encoding = NSUTF8StringEncoding ) {
1054  [get() setValue:@"application/x-www-form-urlencoded"
1055  forHTTPHeaderField:@"Content-Encoding"];
1056  post( [urlEncode( str ) dataUsingEncoding:encoding allowLossyConversion:YES] );
1057  return *this;
1058  }
1059 
1060  oo_inline NSString *urlEncode( NSString *text ) {
1061  NSMutableString *encoded = [NSMutableString string];
1062  for ( const char *iptr = [text UTF8String] ; iptr && *iptr ; iptr++ )
1063  if ( *iptr > 0 && *iptr != '%' ) ///
1064  [encoded appendFormat:@"%c", *iptr];
1065  else
1066  [encoded appendFormat:@"%%%02x", *iptr&0xff];
1067 
1068  return encoded;
1069  }
1070 
1071  oo_inline OOData data( NSStringEncoding *encoding = NULL, NSError **errorPtr = NULL ) {
1072  [[NSURLCache sharedURLCache] removeCachedResponseForRequest:get()];
1073 #ifndef OO_ARC
1074  OOData data = [NSURLConnection sendSynchronousRequest:get() returningResponse:&lastResponse error:errorPtr];
1075 #else
1076  NSURLResponse *tmpResponse; //NSError *tmpError;
1077  OOData data = [NSURLConnection sendSynchronousRequest:get() returningResponse:&tmpResponse error:errorPtr];
1078  lastResponse = tmpResponse; //error = tmpError;
1079 #endif
1080  if ( encoding ) {
1081  NSString *textEncoding = [lastResponse textEncodingName];
1082  CFStringEncoding coreEncoding = textEncoding ?
1083  CFStringConvertIANACharSetNameToEncoding( OO_BRIDGE(CFStringRef)textEncoding ) :
1084  kCFStringEncodingUTF8;
1085  *encoding = CFStringConvertEncodingToNSStringEncoding( coreEncoding );
1086  }
1087 
1088  return data;
1089  }
1090  oo_inline OOString string( NSStringEncoding *encoding = NULL, NSError **errorPtr = NULL ) {
1091  ////OOPool pool;
1092  NSStringEncoding tmpEnc;
1093  if ( !encoding )
1094  encoding = &tmpEnc;
1095  OOData data = this->data( encoding, errorPtr );
1096  return OOString( data, *encoding );
1097  }
1098  oo_inline operator OOString () {
1099  return string();
1100  }
1101 };
1102 
1103 class OORequestSub {
1104  friend class OORequest;
1105  OORequest *req;
1106  OOString key;
1107 
1108  oo_inline OORequestSub( OORequest *req, cOOString key ) {
1109  this->req = req;
1110  this->key = key;
1111  }
1112 
1113 public:
1114  oo_inline OORequestSub operator = ( cOOString val ) {
1115  [req->get() setValue:val forHTTPHeaderField:key];
1116  return *this;
1117  }
1118  oo_inline operator OOString () {
1119  return [req->get() valueForHTTPHeaderField:key];
1120  }
1121 };
1122 
1123 inline OORequestSub OORequest::operator [] ( cOOString sub ) {
1124  return OORequestSub( this, sub );
1125 }
1126 
1127 /**
1128  OOURL to initialise strings from the network or files.
1129  */
1130 
1131 class OOURL : public OOReference<NSURL *> {
1132 public:
1133 
1134  oo_inline OOURL( NSURL *url ) {
1135  set( url );
1136  }
1137  oo_inline OOURL( cOOString url, NSURL *base = nil ) {
1138  setURL( url, base );
1139  }
1140  oo_inline OOURL( NSString *url = OONil, NSURL *base = nil ) {
1141  setURL( url, base );
1142  }
1143  oo_inline void setURL( cOOString url, NSURL *baseURL = nil ) {
1144  if ( !!url )
1145  rawset( baseURL ?
1146  [[NSURL alloc] initWithString:url relativeToURL:baseURL] :
1147  [[NSURL alloc] initWithString:url] );
1148  }
1150  return OORequest( get() );
1151  }
1153  return [[get() absoluteString] isEqualToString:[other absoluteString]];
1154  }
1155  oo_inline OOString string( NSStringEncoding *enc = NULL, NSError **error = NULL ) const {
1156  return [NSMutableString stringWithContentsOfURL:get() usedEncoding:enc error:error];
1157  }
1158  oo_inline OOData data( NSDataReadingOptions readOptionsMask = 0, NSError **errorPtr = NULL ) const {
1159  return [NSMutableData dataWithContentsOfURL:get() options:readOptionsMask error:errorPtr];
1160  }
1161  oo_inline operator OOString () const {
1162  return string();
1163  }
1164  oo_inline operator OOData () const {
1165  return data();
1166  }
1168  return [NSKeyedUnarchiver unarchiveObjectWithData:data()];
1169  }
1171  return request().post( post );
1172  }
1173 
1174  oo_inline BOOL save( cOOString string, NSStringEncoding encoding = NSUTF8StringEncoding ) {
1175  return save( [string dataUsingEncoding:encoding allowLossyConversion:YES] );
1176  }
1177  oo_inline BOOL save( NSData *data, BOOL atomically = NO ) {
1178  return [data writeToURL:*this atomically:atomically];
1179  }
1180  oo_inline BOOL save( id object, BOOL atomically = NO ) {
1181  return save( [NSKeyedArchiver archivedDataWithRootObject:object], atomically );
1182  }
1183 
1184  OONode xml( int flags = 0 );
1185 };
1186 
1188  rawset( [[NSMutableURLRequest alloc] initWithURL:url] );
1189 }
1190 
1191 /**
1192  Placeholder for a file path, see OOResource, OODocument, OOTmpFile.
1193  */
1194 
1195 class OOFile : public OOURL {
1196 #ifdef __OBJC_GC__
1197  NSURL *ref3;
1198  oo_inline virtual id rawset( NSURL *val ) OO_RETURNS {
1199  return OOReference<NSURL *>::rawset( ref3 = val );
1200  }
1201 #endif
1202 public:
1204  }
1205  oo_inline OOFile( NSURL *url ) : OOURL( url ) {}
1206  oo_inline OOFile( cOOFile file ) : OOURL() { setPath( file.path() ); }
1207  oo_inline OOFile( cOOString path, BOOL isDir = NO ) : OOURL( (NSURL *)0 ) {
1208  setPath( path, isDir );
1209  }
1210  oo_inline OOFile( cOOString name, cOOString type ) : OOURL( (NSURL *)0 ){
1211  setPath( [[NSBundle mainBundle] pathForResource:name ofType:type] );
1212  }
1213  oo_inline OOFile &setPath( cOOString path, BOOL isDir = NO ) {
1214  if ( *path )
1215  rawset( [[NSURL alloc] initFileURLWithPath:path.get() isDirectory:isDir] );
1216  return *this;
1217  }
1219  return [get() baseURL] ? [get() relativeString] : [get() path];
1220  }
1222  return [path() lastPathComponent];
1223  }
1225  return [path() stringByDeletingLastPathComponent];
1226  }
1228  return [path() pathExtension];
1229  }
1231  return setPath( [path() stringByResolvingSymlinksInPath] );
1232  }
1233  oo_inline NSDictionary *attr( NSError **error = NULL ) const {
1234  return [[NSFileManager defaultManager] attributesOfItemAtPath:path() error:error];
1235  }
1236  oo_inline unsigned long long size() const {
1237  return [attr() fileSize];
1238  }
1239 
1240  oo_inline BOOL exists() const {
1241  return [[NSFileManager defaultManager] fileExistsAtPath:path()];
1242  }
1243  oo_inline BOOL copyto( cOOString to ) const {
1244  return [[NSFileManager defaultManager] copyItemAtPath:path() toPath:to error:NULL];
1245  }
1246  oo_inline BOOL moveto( cOOString to ) const {
1247  return [[NSFileManager defaultManager] moveItemAtPath:path() toPath:to error:NULL];
1248  }
1249  oo_inline BOOL linkto( cOOString to ) const {
1250  return [[NSFileManager defaultManager] linkItemAtPath:path() toPath:to error:NULL];
1251  }
1252  oo_inline BOOL remove() {
1253  return [[NSFileManager defaultManager] removeItemAtPath:path() error:NULL];
1254  }
1255  oo_inline BOOL mkdir( BOOL flag = YES, NSDictionary *attr = nil ) {
1256  return [[NSFileManager defaultManager] createDirectoryAtPath:path()
1257  withIntermediateDirectories:flag attributes:attr error:NULL];
1258  }
1259  oo_inline OOFile &operator = ( cOOString str ) {
1260  save( str ); return *this;
1261  }
1262  oo_inline OOFile &operator = ( cOOData data ) {
1263  save( *data ); return *this;
1264  }
1265  oo_inline OOFile &operator = ( cOOFile file ) {
1266  return *this = file.data();
1267  }
1268 #if 000
1269  oo_inline BOOL operator ! () const {
1270  return !exists();
1271  }
1272  oo_inline BOOL operator ~ () {
1273  return remove();
1274  }
1275 #endif
1276 };
1277 
1278 /**
1279  Pathfinder for resources in applications.
1280  */
1281 
1282 class OOResource : public OOFile {
1283 public:
1285  OOStringArray comps = name / @".";
1286  setPath( [[NSBundle mainBundle] pathForResource:**comps[0]
1287  ofType:comps>1 ? **comps[1] : nil] );
1288  }
1289 };
1290 
1291 /**
1292  Pathfinder for documents for applications.
1293  */
1294 
1295 class OODocument : public OOFile {
1296 public:
1297 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
1299  OOFile( OOFormat( @"%@/Documents/%@", NSHomeDirectory(), *name ) ) {}
1300 #else
1301  oo_inline OODocument( cOOString name ) :
1302  OOFile( [[[[NSFileManager defaultManager]
1303  URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]
1304  lastObject] URLByAppendingPathComponent:name] ) {}
1305 #endif
1306 };
1307 
1308 /**
1309  Pathfinder for temporary files for applications.
1310  */
1311 class OOTmpFile : public OOFile {
1312 public:
1313 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
1315  OOFile( OOFormat( @"%@/tmp/%@", NSHomeDirectory(), *name ) ) {}
1316 #else
1317  oo_inline OOTmpFile( cOOString name ) :
1318  OOFile( [[[[NSFileManager defaultManager]
1319  URLsForDirectory:NSCachesDirectory inDomains:NSUserDomainMask]
1320  lastObject] URLByAppendingPathComponent:name] ) {}
1321 #endif
1322 };
1323 
1324 /**
1325  Internal class for subscripted acces to defaults.
1326  */
1327 
1328 class OODefaultsSub : public OODictionarySub<OOString> {
1329  friend class OODefaults;
1330  oo_inline OODefaultsSub( const OODictionary<OOString> *root, id key ) : OODictionarySub<OOString>( root, key ) {
1331  }
1332  oo_inline virtual id get( BOOL warn = YES ) const OO_RETURNS {
1333  id value = [[NSUserDefaults standardUserDefaults] objectForKey:key];
1334  if ( [value class] == [NSArray class] ||
1335  [value class] == [NSDictionary class] )
1336  OO_RELEASE( set( value = [value mutableCopy] ) );
1337  else
1338  OODictionarySub<OOString>::set( value );
1339  return value != OONull ? value : nil;
1340  }
1341  oo_inline virtual id set ( id value ) const OO_RETURNS {
1342  NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
1343  [defaults setObject:value forKey:key];
1344  /////[defaults synchronize];
1345  return OODictionarySub<OOString>::set( value );
1346  }
1347 public:
1348  oo_inline OODefaultsSub &operator = ( cOOString val ) { set( val.get() ); return *this; }
1349  oo_inline OODefaultsSub &operator = ( CFStringRef val ) { set( OO_BRIDGE(id)val ); return *this; }
1350  oo_inline OODefaultsSub &operator = ( NSString *val ) { set( val ); return *this; }
1351  oo_inline OODefaultsSub &operator = ( NSArray *val ) { set( val ); return *this; }
1352  oo_inline OODefaultsSub &operator = ( NSDictionary *val ) { set( val ); return *this; }
1353  oo_inline OODefaultsSub &operator = ( const OORef<NSMutableArray *> &val ) { set( val.get() ); return *this; }
1354  oo_inline OODefaultsSub &operator = ( const OORef<NSMutableDictionary *> &val ) { set( val.get() ); return *this; }
1355  oo_inline OODefaultsSub &operator = ( long long val ) { set( [[NSNumber numberWithLongLong:val] stringValue] ); return *this; }
1356  oo_inline OODefaultsSub &operator = ( double val ) { set( [[NSNumber numberWithDouble:val] stringValue] ); return *this; }
1357  oo_inline OODefaultsSub &operator = ( float val ) { set( [[NSNumber numberWithFloat:val] stringValue] ); return *this; }
1358  oo_inline OODefaultsSub &operator = ( int val ) { set( [[NSNumber numberWithInt:val] stringValue] ); return *this; }
1359  oo_inline OODefaultsSub &operator = ( BOOL val ) { set( [[NSNumber numberWithBool:val] stringValue] ); return *this; }
1360 
1361  oo_inline operator long long () { return [get() longLongValue]; }
1362  oo_inline operator double () { return [get() doubleValue]; }
1363  oo_inline operator float () { return [get() floatValue]; }
1364  oo_inline operator BOOL () { return [get() boolValue]; }
1365  oo_inline operator int () { return [get() intValue]; }
1366  oo_inline operator NSDictionary * () { return get(); }
1367  oo_inline operator NSString * () { return get(); }
1368  oo_inline operator NSArray * () { return get(); }
1369 
1370  oo_inline OODefaultsSub &operator = ( long val ) { set( [[NSNumber numberWithLong:val] stringValue] ); return *this; }
1371  oo_inline operator long () { return [get() intValue]; }
1372 
1373  oo_inline OOString operator ~ () {
1374  [[NSUserDefaults standardUserDefaults] removeObjectForKey:key];
1375  return OODictionarySub<OOString>::operator ~ ();
1376  }
1377 };
1378 
1379 /**
1380  Binds defaults to an OODictionary.
1381  */
1382 
1384 #ifdef __OBJC_GC__
1385  NSMutableDictionary *ref3;
1386  oo_inline virtual id rawset( NSMutableDictionary *val ) OO_RETURNS {
1387  return OOReference<NSMutableDictionary *>::rawset( ref3 = val );
1388  }
1389 #endif
1390 public:
1392  OOPool pool;
1393  *this <<= [[NSUserDefaults standardUserDefaults] dictionaryRepresentation];
1394  }
1395  oo_inline OODefaultsSub operator[] ( id key ) const {
1396  return OODefaultsSub( this, key );
1397  }
1398  oo_inline OODefaultsSub operator[] ( cOOString key ) const {
1399  return OODefaultsSub( this, key );
1400  }
1401  oo_inline OODefaultsSub operator [] ( const CFStringRef sub ) const {
1402  return (*this)[OO_BRIDGE(id)sub];
1403  }
1404  oo_inline void sync() {
1405  [[NSUserDefaults standardUserDefaults] synchronize];
1406  }
1408  sync();
1409  }
1410 };
1411 
1412 /**
1413  Binds application's Info.plist to an OODictionary.
1414  */
1415 
1417 public:
1418  oo_inline OOInfo( NSBundle *bundle = [NSBundle mainBundle] ) {
1419  set( (NSMutableDictionary *)[bundle infoDictionary] );
1420  }
1421 };
1422 
1423 /**
1424  Wrapper for execution of command
1425  */
1426 
1427 typedef int (^OOTaskBlock)();
1428 
1429 class OOTask {
1430 public:
1431  int standardInput, pid;
1432  oo_inline FILE *exec( cOOStringArray command ) {
1433  char const *argv[100], *envp[1000], **eptr = envp;
1434 
1435  for ( int i=0 ; i<command ; i++ )
1436  argv[i] = command[i];
1437  argv[command] = NULL;
1438 
1439  int input[2], output[2];
1440  if ( pipe( input ) < 0 || pipe( output ) < 0 )
1441  NSLog( @"OOTask::exec - pipe() problem" );
1442 
1443  if ( (pid = fork()) == 0 ) {
1444 
1445  FILE *fp = popen( "/usr/bin/perl -e 'print \"$_=$ENV{$_}\\n\" foreach keys %ENV; exit 99;'", "r" );
1446  if ( fp ) {
1447  char line[10000];
1448  while( fp && fgets( line, sizeof line, fp ) ) {
1449  line[strlen(line)-1] = '\000';
1450  *eptr++ = strdup(line);
1451  }
1452  if ( pclose( fp )>>8 != 99 )
1453  exit( 99 );
1454  }
1455  *eptr++ = NULL;
1456 
1457  // close parent pipes
1458  close( input[1] );
1459  close( output[0] );
1460 
1461  // setup stdin/stdout/stderr
1462  close( 0 ); dup( input[0] ); close( input[0] );
1463  close( 1 ); dup( output[1] );
1464  close( 2 ); dup( output[1] ); close( output[1] );
1465 
1466  if ( execve( argv[0], (char * const *)argv, (char * const *)envp ) < 0 )
1467  NSLog( @"OOTask::exec - execve failed" );
1468  exit(1);
1469  }
1470 
1471  close( input[0] );
1472  close( output[1] );
1473 
1474  standardInput = input[1];
1475  return fdopen( output[0], "r" );
1476  }
1477  oo_inline FILE *exec( OOTaskBlock callback ) {
1478 
1479  int input[2], output[2];
1480  if ( pipe( input ) < 0 || pipe( output ) < 0 )
1481  NSLog( @"OOTask::exec - pipe() problem" );
1482 
1483  if ( (pid = fork()) == 0 ) {
1484  // close parent pipes
1485  close( input[1] );
1486  close( output[0] );
1487 
1488  // setup stdin/stdout/stderr
1489  close( 0 ); dup( input[0] ); close( input[0] );
1490  close( 1 ); dup( output[1] ); close( output[1] );
1491  //close( 2 ); dup( output[1] ); close( output[1] );
1492 
1493  exit( callback() );
1494  }
1495 
1496  close( input[0] );
1497  close( output[1] );
1498 
1499  standardInput = input[1];
1500  return fdopen( output[0], "r" );
1501  }
1502 
1503  oo_inline ssize_t send( OOData input ) {
1504  ssize_t wrote = write( standardInput, [input bytes], [input length] );
1505  close( standardInput );
1506  standardInput = -1;
1507  return wrote;
1508  }
1509  oo_inline int wait() {
1510  if ( standardInput >= 0 )
1511  close( standardInput );
1512  int status = 1;
1513  if ( waitpid(pid,&status,0) < 0 )
1514  NSLog( @"OOTask::exec - wait problem" );
1515  return status;
1516  }
1517 };
1518 
1519 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7 \
1520 || __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_5_0
1522 public:
1523  OOJson( cOOData data ) {
1524  *this = data;
1525  }
1527  *this = dict;
1528  }
1529  OOJson &operator = ( cOOData data ) {
1530  set( [NSJSONSerialization JSONObjectWithData:data
1531  options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves error:NULL] );
1532  return *this;
1533  }
1535  return [NSJSONSerialization dataWithJSONObject:get() options:NSJSONWritingPrettyPrinted error:NULL];
1536  }
1537 };
1538 #endif
1539 
1540 /*=================================================================================*/
1541 /*================================ Leftovers ======================================*/
1542 
1543 /**
1544  Shortcut for creating alerts.
1545  */
1546 
1547 inline NSInteger OOAlert( OOString msg, id del = nil,
1548  OOString cancel = @"OK", OOString b1 = nil, OOString b2 = nil ) {
1549  NSLog( @"** OOAlert: %@", *msg );
1550 #ifdef APPKIT_EXTERN
1551  return [[NSAlert alertWithMessageText:*OOInfo()[kCFBundleNameKey]
1552  defaultButton:cancel alternateButton:b1 otherButton:b2
1553  informativeTextWithFormat:@"%@", *msg] runModal];
1554 #else
1555 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
1556  dispatch_async( dispatch_get_main_queue(), ^ {
1557  UIAlertView *alert = [[UIAlertView alloc]
1558  initWithTitle:*OOInfo()[@"CFBundleDisplayName"] message:msg delegate:del
1559  cancelButtonTitle:cancel otherButtonTitles:*b1, *b2, nil];
1560  [alert show];
1561  OO_RELEASE( alert );
1562  } );
1563 #endif
1564  return 0;
1565 #endif
1566 }
1567 
1568 /**
1569  A wrapper for a number using NSNumber so it can be put in an NSArray or NSDictionary
1570  */
1571 
1573 public:
1574  oo_inline OONumber( double d ) {
1575  rawset( [[NSNumber alloc] initWithDouble:d] );
1576  }
1577  oo_inline OONumber( NSNumber *val ) {
1578  set( val );
1579  }
1580 
1581  oo_inline operator NSNumber * () const { return get(); }
1582  oo_inline operator double () const { return [get() doubleValue]; }
1583  oo_inline double operator * () const { return [get() doubleValue]; }
1584 
1585  oo_inline OONumber &operator = ( const OONumber &val ) { set( val.get() ); return *this; }
1586  oo_inline OONumber &operator += ( double val ) { return *this = *this + val; }
1587  oo_inline OONumber &operator -= ( double val ) { return *this = *this - val; }
1588  oo_inline OONumber &operator *= ( double val ) { return *this = *this * val; }
1589  oo_inline OONumber &operator /= ( double val ) { return *this = *this / val; }
1590  oo_inline OONumber operator + ( double val ) const { return **this + val; }
1591  oo_inline OONumber operator - ( double val ) const { return **this - val; }
1592  oo_inline OONumber operator * ( double val ) const { return **this * val; }
1593  oo_inline OONumber operator / ( double val ) const { return **this / val; }
1594 };
1595 
1596 /**
1597  A fledgling wrapper for NSScanner which didn't really pan out...
1598  */
1599 
1600 class OOScan {
1602 public:
1604  OO_RELEASE( *(scan = [[NSScanner alloc] initWithString:input]) );
1605  }
1606 
1607  oo_inline OOString operator & ( NSString *str ) {
1608  NSString *out = nil;
1609  [*scan scanString:str intoString:&out];
1610  return out;
1611  }
1612  oo_inline OOString operator | ( NSString *str ) {
1613  NSString *out = nil;
1614  [*scan scanUpToString:str intoString:&out];
1615  return out;
1616  }
1618  [*scan scanDouble:&d];
1619  return *this;
1620  }
1622  [*scan scanFloat:&f];
1623  return *this;
1624  }
1626  [*scan scanInt:&i];
1627  return *this;
1628  }
1629 };
1630 
1631 #endif
1632 #endif